import scipy.sparse as spsp
import numpy as np

from pysit.solvers.wavefield_vector import *
from .constant_density_acoustic_frequency_scalar_base import *

from pysit.util import Bunch
from pysit.util import PositiveEvenIntegers
from pysit.util.derivatives import build_derivative_matrix
from pysit.util.matrix_helpers import build_sigma, make_diag_mtx

from pysit.util.solvers import inherit_dict

__all__ = ['ConstantDensityAcousticFrequencyScalar_3D']

__docformat__ = "restructuredtext en"

@inherit_dict('supports', '_local_support_spec')
class ConstantDensityAcousticFrequencyScalar_3D(ConstantDensityAcousticFrequencyScalarBase):

    _local_support_spec = {'spatial_discretization': 'finite-difference',
                           'spatial_dimension': 3,
                           'spatial_accuracy_order': PositiveEvenIntegers,
                           'boundary_conditions': ['pml', 'pml-sim', 'dirichlet'],
                           'precision': ['single', 'double']}

    def __init__(self,
                 mesh,
                 spatial_accuracy_order=4,
                 spatial_shifted_differences=True,
                 **kwargs):

        self.operator_components = Bunch()

        self.spatial_accuracy_order = spatial_accuracy_order

        self.spatial_shifted_differences = spatial_shifted_differences

        ConstantDensityAcousticFrequencyScalarBase.__init__(self,
                                                            mesh,
                                                            spatial_accuracy_order=spatial_accuracy_order,
                                                            spatial_shifted_differences=spatial_shifted_differences,
                                                            **kwargs)

        # In 3D there is only compact operator implemented
        if self.mesh.x.lbc.type == 'pml':
            if self.mesh.x.lbc.domain_bc.compact:
                self.compact = self.mesh.x.lbc.domain_bc.compact
            else:
                raise NotImplementedError(
                    '3D frequency helmholtz operator with auxilliary fields is not available please use the flag compact=True for setting')
        else:
            self.compact = False
            raise NotImplementedError(
                'Please set boundary conditions as PML with the flag compact=True')

    def _sigma_PML(self, mesh):
        nx, ny, nz = mesh.shape(include_bc=True, as_grid=True)
        # in mesh.py spacial direction seems to be ordered this way
        npml_x_l = mesh.x.lbc.n
        npml_x_r = mesh.x.rbc.n
        npml_z_l = mesh.z.lbc.n
        npml_z_r = mesh.z.rbc.n
        npml_y_l = mesh.y.lbc.n
        npml_y_r = mesh.y.rbc.n

        t_x_l = np.linspace(1, 0, npml_x_l)
        t_x_r = np.linspace(0, 1, npml_x_r)
        t_z_l = np.linspace(1, 0, npml_z_l)
        t_z_r = np.linspace(0, 1, npml_z_r)
        t_y_l = np.linspace(1, 0, npml_y_l)
        t_y_r = np.linspace(0, 1, npml_y_r)

        amplitude_x_l = mesh.x.lbc.domain_bc.amplitude
        amplitude_x_r = mesh.x.rbc.domain_bc.amplitude
        amplitude_z_l = mesh.z.lbc.domain_bc.amplitude
        amplitude_z_r = mesh.z.rbc.domain_bc.amplitude
        amplitude_y_l = mesh.y.lbc.domain_bc.amplitude
        amplitude_y_r = mesh.y.rbc.domain_bc.amplitude

        sx = np.zeros(nx*ny*nz)
        sy = np.zeros(nx*ny*nz)
        sz = np.zeros(nx*ny*nz)
        sxp = np.zeros(nx*ny*nz)
        syp = np.zeros(nx*ny*nz)
        szp = np.zeros(nx*ny*nz)

        # PML for the x direction
        for i in range(ny*nz):
            for j in range(npml_x_l):
                sx[i + j*nz] = amplitude_x_l * t_x_l[j]**2
                sxp[i + j*nz] = -2 * amplitude_x_l * t_x_l[j]

        for i in range(ny*nz):
            for j in range(npml_x_r):
                sx[i + (j + (nx - npml_x_r))*nz] = amplitude_x_r * t_x_r[j]**2
                sxp[i + (j + (nx - npml_x_r))*nz] = 2 * amplitude_x_r * t_x_r[j]

        # PML for the y direction
        for i in range(nz):
            for j in range(nx):
                for k in range(npml_y_l):
                    sy[i*nx*ny + j + k*nx] = amplitude_y_l * t_y_l[k]**2
                    syp[i*nx*ny + j + k*nx] = -2 * amplitude_y_l * t_y_l[k]

        for i in range(nz):
            for j in range(nx):
                for k in range(npml_y_r):
                    sy[i*nx*ny + j + (k + (ny - npml_y_r))*nx] = amplitude_y_r * t_y_r[k]**2
                    syp[i*nx*ny + j + (k + (ny - npml_y_r))*nx] = 2 * amplitude_y_r * t_y_r[k]

        # PML for the z direction
        for i in range(nx*ny):
            for j in range(npml_z_l):
                sz[i*nz + j] = amplitude_z_l * t_z_l[j]**2
                szp[i*nz + j] = -2 * amplitude_z_l * t_z_l[j]

        for i in range(nx*ny):
            for j in range(npml_z_r):
                sz[i*nz + (nz - npml_z_r) + j] = amplitude_z_r * t_z_r[j]**2
                szp[i*nz + (nz - npml_z_r) + j] = 2 * amplitude_z_r * t_z_r[j]

        return (sx, sy, sz, sxp, syp, szp)

if self.mesh.x.lbc.type == 'pml' and self.compact:
            # build intermediates for compact operator
            dof = self.mesh.dof(include_bc=True)
            oc = self.operator_components
            built = oc.get('_numpy_components_built', False)
            oc.M = make_diag_mtx(self.model_parameters.C.squeeze()**-2)
            oc.I = spsp.eye(dof, dof)
            # build the static components
            if not built:
                # build Dxx
                oc.Dxx = build_derivative_matrix(self.mesh,
                                                 2,
                                                 self.spatial_accuracy_order,
                                                 dimension='x',
                                                 use_shifted_differences=self.spatial_shifted_differences)
                # build Dzz
                oc.Dzz = build_derivative_matrix(self.mesh,
                                                 2,
                                                 self.spatial_accuracy_order,
                                                 dimension='z',
                                                 use_shifted_differences=self.spatial_shifted_differences)
                # build Dyy
                oc.Dyy = build_derivative_matrix(self.mesh,
                                                 2,
                                                 self.spatial_accuracy_order,
                                                 dimension='y',
                                                 use_shifted_differences=self.spatial_shifted_differences)
                # build Dx
                oc.Dx = build_derivative_matrix(self.mesh,
                                                1,
                                                self.spatial_accuracy_order,
                                                dimension='x',
                                                use_shifted_differences=self.spatial_shifted_differences)

                # build Dz
                oc.Dz = build_derivative_matrix(self.mesh,
                                                1,
                                                self.spatial_accuracy_order,
                                                dimension='z',
                                                use_shifted_differences=self.spatial_shifted_differences)
                # build Dz
                oc.Dy = build_derivative_matrix(self.mesh,
                                                1,
                                                self.spatial_accuracy_order,
                                                dimension='y',
                                                use_shifted_differences=self.spatial_shifted_differences)

                # build sigma
                oc.sx, oc.sy, oc.sz, oc.sxp, oc.syp, oc.szp = self._sigma_PML(self.mesh)

                oc._numpy_components_built = True

        else:
            # build intermediates for operator with auxiliary fields
            dof = self.mesh.dof(include_bc=True)

            oc = self.operator_components

            built = oc.get('_numpy_components_built', False)

            oc.I = spsp.eye(dof, dof)

            # build the static components
            if not built:
                    # build laplacian
                oc.L = build_derivative_matrix(self.mesh,
                                               2,
                                               self.spatial_accuracy_order,
                                               use_shifted_differences=self.spatial_shifted_differences)

                # build sigmax
                sx = build_sigma(self.mesh, self.mesh.x)
                oc.sigmax = make_diag_mtx(sx)

                # build sigmay
                sy = build_sigma(self.mesh, self.mesh.y)
                oc.sigmay = make_diag_mtx(sy)

                # build sigmaz
                sz = build_sigma(self.mesh, self.mesh.z)
                oc.sigmaz = make_diag_mtx(sz)

                # build Dx
                oc.minus_Dx = build_derivative_matrix(self.mesh,
                                                      1,
                                                      self.spatial_accuracy_order,
                                                      dimension='x',
                                                      use_shifted_differences=self.spatial_shifted_differences)
                oc.minus_Dx.data *= -1

                # build Dy
                oc.minus_Dy = build_derivative_matrix(self.mesh,
                                                      1,
                                                      self.spatial_accuracy_order,
                                                      dimension='y',
                                                      use_shifted_differences=self.spatial_shifted_differences)
                oc.minus_Dy.data *= -1

                # build Dz
                oc.minus_Dz = build_derivative_matrix(self.mesh,
                                                      1,
                                                      self.spatial_accuracy_order,
                                                      dimension='z',
                                                      use_shifted_differences=self.spatial_shifted_differences)
                oc.minus_Dz.data *= -1

                # build other useful things
                oc.minus_I = -1*oc.I
                oc.empty = spsp.csr_matrix((dof, dof))

                # useful intermediates
                oc.sigma_sum_pair_prod = make_diag_mtx(sx*sy + sx*sz + sy*sz)
                oc.sigma_sum = make_diag_mtx(sx+sy+sz)
                oc.sigma_prod = make_diag_mtx(sx*sy*sz)
                oc.minus_sigma_yPzMx_Dx = make_diag_mtx(sy+sz-sx)*oc.minus_Dx
                oc.minus_sigma_xPzMy_Dy = make_diag_mtx(sx+sz-sy)*oc.minus_Dy
                oc.minus_sigma_xPyMz_Dz = make_diag_mtx(sx+sy-sz)*oc.minus_Dz

                oc.minus_sigma_yz_Dx = make_diag_mtx(sy*sz)*oc.minus_Dx
                oc.minus_sigma_zx_Dy = make_diag_mtx(sz*sx)*oc.minus_Dy
                oc.minus_sigma_xy_Dz = make_diag_mtx(sx*sy)*oc.minus_Dz

                oc._numpy_components_built = True

            C = self.model_parameters.C
            oc.m = make_diag_mtx((C**-2).reshape(-1,))

            self.K = spsp.bmat([[oc.m*oc.sigma_sum_pair_prod-oc.L, oc.m*oc.sigma_prod,   oc.minus_Dx, oc.minus_Dy, oc.minus_Dz],
                                [oc.minus_I,                       oc.empty,
                                    oc.empty,    oc.empty,    oc.empty],
                                [oc.minus_sigma_yPzMx_Dx,          oc.minus_sigma_yz_Dx,
                                    oc.sigmax,   oc.empty,    oc.empty],
                                [oc.minus_sigma_xPzMy_Dy,          oc.minus_sigma_zx_Dy,
                                    oc.empty,    oc.sigmay,   oc.empty],
                                [oc.minus_sigma_xPyMz_Dz,          oc.minus_sigma_xy_Dz, oc.empty,    oc.empty,    oc.sigmaz]])

            self.C = spsp.bmat([[oc.m*oc.sigma_sum, oc.empty, oc.empty, oc.empty, oc.empty],
                                [oc.empty,          oc.I,     oc.empty, oc.empty, oc.empty],
                                [oc.empty,          oc.empty, oc.I,     oc.empty, oc.empty],
                                [oc.empty,          oc.empty, oc.empty, oc.I,     oc.empty],
                                [oc.empty,          oc.empty, oc.empty, oc.empty, oc.I]]) / self.dt

            self.M = spsp.bmat([[oc.m, oc.empty, oc.empty, oc.empty, oc.empty],
                                [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty],
                                [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty],
                                [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty],
                                [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty]])

            self.dM = oc.I
            self.dC = oc.sigma_sum / self.dt
            self.dK = oc.sigma_sum_pair_prod

    class WavefieldVector(WavefieldVectorBase):

        aux_names = ['psi', 'Phix', 'Phiy', 'Phiz']


import scipy.sparse as spsp
import numpy as np

from pysit.solvers.wavefield_vector import *
from .constant_density_acoustic_frequency_scalar_base import *

from pysit.util import Bunch
from pysit.util import PositiveEvenIntegers
from pysit.util.derivatives import build_derivative_matrix
from pysit.util.matrix_helpers import build_sigma, make_diag_mtx

from pysit.util.solvers import inherit_dict

__all__ = ['ConstantDensityAcousticFrequencyScalar_3D']

__docformat__ = "restructuredtext en"

@inherit_dict('supports', '_local_support_spec')
class ConstantDensityAcousticFrequencyScalar_3D(ConstantDensityAcousticFrequencyScalarBase):

    _local_support_spec = {'spatial_discretization': 'finite-difference',
                           'spatial_dimension': 3,
                           'spatial_accuracy_order': PositiveEvenIntegers,
                           'boundary_conditions': ['pml', 'pml-sim', 'dirichlet'],
                           'precision': ['single', 'double']}

    def __init__(self,
                 mesh,
                 spatial_accuracy_order=4,
                 spatial_shifted_differences=True,
                 **kwargs):

        self.operator_components = Bunch()

        self.spatial_accuracy_order = spatial_accuracy_order

        self.spatial_shifted_differences = spatial_shifted_differences

        ConstantDensityAcousticFrequencyScalarBase.__init__(self,
                                                            mesh,
                                                            spatial_accuracy_order=spatial_accuracy_order,
                                                            spatial_shifted_differences=spatial_shifted_differences,
                                                            **kwargs)

        # In 3D there is only compact operator implemented
        if self.mesh.x.lbc.type == 'pml':
            if self.mesh.x.lbc.domain_bc.compact:
                self.compact = self.mesh.x.lbc.domain_bc.compact
            else:
                raise NotImplementedError(
                    '3D frequency helmholtz operator with auxilliary fields is not available please use the flag compact=True for setting')
        else:
            self.compact = False
            raise NotImplementedError(
                'Please set boundary conditions as PML with the flag compact=True')

    def _sigma_PML(self, mesh):
        nx, ny, nz = mesh.shape(include_bc=True, as_grid=True)
        # in mesh.py spacial direction seems to be ordered this way
        npml_x_l = mesh.x.lbc.n
        npml_x_r = mesh.x.rbc.n
        npml_z_l = mesh.z.lbc.n
        npml_z_r = mesh.z.rbc.n
        npml_y_l = mesh.y.lbc.n
        npml_y_r = mesh.y.rbc.n

        t_x_l = np.linspace(1, 0, npml_x_l)
        t_x_r = np.linspace(0, 1, npml_x_r)
        t_z_l = np.linspace(1, 0, npml_z_l)
        t_z_r = np.linspace(0, 1, npml_z_r)
        t_y_l = np.linspace(1, 0, npml_y_l)
        t_y_r = np.linspace(0, 1, npml_y_r)

        amplitude_x_l = mesh.x.lbc.domain_bc.amplitude
        amplitude_x_r = mesh.x.rbc.domain_bc.amplitude
        amplitude_z_l = mesh.z.lbc.domain_bc.amplitude
        amplitude_z_r = mesh.z.rbc.domain_bc.amplitude
        amplitude_y_l = mesh.y.lbc.domain_bc.amplitude
        amplitude_y_r = mesh.y.rbc.domain_bc.amplitude

        sx = np.zeros(nx*ny*nz)
        sy = np.zeros(nx*ny*nz)
        sz = np.zeros(nx*

        sxp = np.zeros(nx*ny*nz)
        syp = np.zeros(nx*ny*nz)
        szp = np.zeros(nx*ny*nz)

        # PML for the x direction
        for i in range(ny*nz):
            for j in range(npml_x_l):
                sx[i + j*nz] = amplitude_x_l * t_x_l[j]**2
                sxp[i + j*nz] = -2 * amplitude_x_l * t_x_l[j]

        for i in range(ny*nz):
            for j in range(npml_x_r):
                sx[i + (j + (nx - npml_x_r))*nz] = amplitude_x_r * t_x_r[j]**2
                sxp[i + (j + (nx - npml_x_r))*nz] = 2 * amplitude_x_r * t_x_r[j]

        # PML for the y direction
        for i in range(nz):
            for j in range(nx):
                for k in range(npml_y_l):
                    sy[i*nx*ny + j + k*nx] = amplitude_y_l * t_y_l[k]**2
                    syp[i*nx*ny + j + k*nx] = -2 * amplitude_y_l * t_y_l[k]

        for i in range(nz):
            for j in range(nx):
                for k in range(npml_y_r):
                    sy[i*nx*ny + j + (k + (ny - npml_y_r))*nx] = amplitude_y_r * t_y_r[k]**2
                    syp[i*nx*ny + j + (k + (ny - npml_y_r))*nx] = 2 * amplitude_y_r * t_y_r[k]

        # PML for the z direction
        for i in range(nx*ny):
            for j in range(npml_z_l):
                sz[i*nz + j] = amplitude_z_l * t_z_l[j]**2
                szp[i*nz + j] = -2 * amplitude_z_l * t_z_l[j]

        for i in range(nx*ny):
            for j in range(npml_z_r):
                sz[i*nz + (nz - npml_z_r) + j] = amplitude_z_r * t_z_r[j]**2
                szp[i*nz + (nz - npml_z_r) + j] = 2 * amplitude_z_r * t_z_r[j]

        return (sx, sy, sz, sxp, syp, szp)

    def _rebuild_operators(self):
        if self.mesh.x.lbc.type == 'pml' and self.compact:
            # build intermediates for compact operator
            dof = self.mesh.dof(include_bc=True)
            oc = self.operator_components
            built = oc.get('_numpy_components_built', False)
            oc.M = make_diag_mtx(self.model_parameters.C.squeeze()**-2)
            oc.I = spsp.eye(dof, dof)
            # build the static components
            if not built:
                # build Dxx
                oc.Dxx = build_derivative_matrix(self.mesh,
                                                 2,
                                                 self.spatial_accuracy_order,
                                                 dimension='x',
                                                 use_shifted_differences=self.spatial_shifted_differences)
                # build Dzz
                oc.Dzz = build_derivative_matrix(self.mesh,
                                                 2,
                                                 self.spatial_accuracy_order,
                                                 dimension='z',
                                                 use_shifted_differences=self.spatial_shifted_differences)
                # build Dyy
                oc.Dyy = build_derivative_matrix(self.mesh,
                                                 2,
                                                 self.spatial_accuracy_order,
                                                 dimension='y',
                                                 use_shifted_differences=self.spatial_shifted_differences)
                # build Dx
                oc.Dx = build_derivative_matrix(self.mesh,
                                                1,
                                                self.spatial_accuracy_order,
                                                dimension='x',
                                                use_shifted_differences=self.spatial_shifted_differences)

                # build Dz
                oc.Dz = build_derivative_matrix(self.mesh,
                                                1,
                                                self.spatial_accuracy_order,
                                                dimension='z',
                                                use_shifted_differences=self.spatial_shifted_differences)
                # build Dz
                oc.Dy = build_derivative_matrix(self.mesh,
                                                1,
                                                self.spatial_accuracy_order,
                                                dimension='y',
                                                use_shifted_differences=self.spatial_shifted_differences)

                # build sigma
                oc.sx, oc.sy, oc.sz, oc.sxp, oc.syp, oc.szp = self._sigma_PML(self.mesh)

                oc._numpy_components_built = True

        else:
            # build intermediates for operator with auxiliary fields
            dof = self.mesh.dof(include_bc=True)

            oc = self.operator_components

            built = oc.get('_numpy_components_built', False)

            oc.I = spsp.eye(dof, dof)

            # build the static components
            if not built:
                    # build laplacian
                oc.L = build_derivative_matrix(self.mesh,
                                               2,
                                               self.spatial_accuracy_order,
                                               use_shifted_differences=self.spatial_shifted_differences)

                # build sigmax
                sx = build_sigma(self.mesh, self.mesh.x)
                oc.sigmax = make_diag_mtx(sx)

                # build sigmay
                sy = build_sigma(self.mesh, self.mesh.y)
                oc.sigmay = make_diag_mtx(sy)

                # build sigmaz
                sz = build_sigma(self.mesh, self.mesh.z)
                oc.sigmaz = make_diag_mtx(sz)

                # build Dx
                oc.minus_Dx = build_derivative_matrix(self.mesh,
                                                      1,
                                                      self.spatial_accuracy_order,
                                                      dimension='x',
                                                      use_shifted_differences=self.spatial_shifted_differences)
                oc.minus_Dx.data *= -1

                # build Dy
                oc.minus_Dy = build_derivative_matrix(self.mesh,
                                                      1,
                                                      self.spatial_accuracy_order,
                                                      dimension='y',
                                                      use_shifted_differences=self.spatial_shifted_differences)
                oc.minus_Dy.data *= -1

                # build Dz
                oc.minus_Dz = build_derivative_matrix(self.mesh,
                                                      1,
                                                      self.spatial_accuracy_order,
                                                      dimension='z',
                                                      use_shifted_differences=self.spatial_shifted_differences)
                oc.minus_Dz.data *= -1

                # build other useful things
                oc.minus_I = -1*oc.I
                oc.empty = spsp.csr_matrix((dof, dof))

                # useful intermediates
                oc.sigma_sum_pair_prod = make_diag_mtx(sx*sy + sx*sz + sy*sz)
                oc.sigma_sum = make_diag_mtx(sx+sy+sz)
                oc.sigma_prod = make_diag_mtx(sx*sy*sz)
                oc.minus_sigma_yPzMx_Dx = make_diag_mtx(sy+sz-sx)*oc.minus_Dx
                oc.minus_sigma_xPzMy_Dy = make_diag_mtx(sx+sz-sy)*oc.minus_Dy
                oc.minus_sigma_xPyMz_Dz = make_diag_mtx(sx+sy-sz)*oc.minus_Dz

                oc.minus_sigma_yz_Dx = make_diag_mtx(sy*sz)*oc.minus_Dx
                oc.minus_sigma_zx_Dy = make_diag_mtx(sz*sx)*oc.minus_Dy
                oc.minus_sigma_xy_Dz = make_diag_mtx(sx*sy)*oc.minus_Dz

                oc._numpy_components_built = True

            C = self.model_parameters.C
            oc.m = make_diag_mtx((C**-2).reshape(-1,))

            self.K = spsp.bmat([[oc.m*oc.sigma_sum_pair_prod-oc.L, oc.m*oc.sigma_prod,   oc.minus_Dx, oc.minus_Dy, oc.minus_Dz],
                                [oc.minus_I,                       oc.empty,
                                    oc.empty,    oc.empty,    oc.empty],
                                [oc.minus_sigma_yPzMx_Dx,          oc.minus_sigma_yz_Dx,
                                    oc.sigmax,   oc.empty,    oc.empty],
                                [oc.minus_sigma_xPzMy_Dy,          oc.minus_sigma_zx_Dy,
                                    oc.empty,    oc.sigmay,   oc.empty],
                                [oc.minus_sigma_xPyMz_Dz,          oc.minus_sigma_xy_Dz, oc.empty,    oc.empty,    oc.sigmaz]])

            self.C = spsp.bmat([[oc.m*oc.sigma_sum, oc.empty, oc.empty, oc.empty, oc.empty],
                                [oc.empty,          oc.I,     oc.empty, oc.empty, oc.empty],
                                [oc.empty,          oc.empty, oc.I,     oc.empty, oc.empty],
                                [oc.empty,          oc.empty, oc.empty, oc.I,     oc.empty],
                                [oc.empty,          oc.empty, oc.empty, oc.empty, oc.I]]) / self.dt

            self.M = spsp.bmat([[oc.m, oc.empty, oc.empty, oc.empty, oc.empty],
                                [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty],
                                [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty],
                                [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty],
                                [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty]])

            self.dM = oc.I
            self.dC = oc.sigma_sum / self.dt
            self.dK = oc.sigma_sum_pair_prod

    class WavefieldVector(WavefieldVectorBase):

        aux_names = ['psi', 'Phix', 'Phiy', 'Phiz']


for k in range(npml_y_r):
                    sy[i*nx*ny + j + (k + (ny - npml_y_r))*nx] = amplitude_y_r * t_y_r[k]**2
                    syp[i*nx*ny + j + (k + (ny - npml_y_r))*nx] = 2 * amplitude_y_r * t_y_r[k]

import scipy.sparse as spsp
import numpy as np

from pysit.solvers.wavefield_vector import *
from .constant_density_acoustic_frequency_scalar_base import *

from pysit.util import Bunch
from pysit.util import PositiveEvenIntegers
from pysit.util.derivatives import build_derivative_matrix
from pysit.util.matrix_helpers import build_sigma, make_diag_mtx

from pysit.util.solvers import inherit_dict

__all__ = ['ConstantDensityAcousticFrequencyScalar_3D']

__docformat__ = "restructuredtext en"

@inherit_dict('supports', '_local_support_spec')
class ConstantDensityAcousticFrequencyScalar_3D(ConstantDensityAcousticFrequencyScalarBase):

    _local_support_spec = {'spatial_discretization': 'finite-difference',
                           'spatial_dimension': 3,
                           'spatial_accuracy_order': PositiveEvenIntegers,
                           'boundary_conditions': ['pml', 'pml-sim', 'dirichlet'],
                           'precision': ['single', 'double']}

    def __init__(self,
                 mesh,
                 spatial_accuracy_order=4,
                 spatial_shifted_differences=True,
                 **kwargs):

        self.operator_components = Bunch()

        self.spatial_accuracy_order = spatial_accuracy_order

        self.spatial_shifted_differences = spatial_shifted_differences

        ConstantDensityAcousticFrequencyScalarBase.__init__(self,
                                                            mesh,
                                                            spatial_accuracy_order=spatial_accuracy_order,
                                                            spatial_shifted_differences=spatial_shifted_differences,
                                                            **kwargs)

        # In 3D there is only compact operator implemented
        if self.mesh.x.lbc.type == 'pml':
            if self.mesh.x.lbc.domain_bc.compact:
                self.compact = self.mesh.x.lbc.domain_bc.compact
            else:
                raise NotImplementedError(
                    '3D frequency helmholtz operator with auxilliary fields is not available please use the flag compact=True for setting')
        else:
            self.compact = False
            raise NotImplementedError(
                'Please set boundary conditions as PML with the flag compact=True')

    def _sigma_PML(self, mesh):
        nx, ny, nz = mesh.shape(include_bc=True, as_grid=True)
        # in mesh.py spacial direction seems to be ordered this way
        npml_x_l = mesh.x.lbc.n
        npml_x_r = mesh.x.rbc.n
        npml_z_l = mesh.z.lbc.n
        npml_z_r = mesh.z.rbc.n
        npml_y_l = mesh.y.lbc.n
        npml_y_r = mesh.y.rbc.n

        t_x_l = np.linspace(1, 0, npml_x_l)
        t_x_r = np.linspace(0, 1, npml_x_r)
        t_z_l = np.linspace(1, 0, npml_z_l)
        t_z_r = np.linspace(0, 1, npml_z_r)
        t_y_l = np.linspace(1, 0, npml_y_l)
        t_y_r = np.linspace(0, 1, npml_y_r)

        amplitude_x_l = mesh.x.lbc.domain_bc.amplitude
        amplitude_x_r = mesh.x.rbc.domain_bc.amplitude
        amplitude_z_l = mesh.z.lbc.domain_bc.amplitude
        amplitude_z_r = mesh.z.rbc.domain_bc.amplitude
        amplitude_y_l = mesh.y.lbc.domain_bc.amplitude
        amplitude_y_r = mesh.y.rbc.domain_bc.amplitude

        sx = np.zeros(nx*ny*nz)
        sy = np.zeros(nx*ny*nz)
        sz = np.zeros(nx*ny*nz)
        sxp = np.zeros(nx*ny*nz)
        syp = np.zeros(nx*ny*nz)
        szp = np.zeros(nx*ny*nz)

        # PML for the x direction
        for i in range(ny*nz):
            for j in range(npml_x_l):
                sx[i + j*nz] = amplitude_x_l * t_x_l[j]**2
                sxp[i + j*nz] = -2 * amplitude_x_l * t_x_l[j]

        for i in range(ny*nz):
            for j in range(npml_x_r):
                sx[i + (j + (nx - npml_x_r))*nz] = amplitude_x_r * t_x_r[j]**2
                sxp[i + (j + (nx - npml_x_r))*nz] = 2 * amplitude_x_r * t_x_r[j]

        # PML for the y direction
        for i in range(nz):
            for j in range(nx):
                for k in range(npml_y_l):
                    sy[i*nx*ny + j + k*nx] = amplitude_y_l * t_y_l[k]**2
                    syp[i*nx*ny + j + k*nx] = -2 * amplitude_y_l * t_y_l[k]

        for i in range(nz):
            for j in range(nx):

        # PML for the z direction
        for i in range(nx*ny):
            for j in range(npml_z_l):
                sz[i*nz + j] = amplitude_z_l * t_z_l[j]**2
                szp[i*nz + j] = -2 * amplitude_z_l * t_z_l[j]

        for i in range(nx*ny):
            for j in range(npml_z_r):
                sz[i*nz + (nz - npml_z_r) + j] = amplitude_z_r * t_z_r[j]**2
                szp[i*nz + (nz - npml_z_r) + j] = 2 * amplitude_z_r * t_z_r[j]

        return (sx, sy, sz, sxp, syp, szp)

    def _rebuild_operators(self):
        if self.mesh.x.lbc.type == 'pml' and self.compact:
            # build intermediates for compact operator
            dof = self.mesh.dof(include_bc=True)
            oc = self.operator_components
            built = oc.get('_numpy_components_built', False)
            oc.M = make_diag_mtx(self.model_parameters.C.squeeze()**-2)
            oc.I = spsp.eye(dof, dof)
            # build the static components
            if not built:
                # build Dxx
                oc.Dxx = build_derivative_matrix(self.mesh,
                                                 2,
                                                 self.spatial_accuracy_order,
                                                 dimension='x',
                                                 use_shifted_differences=self.spatial_shifted_differences)
                # build Dzz
                oc.Dzz = build_derivative_matrix(self.mesh,
                                                 2,
                                                 self.spatial_accuracy_order,
                                                 dimension='z',
                                                 use_shifted_differences=self.spatial_shifted_differences)
                # build Dyy
                oc.Dyy = build_derivative_matrix(self.mesh,
                                                 2,
                                                 self.spatial_accuracy_order,
                                                 dimension='y',
                                                 use_shifted_differences=self.spatial_shifted_differences)
                # build Dx
                oc.Dx = build_derivative_matrix(self.mesh,
                                                1,
                                                self.spatial_accuracy_order,
                                                dimension='x',
                                                use_shifted_differences=self.spatial_shifted_differences)

                # build Dz
                oc.Dz = build_derivative_matrix(self.mesh,
                                                1,
                                                self.spatial_accuracy_order,
                                                dimension='z',
                                                use_shifted_differences=self.spatial_shifted_differences)
                # build Dz
                oc.Dy = build_derivative_matrix(self.mesh,
                                                1,
                                                self.spatial_accuracy_order,
                                                dimension='y',
                                                use_shifted_differences=self.spatial_shifted_differences)

                # build sigma
                oc.sx, oc.sy, oc.sz, oc.sxp, oc.syp, oc.szp = self._sigma_PML(self.mesh)

                oc._numpy_components_built = True

        else:
            # build intermediates for operator with auxiliary fields
            dof = self.mesh.dof(include_bc=True)

            oc = self.operator_components

            built = oc.get('_numpy_components_built', False)

            oc.I = spsp.eye(dof, dof)

            # build the static components
            if not built:
                    # build laplacian
                oc.L = build_derivative_matrix(self.mesh,
                                               2,
                                               self.spatial_accuracy_order,
                                               use_shifted_differences=self.spatial_shifted_differences)

                # build sigmax
                sx = build_sigma(self.mesh, self.mesh.x)
                oc.sigmax = make_diag_mtx(sx)

                # build sigmay
                sy = build_sigma(self.mesh, self.mesh.y)
                oc.sigmay = make_diag_mtx(sy)

                # build sigmaz
                sz = build_sigma(self.mesh, self.mesh.z)
                oc.sigmaz = make_diag_mtx(sz)

                # build Dx
                oc.minus_Dx = build_derivative_matrix(self.mesh,
                                                      1,
                                                      self.spatial_accuracy_order,
                                                      dimension='x',
                                                      use_shifted_differences=self.spatial_shifted_differences)
                oc.minus_Dx.data *= -1

                # build Dy
                oc.minus_Dy = build_derivative_matrix(self.mesh,
                                                      1,
                                                      self.spatial_accuracy_order,
                                                      dimension='y',
                                                      use_shifted_differences=self.spatial_shifted_differences)
                oc.minus_Dy.data *= -1

                # build Dz
                oc.minus_Dz = build_derivative_matrix(self.mesh,
                                                      1,
                                                      self.spatial_accuracy_order,
                                                      dimension='z',
                                                      use_shifted_differences=self.spatial_shifted_differences)
                oc.minus_Dz.data *= -1

                # build other useful things
                oc.minus_I = -1*oc.I
                oc.empty = spsp.csr_matrix((dof, dof))

                # useful intermediates
                oc.sigma_sum_pair_prod = make_diag_mtx(sx*sy + sx*sz + sy*sz)
                oc.sigma_sum = make_diag_mtx(sx+sy+sz)
                oc.sigma_prod = make_diag_mtx(sx*sy*sz)
                oc.minus_sigma_yPzMx_Dx = make_diag_mtx(sy+sz-sx)*oc.minus_Dx
                oc.minus_sigma_xPzMy_Dy = make_diag_mtx(sx+sz-sy)*oc.minus_Dy
                oc.minus_sigma_xPyMz_Dz = make_diag_mtx(sx+sy-sz)*oc.minus_Dz

                oc.minus_sigma_yz_Dx = make_diag_mtx(sy*sz)*oc.minus_Dx
                oc.minus_sigma_zx_Dy = make_diag_mtx(sz*sx)*oc.minus_Dy
                oc.minus_sigma_xy_Dz = make_diag_mtx(sx*sy)*oc.minus_Dz

                oc._numpy_components_built = True

            C = self.model_parameters.C
            oc.m = make_diag_mtx((C**-2).reshape(-1,))

            self.K = spsp.bmat([[oc.m*oc.sigma_sum_pair_prod-oc.L, oc.m*oc.sigma_prod,   oc.minus_Dx, oc.minus_Dy, oc.minus_Dz],
                                [oc.minus_I,                       oc.empty,
                                    oc.empty,    oc.empty,    oc.empty],
                                [oc.minus_sigma_yPzMx_Dx,          oc.minus_sigma_yz_Dx,
                                    oc.sigmax,   oc.empty,    oc.empty],
                                [oc.minus_sigma_xPzMy_Dy,          oc.minus_sigma_zx_Dy,
                                    oc.empty,    oc.sigmay,   oc.empty],
                                [oc.minus_sigma_xPyMz_Dz,          oc.minus_sigma_xy_Dz, oc.empty,    oc.empty,    oc.sigmaz]])

            self.C = spsp.bmat([[oc.m*oc.sigma_sum, oc.empty, oc.empty, oc.empty, oc.empty],
                                [oc.empty,          oc.I,     oc.empty, oc.empty, oc.empty],
                                [oc.empty,          oc.empty, oc.I,     oc.empty, oc.empty],
                                [oc.empty,          oc.empty, oc.empty, oc.I,     oc.empty],
                                [oc.empty,          oc.empty, oc.empty, oc.empty, oc.I]]) / self.dt

            self.M = spsp.bmat([[oc.m, oc.empty, oc.empty, oc.empty, oc.empty],
                                [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty],
                                [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty],
                                [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty],
                                [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty]])

            self.dM = oc.I
            self.dC = oc.sigma_sum / self.dt
            self.dK = oc.sigma_sum_pair_prod

    class WavefieldVector(WavefieldVectorBase):

        aux_names = ['psi', 'Phix', 'Phiy', 'Phiz']


import math
import random
import xy

def ellipse(x, y, rx, ry, n=36):
    result = []
    for i in range(n + 1):
        p = i / float(n)
        a = 2 * math.pi * p
        px = x + math.cos(a) * rx
        py = y + math.sin(a) * ry
        result.append((px, py))
    return result

def create_eye(x, y):
    result = []
    r = (random.random() * 1 + 1) * 0.2
    a = random.random() * 0.8 + 0.1
    rx = r * a
    ry = r * (1 - a)
    s = rx + random.random() * 0.025
    result.append(ellipse(x + s, y, rx, ry))
    result.append(ellipse(x - s, y, rx, ry))
    r = (random.random() * 1 + 1) * 0.05
    a = random.random() * 0.8 + 0.1
    da = random.random() * 2 * math.pi
    d = random.random() * 0.1
    dx = math.cos(da) * d
    dy = math.sin(da) * d
    result.append(ellipse(dx + x + s, dy + y, r * a, r * (1 - a)))
    result.append(ellipse(dx + x - s, dy + y, r * a, r * (1 - a)))
    r = (random.random() * 1 + 1) * 0.2
    a = random.random() * 0.8 + 0.1
    result.append(ellipse(x, y - 0.25, r * a, r * (1 - a)))
    o = 0.25 + r * (1 - a) + random.random() * 0.25
    r = random.random() ** 2 * 4 + 0.1
    d = random.random() * 0.2 + 0.05
    sign = random.choice([1, -1])
    da = math.degrees(math.atan2(d, r))
    if sign > 0:
        result.append(xy.arc(x, y - o + r * sign, r, 270 - da, 270 + da))
    else:
        result.append(xy.arc(x, y - o + r * sign, r, 90 - da, 90 + da))
    return result

def create_paths():
    result = []
    for y in range(6*3):
        for x in range(5*3):
            result.extend(create_eye(x, y))
    return result

paths = create_paths()
    drawing = xy.Drawing(paths).scale_to_fit(315, 380)
    drawing = drawing.sort_paths_greedy()
    im = drawing.render()
    im.write_to_png('eyes.png')

if __name__ == '__main__':
    main()


result = []
    for y in range(6*3):
        for x in range(5*3):
            result.extend(create_eye(x, y))
    return result

import math
import random
import xy

def ellipse(x, y, rx, ry, n=36):
    result = []
    for i in range(n + 1):
        p = i / float(n)
        a = 2 * math.pi * p
        px = x + math.cos(a) * rx
        py = y + math.sin(a) * ry
        result.append((px, py))
    return result

def create_eye(x, y):
    result = []
    r = (random.random() * 1 + 1) * 0.2
    a = random.random() * 0.8 + 0.1
    rx = r * a
    ry = r * (1 - a)
    s = rx + random.random() * 0.025
    result.append(ellipse(x + s, y, rx, ry))
    result.append(ellipse(x - s, y, rx, ry))
    r = (random.random() * 1 + 1) * 0.05
    a = random.random() * 0.8 + 0.1
    da = random.random() * 2 * math.pi
    d = random.random() * 0.1
    dx = math.cos(da) * d
    dy = math.sin(da) * d
    result.append(ellipse(dx + x + s, dy + y, r * a, r * (1 - a)))
    result.append(ellipse(dx + x - s, dy + y, r * a, r * (1 - a)))
    r = (random.random() * 1 + 1) * 0.2
    a = random.random() * 0.8 + 0.1
    result.append(ellipse(x, y - 0.25, r * a, r * (1 - a)))
    o = 0.25 + r * (1 - a) + random.random() * 0.25
    r = random.random() ** 2 * 4 + 0.1
    d = random.random() * 0.2 + 0.05
    sign = random.choice([1, -1])
    da = math.degrees(math.atan2(d, r))
    if sign > 0:
        result.append(xy.arc(x, y - o + r * sign, r, 270 - da, 270 + da))
    else:
        result.append(xy.arc(x, y - o + r * sign, r, 90 - da, 90 + da))
    return result

def create_paths():

def main():
    paths = create_paths()
    drawing = xy.Drawing(paths).scale_to_fit(315, 380)
    drawing = drawing.sort_paths_greedy()
    im = drawing.render()
    im.write_to_png('eyes.png')

if __name__ == '__main__':
    main()


import math
import random
import xy

def ellipse(x, y, rx, ry, n=36):
    result = []
    for i in range(n + 1):
        p = i / float(n)
        a = 2 * math.pi * p
        px = x + math.cos(a) * rx
        py = y + math.sin(a) * ry
        result.append((px, py))
    return result

def create_eye(x, y):
    result = []
    r = (random.random() * 1 + 1) * 0.2
    a = random.random() * 0.8 + 0.1
    rx = r * a
    ry = r * (1 - a)
    s = rx + random.random() * 0.025
    result.append(ellipse(x + s, y, rx, ry))
    result.append(ellipse(x - s, y, rx, ry))
    r = (random.random() * 1 + 1) * 0.05
    a = random.random() * 0.8 + 0.1
    da = random.random() * 2 * math.pi
    d = random.random()

    dx = math.cos(da) * d
    dy = math.sin(da) * d
    result.append(ellipse(dx + x + s, dy + y, r * a, r * (1 - a)))
    result.append(ellipse(dx + x - s, dy + y, r * a, r * (1 - a)))
    r = (random.random() * 1 + 1) * 0.2
    a = random.random() * 0.8 + 0.1
    result.append(ellipse(x, y - 0.25, r * a, r * (1 - a)))
    o = 0.25 + r * (1 - a) + random.random() * 0.25
    r = random.random() ** 2 * 4 + 0.1
    d = random.random() * 0.2 + 0.05
    sign = random.choice([1, -1])
    da = math.degrees(math.atan2(d, r))
    if sign > 0:
        result.append(xy.arc(x, y - o + r * sign, r, 270 - da, 270 + da))
    else:
        result.append(xy.arc(x, y - o + r * sign, r, 90 - da, 90 + da))
    return result

def create_paths():
    result = []
    for y in range(6*3):
        for x in range(5*3):
            result.extend(create_eye(x, y))
    return result

def main():
    paths = create_paths()
    drawing = xy.Drawing(paths).scale_to_fit(315, 380)
    drawing = drawing.sort_paths_greedy()
    im = drawing.render()
    im.write_to_png('eyes.png')

if __name__ == '__main__':
    main()


for i in range(n + 1):
        p = i / float(n)
        a = 2 * math.pi * p
        px = x + math.cos(a) * rx
        py = y + math.sin(a) * ry
        result.append((px, py))

import math
import random
import xy

def ellipse(x, y, rx, ry, n=36):
    result = []

    return result

def create_eye(x, y):
    result = []
    r = (random.random() * 1 + 1) * 0.2
    a = random.random() * 0.8 + 0.1
    rx = r * a
    ry = r * (1 - a)
    s = rx + random.random() * 0.025
    result.append(ellipse(x + s, y, rx, ry))
    result.append(ellipse(x - s, y, rx, ry))
    r = (random.random() * 1 + 1) * 0.05
    a = random.random() * 0.8 + 0.1
    da = random.random() * 2 * math.pi
    d = random.random() * 0.1
    dx = math.cos(da) * d
    dy = math.sin(da) * d
    result.append(ellipse(dx + x + s, dy + y, r * a, r * (1 - a)))
    result.append(ellipse(dx + x - s, dy + y, r * a, r * (1 - a)))
    r = (random.random() * 1 + 1) * 0.2
    a = random.random() * 0.8 + 0.1
    result.append(ellipse(x, y - 0.25, r * a, r * (1 - a)))
    o = 0.25 + r * (1 - a) + random.random() * 0.25
    r = random.random() ** 2 * 4 + 0.1
    d = random.random() * 0.2 + 0.05
    sign = random.choice([1, -1])
    da = math.degrees(math.atan2(d, r))
    if sign > 0:
        result.append(xy.arc(x, y - o + r * sign, r, 270 - da, 270 + da))
    else:
        result.append(xy.arc(x, y - o + r * sign, r, 90 - da, 90 + da))
    return result

def create_paths():
    result = []
    for y in range(6*3):
        for x in range(5*3):
            result.extend(create_eye(x, y))
    return result

def main():
    paths = create_paths()
    drawing = xy.Drawing(paths).scale_to_fit(315, 380)
    drawing = drawing.sort_paths_greedy()
    im = drawing.render()
    im.write_to_png('eyes.png')

if __name__ == '__main__':
    main()


from ..attributetype import AttributeType
from ..exceptions import LDAPExtensionError
from ..controls import Control
from ..objectclass import ObjectClass
from ..rules import SyntaxRule, MatchingRule
from ..utils import get_obj_module
import six
import logging

logger = logging.getLogger(__name__)

_preregistered_elements = {}
_registered_mods = set()

_recognized_subclasses = (SyntaxRule, MatchingRule, Control)
_recognized_instances = (ObjectClass, AttributeType)

class MetaLaurelinTransiter(type):
    """Prepares schema elements and controls defined as attributes of infraclasses for registration"""

cls = type.__new__(mcs, name, bases, dct)
        modname = get_obj_module(cls)

        for attr, value in dct.items():
            if attr.startswith('_'):
                continue

            if isinstance(value, six.class_types) and issubclass(value, _recognized_subclasses):
                is_element = True
            elif isinstance(value, _recognized_instances):
                is_element = True
            else:
                is_element = False

            if is_element:
                if modname not in _preregistered_elements:
                    _preregistered_elements[modname] = []
                _preregistered_elements[modname].append(value)

        return cls

@six.add_metaclass(MetaLaurelinTransiter)
class LaurelinTransiter(object):
    """Base class for classes in extensions defining schema elements or controls"""
    pass

class LaurelinRegistrar(object):
    """The require() method on this class registers all schema and controls in a module.

    If this class is subclassed in an extension module (such as with LaurelinExtension), there is no need to pass an
    argument to the constructor. However, for extensions with many schema elements or controls, it may be desirable to
    break up these objects into multiple submodules that are imported on end-user request.

    In such a setup, an instance of LaurelinRegistrar would need to be created and exposed to the end-user for each
    submodule so that they can call ``.require()`` on it. This constructor would need to be passed ``__name__``.

    Note that if this is applied to a package, require() will function on all imported submodules of the package.
    """

    def __init__(self, modname=None):
        if modname:
            self.modname = modname
        else:
            self.modname = get_obj_module(self.__class__)
            if self.modname == __name__:
                raise LDAPExtensionError('You must pass __name__ to LaurelinRegistrar()')

    def require(self):
        """Register schema elements and controls defined in any LaurelinTransiter subclass in the same module as the
        calling class. If the calling class is defined in an __init__.py, also register schema/controls for submodules
        that have been imported.
        """
        if self.modname in _registered_mods:
            return
        package_prefix = self.modname + '.'
        for key_modname, elements in _preregistered_elements.items():
            # check for prefix to allow definition in submodules of a package
            if key_modname in _registered_mods:
                continue
            if key_modname == self.modname or key_modname.startswith(package_prefix):
                logger.debug('Registering schema and controls for {0}'.format(key_modname))
                for obj in elements:
                    obj.register()
                _registered_mods.add(self.modname)


if modname:
            self.modname = modname
        else:
            self.modname = get_obj_module(self.__class__)
            if self.modname == __name__:
                raise LDAPExtensionError('You must pass __name__ to LaurelinRegistrar()')

from ..attributetype import AttributeType
from ..exceptions import LDAPExtensionError
from ..controls import Control
from ..objectclass import ObjectClass
from ..rules import SyntaxRule, MatchingRule
from ..utils import get_obj_module
import six
import logging

logger = logging.getLogger(__name__)

_preregistered_elements = {}
_registered_mods = set()

_recognized_subclasses = (SyntaxRule, MatchingRule, Control)
_recognized_instances = (ObjectClass, AttributeType)

class MetaLaurelinTransiter(type):
    """Prepares schema elements and controls defined as attributes of infraclasses for registration"""
    def __new__(mcs, name, bases, dct):
        cls = type.__new__(mcs, name, bases, dct)
        modname = get_obj_module(cls)

        for attr, value in dct.items():
            if attr.startswith('_'):
                continue

            if isinstance(value, six.class_types) and issubclass(value, _recognized_subclasses):
                is_element = True
            elif isinstance(value, _recognized_instances):
                is_element = True
            else:
                is_element = False

            if is_element:
                if modname not in _preregistered_elements:
                    _preregistered_elements[modname] = []
                _preregistered_elements[modname].append(value)

        return cls

@six.add_metaclass(MetaLaurelinTransiter)
class LaurelinTransiter(object):
    """Base class for classes in extensions defining schema elements or controls"""
    pass

class LaurelinRegistrar(object):
    """The require() method on this class registers all schema and controls in a module.

    If this class is subclassed in an extension module (such as with LaurelinExtension), there is no need to pass an
    argument to the constructor. However, for extensions with many schema elements or controls, it may be desirable to
    break up these objects into multiple submodules that are imported on end-user request.

    In such a setup, an instance of LaurelinRegistrar would need to be created and exposed to the end-user for each
    submodule so that they can call ``.require()`` on it. This constructor would need to be passed ``__name__``.

    Note that if this is applied to a package, require() will function on all imported submodules of the package.
    """

    def __init__(self, modname=None):

    def require(self):
        """Register schema elements and controls defined in any LaurelinTransiter subclass in the same module as the
        calling class. If the calling class is defined in an __init__.py, also register schema/controls for submodules
        that have been imported.
        """
        if self.modname in _registered_mods:
            return
        package_prefix = self.modname + '.'
        for key_modname, elements in _preregistered_elements.items():
            # check for prefix to allow definition in submodules of a package
            if key_modname in _registered_mods:
                continue
            if key_modname == self.modname or key_modname.startswith(package_prefix):
                logger.debug('Registering schema and controls for {0}'.format(key_modname))
                for obj in elements:
                    obj.register()
                _registered_mods.add(self.modname)


from ..attributetype import AttributeType
from ..exceptions import LDAPExtensionError
from ..controls import Control
from ..objectclass import ObjectClass
from ..rules import SyntaxRule, MatchingRule
from ..utils import get_obj_module
import six
import logging

logger = logging.getLogger(__name__)

_preregistered_elements = {}
_registered_mods = set()

_recognized_subclasses = (SyntaxRule, MatchingRule, Control)
_recognized_instances = (ObjectClass, AttributeType)

class MetaLaurelinTransiter(type):
    """Prepares schema elements and controls defined as attributes of infraclasses for registration"""
    def __new__(mcs, name, bases, dct):
        cls = type.__new__(mcs, name, bases, dct)
        modname = get_obj_module(cls)

        for attr, value in dct.items():
            if attr.startswith('_'):
                continue

            if isinstance(value, six.class_types) and issubclass(value, _recognized_subclasses):
                is_element = True
            elif isinstance(value, _recognized_instances):
                is_element = True
            else:
                is_element = False

            if is_element:
                if modname not in _preregistered_elements:
                    _preregistered_elements[modname] = []
                _preregistered_elements[modname].append(value)

        retu

@six.add_metaclass(MetaLaurelinTransiter)
class LaurelinTransiter(object):
    """Base class for classes in extensions defining schema elements or controls"""
    pass

class LaurelinRegistrar(object):
    """The require() method on this class registers all schema and controls in a module.

    If this class is subclassed in an extension module (such as with LaurelinExtension), there is no need to pass an
    argument to the constructor. However, for extensions with many schema elements or controls, it may be desirable to
    break up these objects into multiple submodules that are imported on end-user request.

    In such a setup, an instance of LaurelinRegistrar would need to be created and exposed to the end-user for each
    submodule so that they can call ``.require()`` on it. This constructor would need to be passed ``__name__``.

    Note that if this is applied to a package, require() will function on all imported submodules of the package.
    """

    def __init__(self, modname=None):
        if modname:
            self.modname = modname
        else:
            self.modname = get_obj_module(self.__class__)
            if self.modname == __name__:
                raise LDAPExtensionError('You must pass __name__ to LaurelinRegistrar()')

    def require(self):
        """Register schema elements and controls defined in any LaurelinTransiter subclass in the same module as the
        calling class. If the calling class is defined in an __init__.py, also register schema/controls for submodules
        that have been imported.
        """
        if self.modname in _registered_mods:
            return
        package_prefix = self.modname + '.'
        for key_modname, elements in _preregistered_elements.items():
            # check for prefix to allow definition in submodules of a package
            if key_modname in _registered_mods:
                continue
            if key_modname == self.modname or key_modname.startswith(package_prefix):
                logger.debug('Registering schema and controls for {0}'.format(key_modname))
                for obj in elements:
                    obj.register()
                _registered_mods.add(self.modname)


for obj in elements:
                    obj.register()

from ..attributetype import AttributeType
from ..exceptions import LDAPExtensionError
from ..controls import Control
from ..objectclass import ObjectClass
from ..rules import SyntaxRule, MatchingRule
from ..utils import get_obj_module
import six
import logging

logger = logging.getLogger(__name__)

_preregistered_elements = {}
_registered_mods = set()

_recognized_subclasses = (SyntaxRule, MatchingRule, Control)
_recognized_instances = (ObjectClass, AttributeType)

class MetaLaurelinTransiter(type):
    """Prepares schema elements and controls defined as attributes of infraclasses for registration"""
    def __new__(mcs, name, bases, dct):
        cls = type.__new__(mcs, name, bases, dct)
        modname = get_obj_module(cls)

        for attr, value in dct.items():
            if attr.startswith('_'):
                continue

            if isinstance(value, six.class_types) and issubclass(value, _recognized_subclasses):
                is_element = True
            elif isinstance(value, _recognized_instances):
                is_element = True
            else:
                is_element = False

            if is_element:
                if modname not in _preregistered_elements:
                    _preregistered_elements[modname] = []
                _preregistered_elements[modname].append(value)

        return cls

@six.add_metaclass(MetaLaurelinTransiter)
class LaurelinTransiter(object):
    """Base class for classes in extensions defining schema elements or controls"""
    pass

class LaurelinRegistrar(object):
    """The require() method on this class registers all schema and controls in a module.

    If this class is subclassed in an extension module (such as with LaurelinExtension), there is no need to pass an
    argument to the constructor. However, for extensions with many schema elements or controls, it may be desirable to
    break up these objects into multiple submodules that are imported on end-user request.

    In such a setup, an instance of LaurelinRegistrar would need to be created and exposed to the end-user for each
    submodule so that they can call ``.require()`` on it. This constructor would need to be passed ``__name__``.

    Note that if this is applied to a package, require() will function on all imported submodules of the package.
    """

    def __init__(self, modname=None):
        if modname:
            self.modname = modname
        else:
            self.modname = get_obj_module(self.__class__)
            if self.modname == __name__:
                raise LDAPExtensionError('You must pass __name__ to LaurelinRegistrar()')

    def require(self):
        """Register schema elements and controls defined in any LaurelinTransiter subclass in the same module as the
        calling class. If the calling class is defined in an __init__.py, also register schema/controls for submodules
        that have been imported.
        """
        if self.modname in _registered_mods:
            return
        package_prefix = self.modname + '.'
        for key_modname, elements in _preregistered_elements.items():
            # check for prefix to allow definition in submodules of a package
            if key_modname in _registered_mods:
                continue
            if key_modname == self.modname or key_modname.startswith(package_prefix):
                logger.debug('Registering schema and controls for {0}'.format(key_modname))


try:
        fd = int(sys.argv[2])

        try:
            os.write(fd, b"blat")
        except OSError:
            # Success -- could not write to fd.
            sys.exit(0)
        else:
            if verbose:
                sys.stderr.write("fd %d is open in child" % fd)
            sys.exit(1)

    except Exception:
        if verbose:
            raise
        sys.exit(1)

# Helper script for test_tempfile.py.  argv[2] is the number of a file
# descriptor which should _not_ be open.  Check this by attempting to
# write to it -- if we succeed, something is wrong.

import sys
import os
from test.support import SuppressCrashReport

with SuppressCrashReport():
    verbose = (sys.argv[1] == 'v')


import torch
from torch.autograd import Function
from torch.autograd.function import once_differentiable

from dynamic_rcnn import _C

class DeformRoIPoolingFunction(Function):

    @staticmethod
    def forward(
        ctx,
        data,
        rois,
        offset,
        spatial_scale,
        out_size,
        out_channels,
        no_trans,
        group_size=1,
        part_size=None,
        sample_per_part=4,
        trans_std=.0
    ):
        ctx.spatial_scale = spatial_scale
        ctx.out_size = out_size
        ctx.out_channels = out_channels
        ctx.no_trans = no_trans
        ctx.group_size = group_size
        ctx.part_size = out_size if part_size is None else part_size
        ctx.sample_per_part = sample_per_part
        ctx.trans_std = trans_std

        assert 0.0 <= ctx.trans_std <= 1.0
        if not data.is_cuda:
            raise NotImplementedError

        n = rois.shape[0]
        output = data.new_empty(n, out_channels, out_size, out_size)
        output_count = data.new_empty(n, out_channels, out_size, out_size)
        _C.deform_psroi_pooling_forward(
            data,
            rois,
            offset,
            output,
            output_count,
            ctx.no_trans,
            ctx.spatial_scale,
            ctx.out_channels,
            ctx.group_size,
            ctx.out_size,
            ctx.part_size,
            ctx.sample_per_part,
            ctx.trans_std
        )

        if data.requires_grad or rois.requires_grad or offset.requires_grad:
            ctx.save_for_backward(data, rois, offset)
        ctx.output_count = output_count

        return output

    @staticmethod
    @once_differentiable

if not grad_output.is_cuda:
            raise NotImplementedError

        data, rois, offset = ctx.saved_tensors
        output_count = ctx.output_count
        grad_input = torch.zeros_like(data)
        grad_rois = None
        grad_offset = torch.zeros_like(offset)

        _C.deform_psroi_pooling_backward(
            grad_output,
            data,
            rois,
            offset,
            output_count,
            grad_input,
            grad_offset,
            ctx.no_trans,
            ctx.spatial_scale,
            ctx.out_channels,
            ctx.group_size,
            ctx.out_size,
            ctx.part_size,
            ctx.sample_per_part,
            ctx.trans_std
        )
        return (grad_input, grad_rois, grad_offset, None, None, None, None, None, None, None, None)

deform_roi_pooling = DeformRoIPoolingFunction.apply


import torch
from torch.autograd import Function
from torch.autograd.function import once_differentiable

from dynamic_rcnn import _C

class DeformRoIPoolingFunction(Function):

    @staticmethod
    def forward(
        ctx,
        data,
        rois,
        offset,
        spatial_scale,
        out_size,
        out_channels,
        no_trans,
        group_size=1,
        part_size=None,
        sample_per_part=4,
        trans_std=.0
    ):
        ctx.spatial_scale = spatial_scale
        ctx.out_size = out_size
        ctx.out_channels = out_channels
        ctx.no_trans = no_trans
        ctx.group_size = group_size
        ctx.part_size = out_size if part_size is None else part_size
        ctx.sample_per_part = sample_per_part
        ctx.trans_std = trans_std

        assert 0.0 <= ctx.trans_std <=

        if not data.is_cuda:
            raise NotImplementedError

        n = rois.shape[0]
        output = data.new_empty(n, out_channels, out_size, out_size)
        output_count = data.new_empty(n, out_channels, out_size, out_size)
        _C.deform_psroi_pooling_forward(
            data,
            rois,
            offset,
            output,
            output_count,
            ctx.no_trans,
            ctx.spatial_scale,
            ctx.out_channels,
            ctx.group_size,
            ctx.out_size,
            ctx.part_size,
            ctx.sample_per_part,
            ctx.trans_std
        )

        if data.requires_grad or rois.requires_grad or offset.requires_grad:
            ctx.save_for_backward(data, rois, offset)
        ctx.output_count = output_count

        return output

    @staticmethod
    @once_differentiable
    def backward(ctx, grad_output):
        if not grad_output.is_cuda:
            raise NotImplementedError

        data, rois, offset = ctx.saved_tensors
        output_count = ctx.output_count
        grad_input = torch.zeros_like(data)
        grad_rois = None
        grad_offset = torch.zeros_like(offset)

        _C.deform_psroi_pooling_backward(
            grad_output,
            data,
            rois,
            offset,
            output_count,
            grad_input,
            grad_offset,
            ctx.no_trans,
            ctx.spatial_scale,
            ctx.out_channels,
            ctx.group_size,
            ctx.out_size,
            ctx.part_size,
            ctx.sample_per_part,
            ctx.trans_std
        )
        return (grad_input, grad_rois, grad_offset, None, None, None, None, None, None, None, None)

deform_roi_pooling = DeformRoIPoolingFunction.apply


def named_partial(func, *args, **kwargs):

from functools import partial, update_wrapper
import Metrics
import ContentCentricMeasurements
import UserCentricMeasurements
from BaselineMeasurements import *

import pprint

partial_func = partial(func, *args, **kwargs)
    update_wrapper(partial_func, func)
    partial_func.varnames = func.__code__.co_varnames
    return partial_func

reddit_events = ["post","comment"]

user_measurement_params = {
    ### User Centric Measurements
     "user_unique_content": {
         'question': '17',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getUserUniqueContent",
         "measurement_args":{"eventTypes":reddit_events,"content_field":"root"},
         "metrics": {
             "js_divergence": named_partial(Metrics.js_divergence, discrete=False),
             "rmse": Metrics.rmse,
             "nrmse": named_partial(Metrics.rmse,relative=True),
             "r2": Metrics.r2}
     },

     "user_activity_timeline": {
         "question": '19',
         "scale": "node",
         "node_type":"user",
         "scenario1":False,
         "scenario2":True,
         "scenario3":False,
         "measurement": "getUserActivityTimeline",
         "measurement_args":{"eventTypes":reddit_events},
         "metrics": {"rmse": Metrics.rmse,
                     "nrmse": named_partial(Metrics.rmse,relative=True),
                     "ks_test": Metrics.ks_test,
                     "dtw": Metrics.dtw}

     },

     "user_activity_distribution": {
         "question": '24a',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getUserActivityDistribution",
         "measurement_args":{"eventTypes":reddit_events},
         "metrics": {"rmse": Metrics.rmse,
                     "nrmse": named_partial(Metrics.rmse,relative=True),
                     "r2": Metrics.r2,
                     "js_divergence": named_partial(Metrics.js_divergence, discrete=True)}
     },

     "most_active_users": {
         "question": '24b',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getMostActiveUsers",
         "measurement_args":{"k":1500,"eventTypes":reddit_events},
         "metrics": {"rbo": named_partial(Metrics.rbo_score, p=0.9965)}
     },

     "user_popularity": {
         "question": '25',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getUserPopularity",
         "measurement_args":{"k":1500,"eventTypes":reddit_events,"content_field":"root"},
         "metrics": {"rbo": named_partial(Metrics.rbo_score, p=0.9965)}
     },

     "user_gini_coef": {
         "question": '26a',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getGiniCoef",
         "measurement_args":{"nodeType":"user","eventTypes":reddit_events},
         "metrics": {"absolute_difference": Metrics.absolute_difference,
                     "absolute_percentage_error": Metrics.absolute_percentage_error}
     },

     "user_palma_coef": {
         "question": '26b',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getPalmaCoef",
         "measurement_args":{"nodeType":"user","eventTypes":reddit_events},
         "metrics": {"absolute_difference": Metrics.absolute_difference,
                     "absolute_percentage_error": Metrics.absolute_percentage_error}
     },

}

content_measurement_params = {
    ##Content-centric measurements

     "content_liveliness_distribution": {
         "question": 13,
         "scale": "population",
         "node_type":"content",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getDistributionOfEventsByContent",
         "measurement_args":{"eventTypes":["comment"],"content_field":"root"},
         "metrics": {"js_divergence": named_partial(Metrics.js_divergence, discrete=False)}
     },

      "content_activity_disparity_gini_comment": {
          "question": 14,
          "scale": "population",
          "node_type":"content",
          "scenario1":True,
          "scenario2":True,
          "scenario3":True,
          "filters": {"event": ["comment"]},
          "measurement": "getGiniCoef",
          "measurement_args":{"eventTypes":["comment"]},
          "metrics": {"absolute_difference": Metrics.absolute_difference,
                      "absolute_percentage_error": Metrics.absolute_percentage_error}
      },

      "content_activity_disparity_palma_comment": {
          "question": 14,
          "scale": "population",
          "node_type":"content",
          "scenario1":True,
          "scenario2":True,
          "scenario3":True,
          "measurement": "getPalmaCoef",
          "measurement_args":{"eventTypes":["comment"]},
          "metrics": {"absolute_difference": Metrics.absolute_difference,
                     "absolute_percentage_error": Metrics.absolute_percentage_error}
      },

      "subreddit_user_continue_prop":{
         "question":"30",
         "scale":"node",
         "node_type":"content",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement":"propUserContinue",
         "measurement_args":{"eventTypes":["comment","post"],"content_field":"subreddit"},
         "metrics":{"rmse":Metrics.rmse,
                    "nrmse": named_partial(Metrics.rmse,relative=True),
                    }
         },
     "subreddit_post_to_comment":{
         "question":'31',
         "scale":"node",
         "node_type":"content",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement_args":{"eventTypes":reddit_events,"event1":"post","event2":"comment","content_field":"subreddit"},
         "measurement":"getEventTypeRatioTimeline",
         "metrics":{"rmse":Metrics.rmse,
                    "nrmse": named_partial(Metrics.rmse,relative=True),
                    }
         }
     }

community_measurement_params = {
    #Community-level measurements
    "community_gini":{
        "question":'6',
        "scale":"community",
        "node_type":"content",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"getCommunityGini",
        "measurement_args":{"eventTypes":reddit_events,"community_field":"subreddit","content_field":"root"},
        "metrics":{"absolute_difference": Metrics.absolute_difference,
                   "absolute_percentage_error": Metrics.absolute_percentage_error}
        },

    "community_palma":{
        "question":'6',
        "scale":"community",
        "node_type":"content",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"getCommunityPalma",
        "measurement_args":{"eventTypes":reddit_events,"community_field":"subreddit","content_field":"root"},
        "metrics":{"absolute_difference": Metrics.absolute_difference,
                   "absolute_percentage_error": Metrics.absolute_percentage_error}
        },

    "community_event_proportions":{
        "question":'7',
        "scale":"community",
        "node_type":"content",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"getProportion",
         "measurement_args":{"eventTypes":reddit_events,"community_field":"subreddit"},
        "metrics":{"js_divergence": named_partial(Metrics.js_divergence,discrete=True)}
        },
    "community_contributing_users":{
        "question":"20",
        "scale":"community",
        "node_type":"user",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"contributingUsers",
        "measurement_args":{"eventTypes":reddit_events,"community_field":"subreddit"},
        "metrics":{"absolute_difference":Metrics.absolute_difference,
                   "absolute_percentage_error": Metrics.absolute_percentage_error}
        },
    "community_num_user_actions":{
        "question":"23",
        "scale":"community",
        "node_type":"user",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"getNumUserActions",
        "measurement_args":{"eventTypes":reddit_events,"unit":'D',"community_field":"subreddit"},
        "metrics":{"rmse": named_partial(Metrics.rmse, join="outer"),
                   "nrmse": named_partial(Metrics.rmse,relative=True),
                   "dtw": Metrics.dtw,
                   "js_divergence": named_partial(Metrics.js_divergence,discrete=False)
                   }
        },
    "community_burstiness":{
        "question":"9",
        "scale":"community",
        "node_type":"content",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"burstsInCommunityEvents",
        "measurement_args":{"eventTypes":reddit_events,"community_field":"subreddit"},
        "metrics":{"absolute_difference":Metrics.absolute_difference,
                   "absolute_percentage_error": Metrics.absolute_percentage_error}
        },

    "community_user_burstiness":{
        "question":"",
        "scale":"community",
        "node_type":"user",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"getUserBurstByCommunity",
        "metrics":{'ks_test':Metrics.ks_test}
        }
    }

reddit_scenario1_measurement_params_cyber = {}

reddit_scenario1_measurement_params_cyber.update(user_measurement_params)
reddit_scenario1_measurement_params_cyber.update(content_measurement_params)
reddit_scenario1_measurement_params_cyber.update(community_measurement_params)


partial_func = partial(func, *args, **kwargs)
    update_wrapper(partial_func, func)
    partial_func.varnames = func.__code__.co_varnames
    return partial_func

from functools import partial, update_wrapper
import Metrics
import ContentCentricMeasurements
import UserCentricMeasurements
from BaselineMeasurements import *

import pprint

def named_partial(func, *args, **kwargs):

reddit_events = ["post","comment"]

user_measurement_params = {
    ### User Centric Measurements
     "user_unique_content": {
         'question': '17',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getUserUniqueContent",
         "measurement_args":{"eventTypes":reddit_events,"content_field":"root"},
         "metrics": {
             "js_divergence": named_partial(Metrics.js_divergence, discrete=False),
             "rmse": Metrics.rmse,
             "nrmse": named_partial(Metrics.rmse,relative=True),
             "r2": Metrics.r2}
     },

     "user_activity_timeline": {
         "question": '19',
         "scale": "node",
         "node_type":"user",
         "scenario1":False,
         "scenario2":True,
         "scenario3":False,
         "measurement": "getUserActivityTimeline",
         "measurement_args":{"eventTypes":reddit_events},
         "metrics": {"rmse": Metrics.rmse,
                     "nrmse": named_partial(Metrics.rmse,relative=True),
                     "ks_test": Metrics.ks_test,
                     "dtw": Metrics.dtw}

     },

     "user_activity_distribution": {
         "question": '24a',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getUserActivityDistribution",
         "measurement_args":{"eventTypes":reddit_events},
         "metrics": {"rmse": Metrics.rmse,
                     "nrmse": named_partial(Metrics.rmse,relative=True),
                     "r2": Metrics.r2,
                     "js_divergence": named_partial(Metrics.js_divergence, discrete=True)}
     },

     "most_active_users": {
         "question": '24b',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getMostActiveUsers",
         "measurement_args":{"k":1500,"eventTypes":reddit_events},
         "metrics": {"rbo": named_partial(Metrics.rbo_score, p=0.9965)}
     },

     "user_popularity": {
         "question": '25',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getUserPopularity",
         "measurement_args":{"k":1500,"eventTypes":reddit_events,"content_field":"root"},
         "metrics": {"rbo": named_partial(Metrics.rbo_score, p=0.9965)}
     },

     "user_gini_coef": {
         "question": '26a',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getGiniCoef",
         "measurement_args":{"nodeType":"user","eventTypes":reddit_events},
         "metrics": {"absolute_difference": Metrics.absolute_difference,
                     "absolute_percentage_error": Metrics.absolute_percentage_error}
     },

     "user_palma_coef": {
         "question": '26b',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getPalmaCoef",
         "measurement_args":{"nodeType":"user","eventTypes":reddit_events},
         "metrics": {"absolute_difference": Metrics.absolute_difference,
                     "absolute_percentage_error": Metrics.absolute_percentage_error}
     },

}

content_measurement_params = {
    ##Content-centric measurements

     "content_liveliness_distribution": {
         "question": 13,
         "scale": "population",
         "node_type":"content",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getDistributionOfEventsByContent",
         "measurement_args":{"eventTypes":["comment"],"content_field":"root"},
         "metrics": {"js_divergence": named_partial(Metrics.js_divergence, discrete=False)}
     },

      "content_activity_disparity_gini_comment": {
          "question": 14,
          "scale": "population",
          "node_type":"content",
          "scenario1":True,
          "scenario2":True,
          "scenario3":True,
          "filters": {"event": ["comment"]},
          "measurement": "getGiniCoef",
          "measurement_args":{"eventTypes":["comment"]},
          "metrics": {"absolute_difference": Metrics.absolute_difference,
                      "absolute_percentage_error": Metrics.absolute_percentage_error}
      },

      "content_activity_disparity_palma_comment": {
          "question": 14,
          "scale": "population",
          "node_type":"content",
          "scenario1":True,
          "scenario2":True,
          "scenario3":True,
          "measurement": "getPalmaCoef",
          "measurement_args":{"eventTypes":["comment"]},
          "metrics": {"absolute_difference": Metrics.absolute_difference,
                     "absolute_percentage_error": Metrics.absolute_percentage_error}
      },

      "subreddit_user_continue_prop":{
         "question":"30",
         "scale":"node",
         "node_type":"content",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement":"propUserContinue",
         "measurement_args":{"eventTypes":["comment","post"],"content_field":"subreddit"},
         "metrics":{"rmse":Metrics.rmse,
                    "nrmse": named_partial(Metrics.rmse,relative=True),
                    }
         },
     "subreddit_post_to_comment":{
         "question":'31',
         "scale":"node",
         "node_type":"content",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement_args":{"eventTypes":reddit_events,"event1":"post","event2":"comment","content_field":"subreddit"},
         "measurement":"getEventTypeRatioTimeline",
         "metrics":{"rmse":Metrics.rmse,
                    "nrmse": named_partial(Metrics.rmse,relative=True),
                    }
         }
     }

community_measurement_params = {
    #Community-level measurements
    "community_gini":{
        "question":'6',
        "scale":"community",
        "node_type":"content",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"getCommunityGini",
        "measurement_args":{"eventTypes":reddit_events,"community_field":"subreddit","content_field":"root"},
        "metrics":{"absolute_difference": Metrics.absolute_difference,
                   "absolute_percentage_error": Metrics.absolute_percentage_error}
        },

    "community_palma":{
        "question":'6',
        "scale":"community",
        "node_type":"content",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"getCommunityPalma",
        "measurement_args":{"eventTypes":reddit_events,"community_field":"subreddit","content_field":"root"},
        "metrics":{"absolute_difference": Metrics.absolute_difference,
                   "absolute_percentage_error": Metrics.absolute_percentage_error}
        },

    "community_event_proportions":{
        "question":'7',
        "scale":"community",
        "node_type":"content",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"getProportion",
         "measurement_args":{"eventTypes":reddit_events,"community_field":"subreddit"},
        "metrics":{"js_divergence": named_partial(Metrics.js_divergence,discrete=True)}
        },
    "community_contributing_users":{
        "question":"20",
        "scale":"community",
        "node_type":"user",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"contributingUsers",
        "measurement_args":{"eventTypes":reddit_events,"community_field":"subreddit"},
        "metrics":{"absolute_difference":Metrics.absolute_difference,
                   "absolute_percentage_error": Metrics.absolute_percentage_error}
        },
    "community_num_user_actions":{
        "question":"23",
        "scale":"community",
        "node_type":"user",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"getNumUserActions",
        "measurement_args":{"eventTypes":reddit_events,"unit":'D',"community_field":"subreddit"},
        "metrics":{"rmse": named_partial(Metrics.rmse, join="outer"),
                   "nrmse": named_partial(Metrics.rmse,relative=True),
                   "dtw": Metrics.dtw,
                   "js_divergence": named_partial(Metrics.js_divergence,discrete=False)
                   }
        },
    "community_burstiness":{
        "question":"9",
        "scale":"community",
        "node_type":"content",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"burstsInCommunityEvents",
        "measurement_args":{"eventTypes":reddit_events,"community_field":"subreddit"},
        "metrics":{"absolute_difference":Metrics.absolute_difference,
                   "absolute_percentage_error": Metrics.absolute_percentage_error}
        },

    "community_user_burstiness":{
        "question":"",
        "scale":"community",
        "node_type":"user",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"getUserBurstByCommunity",
        "metrics":{'ks_test':Metrics.ks_test}
        }
    }

reddit_scenario1_measurement_params_cyber = {}

reddit_scenario1_measurement_params_cyber.update(user_measurement_params)
reddit_scenario1_measurement_params_cyber.update(content_measurement_params)
reddit_scenario1_measurement_params_cyber.update(community_measurement_params)


from functools import partial, update_wrapper
import Metrics
import ContentCentricMeasurements
import UserCentricMeasurements
from BaselineMeasurements import *

import pprint

def named_partial(func, *args, **kwargs):
    partial_func = partial(

    update_wrapper(partial_func, func)
    partial_func.varnames = func.__code__.co_varnames
    return partial_func

reddit_events = ["post","comment"]

user_measurement_params = {
    ### User Centric Measurements
     "user_unique_content": {
         'question': '17',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getUserUniqueContent",
         "measurement_args":{"eventTypes":reddit_events,"content_field":"root"},
         "metrics": {
             "js_divergence": named_partial(Metrics.js_divergence, discrete=False),
             "rmse": Metrics.rmse,
             "nrmse": named_partial(Metrics.rmse,relative=True),
             "r2": Metrics.r2}
     },

     "user_activity_timeline": {
         "question": '19',
         "scale": "node",
         "node_type":"user",
         "scenario1":False,
         "scenario2":True,
         "scenario3":False,
         "measurement": "getUserActivityTimeline",
         "measurement_args":{"eventTypes":reddit_events},
         "metrics": {"rmse": Metrics.rmse,
                     "nrmse": named_partial(Metrics.rmse,relative=True),
                     "ks_test": Metrics.ks_test,
                     "dtw": Metrics.dtw}

     },

     "user_activity_distribution": {
         "question": '24a',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getUserActivityDistribution",
         "measurement_args":{"eventTypes":reddit_events},
         "metrics": {"rmse": Metrics.rmse,
                     "nrmse": named_partial(Metrics.rmse,relative=True),
                     "r2": Metrics.r2,
                     "js_divergence": named_partial(Metrics.js_divergence, discrete=True)}
     },

     "most_active_users": {
         "question": '24b',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getMostActiveUsers",
         "measurement_args":{"k":1500,"eventTypes":reddit_events},
         "metrics": {"rbo": named_partial(Metrics.rbo_score, p=0.9965)}
     },

     "user_popularity": {
         "question": '25',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getUserPopularity",
         "measurement_args":{"k":1500,"eventTypes":reddit_events,"content_field":"root"},
         "metrics": {"rbo": named_partial(Metrics.rbo_score, p=0.9965)}
     },

     "user_gini_coef": {
         "question": '26a',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getGiniCoef",
         "measurement_args":{"nodeType":"user","eventTypes":reddit_events},
         "metrics": {"absolute_difference": Metrics.absolute_difference,
                     "absolute_percentage_error": Metrics.absolute_percentage_error}
     },

     "user_palma_coef": {
         "question": '26b',
         "scale": "population",
         "node_type":"user",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getPalmaCoef",
         "measurement_args":{"nodeType":"user","eventTypes":reddit_events},
         "metrics": {"absolute_difference": Metrics.absolute_difference,
                     "absolute_percentage_error": Metrics.absolute_percentage_error}
     },

}

content_measurement_params = {
    ##Content-centric measurements

     "content_liveliness_distribution": {
         "question": 13,
         "scale": "population",
         "node_type":"content",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement": "getDistributionOfEventsByContent",
         "measurement_args":{"eventTypes":["comment"],"content_field":"root"},
         "metrics": {"js_divergence": named_partial(Metrics.js_divergence, discrete=False)}
     },

      "content_activity_disparity_gini_comment": {
          "question": 14,
          "scale": "population",
          "node_type":"content",
          "scenario1":True,
          "scenario2":True,
          "scenario3":True,
          "filters": {"event": ["comment"]},
          "measurement": "getGiniCoef",
          "measurement_args":{"eventTypes":["comment"]},
          "metrics": {"absolute_difference": Metrics.absolute_difference,
                      "absolute_percentage_error": Metrics.absolute_percentage_error}
      },

      "content_activity_disparity_palma_comment": {
          "question": 14,
          "scale": "population",
          "node_type":"content",
          "scenario1":True,
          "scenario2":True,
          "scenario3":True,
          "measurement": "getPalmaCoef",
          "measurement_args":{"eventTypes":["comment"]},
          "metrics": {"absolute_difference": Metrics.absolute_difference,
                     "absolute_percentage_error": Metrics.absolute_percentage_error}
      },

      "subreddit_user_continue_prop":{
         "question":"30",
         "scale":"node",
         "node_type":"content",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement":"propUserContinue",
         "measurement_args":{"eventTypes":["comment","post"],"content_field":"subreddit"},
         "metrics":{"rmse":Metrics.rmse,
                    "nrmse": named_partial(Metrics.rmse,relative=True),
                    }
         },
     "subreddit_post_to_comment":{
         "question":'31',
         "scale":"node",
         "node_type":"content",
         "scenario1":True,
         "scenario2":True,
         "scenario3":True,
         "measurement_args":{"eventTypes":reddit_events,"event1":"post","event2":"comment","content_field":"subreddit"},
         "measurement":"getEventTypeRatioTimeline",
         "metrics":{"rmse":Metrics.rmse,
                    "nrmse": named_partial(Metrics.rmse,relative=True),
                    }
         }
     }

community_measurement_params = {
    #Community-level measurements
    "community_gini":{
        "question":'6',
        "scale":"community",
        "node_type":"content",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"getCommunityGini",
        "measurement_args":{"eventTypes":reddit_events,"community_field":"subreddit","content_field":"root"},
        "metrics":{"absolute_difference": Metrics.absolute_difference,
                   "absolute_percentage_error": Metrics.absolute_percentage_error}
        },

    "community_palma":{
        "question":'6',
        "scale":"community",
        "node_type":"content",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"getCommunityPalma",
        "measurement_args":{"eventTypes":reddit_events,"community_field":"subreddit","content_field":"root"},
        "metrics":{"absolute_difference": Metrics.absolute_difference,
                   "absolute_percentage_error": Metrics.absolute_percentage_error}
        },

    "community_event_proportions":{
        "question":'7',
        "scale":"community",
        "node_type":"content",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"getProportion",
         "measurement_args":{"eventTypes":reddit_events,"community_field":"subreddit"},
        "metrics":{"js_divergence": named_partial(Metrics.js_divergence,discrete=True)}
        },
    "community_contributing_users":{
        "question":"20",
        "scale":"community",
        "node_type":"user",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"contributingUsers",
        "measurement_args":{"eventTypes":reddit_events,"community_field":"subreddit"},
        "metrics":{"absolute_difference":Metrics.absolute_difference,
                   "absolute_percentage_error": Metrics.absolute_percentage_error}
        },
    "community_num_user_actions":{
        "question":"23",
        "scale":"community",
        "node_type":"user",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"getNumUserActions",
        "measurement_args":{"eventTypes":reddit_events,"unit":'D',"community_field":"subreddit"},
        "metrics":{"rmse": named_partial(Metrics.rmse, join="outer"),
                   "nrmse": named_partial(Metrics.rmse,relative=True),
                   "dtw": Metrics.dtw,
                   "js_divergence": named_partial(Metrics.js_divergence,discrete=False)
                   }
        },
    "community_burstiness":{
        "question":"9",
        "scale":"community",
        "node_type":"content",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"burstsInCommunityEvents",
        "measurement_args":{"eventTypes":reddit_events,"community_field":"subreddit"},
        "metrics":{"absolute_difference":Metrics.absolute_difference,
                   "absolute_percentage_error": Metrics.absolute_percentage_error}
        },

    "community_user_burstiness":{
        "question":"",
        "scale":"community",
        "node_type":"user",
        "scenario1":True,
        "scenario2":True,
        "scenario3":True,
        "measurement":"getUserBurstByCommunity",
        "metrics":{'ks_test':Metrics.ks_test}
        }
    }

reddit_scenario1_measurement_params_cyber = {}

reddit_scenario1_measurement_params_cyber.update(user_measurement_params)
reddit_scenario1_measurement_params_cyber.update(content_measurement_params)
reddit_scenario1_measurement_params_cyber.update(community_measurement_params)


import torch
from torch import nn

class LogisticRegressionModel(nn.Module):
    def __init__(self, input_dim: int, output_classes: int):
        super(LogisticRegressionModel, self).__init__()
        self.linear = torch.nn.Linear(input_dim, output_classes)

x = x.float()
        outputs = self.linear(x)
        return outputs


x = x.float()
        outputs = self.linear(x)
        return outputs

import torch
from torch import nn

class LogisticRegressionModel(nn.Module):
    def __init__(self, input_dim: int, output_classes: int):
        super(LogisticRegressionModel, self).__init__()
        self.linear = torch.nn.Linear(input_dim, output_classes)

    def forward(self, x):


import torch
from torch import nn

class LogisticRegressionModel(nn.Module):
    def __init__(self, input_dim: int, output_classes: int):
        super(LogisticRegressionModel, self).__init__()
        self.linear = torch.nn.Linear(input_dim, output_classes)

    def forward(self, x):
        x = x.float()
        outputs = self.linear(x)
        return outpu