from __future__ import unicode_literals
from django.conf.urls import url

from . import views

app_name='watsonstt'

urlpatterns = [
#    url( r'^', views.ngmain,     name='ngmain'),
    url( r'^ngmain/', views.ngmain,     name='ngmain'),

    url( r'^newwordsave/',  views.newwordsave,    name='newwordsave'),
    url( r'^newwordlist/',  views.newwordlist,    name='newwordlist'),
    url( r'^newworddelete/',  views.newworddelete,    name='newworddelete'),

    url( r'^start/', views.start,       name='start'),

# XHR era
    url( r'^xhour1/',  views.xhour1,   name='xhour1'),
    url( r'^getcred/', views.getcred,  name='getcred'),
    url( r'^getcust/', views.getcust,  name='getcust'),
# XHR era
# AJS era
    url( r'^singleword/',       views.singleword,       name='singleword'),
    url( r'^singlewordsave/',   views.singlewordsave,   name='singlewordsave'),
    url( r'^singlewordrender/', views.singlewordrender, name='singlewordrender'),

    url( r'^multiword/',      views.multiword,        name='multiword'),
    url( r'^angularcred/',     views.angularcred,        name='angularcred'),
    url( r'^angularcust/',     views.angularcust,        name='angularcust'),
    url( r'^multiwordsave/',  views.multiwordsave,    name='multiwordsave'),

######
    url( r'^generalquery/', views.generalquery, name='generalquery'),
    url( r'^executequery/', views.executequery, name='executequery'),
######

    url( r'^ang/', views.ang,           name='ang'),

#    url( r'^tempword1/', views.tempword1,                     name='tempword1'),
    url( r'^tempword2/', views.tempword2,                     name='tempword2'),
    url( r'^tempword3/(?P<word_id>[0-9]+)/', views.tempword3, name='tempword3'),
    url( r'^tempword4/(?P<word_id>[0-9]+)/', views.tempword4, name='tempword4'),
    url( r'^tempword5/(?P<sound_id>\d+)/', views.tempword5,   name='tempword5'),
    url( r'^tempword6/(?P<word_id>\d+)/', views.tempword6,    name='tempword6'),

##### credential
    url( r'^step1list/', views.step1list,           name='step1list'),
    url( r'^step1form/', views.step1form,           name='step1form'),

###### customization
    url( r'^step2form/', views.step2form,           name='step2form'),
    url( r'^step2list/', views.step2list,           name='step2list'),

    url( r'^filetest1/', views.filetest1,           name='filetest1'),
    url( r'^filetest2/', views.filetest2,           name='filetest2'),

# AJS era end

######
#    url( r'^step6formword/', views.step6formword,           name='step6formword'),
#    url( r'^step6formsond/', views.step6formsond,           name='step6formsond'),
#    url( r'^step6final/',    views.step6final,              name='step6final'),
######
    url( r'^step9home/', views.step9home,              name='step9home'),
    url( r'^step9formword/', views.step9formword,        name='step9formword'),
    url( r'^step9editword/(?P<word_id>\d+)/', views.step9editword,   name='step9editword'),
    url( r'^step9soundaword/(?P<word_id>\d+)/', views.step9soundaword,   name='step9soundaword'),
    url( r'^step9deletesound/(?P<sound_id>\d+)/', views.step9deletesound,   name='step9deletesound'),
    url( r'^step9deleteword/(?P<word_id>\d+)/',   views.step9deleteword,   name='step9deleteword'),
#    url( r'^step9formsond/', views.step9formsond,        name='step9formsond'),
#    url( r'^step9listsound/', views.step9listsound,         name='step9listsound'),

###### ###### ###### ###### ###### ###### ###### ###### ###### ###### ###### ###### ######
# test
    url( r'^formsettest/', views.formsettest,           name='formsettest'),

    url( r'^dynamictest/', views.dynamictest,                   name='dynamictest'),
    url( r'^api1/', views.api1,                   name='api1'),
    url( r'^api2/', views.api2,                   name='api2'),
# old
#    url( r'^form/', views.get_name,               name='form'),
# temp

#    url( r'^$',     views.HomePageView.as_view(),  name='home'),
]


#This program prints out all my favourtite movies from a list.
#list stores my favourite movies
movies = ["Break fast club", "Ender's Game","Dope","Split","Sing Street"]
#numbering for the movies
no = 0
#Prints the movies in postion format.
print("These are my favourite movies \n")
for (num,movie) in enumerate(movies):
    no += 1
    print(str(no)+"."+movie)


from __future__ import annotations
from typing import Tuple, List, Optional, Callable, Union
import numpy as np
import warnings

import torch
try:
    import torch
    TORCH_EXISTS = True
except ImportError:
    TORCH_EXISTS = False
    warnings.warn('torch is not installed. Install it to take full advantage of its features')
try:
    from tqdm.auto import trange, tqdm
    TQDM_EXISTS = True
except ImportError:
    TQDM_EXISTS = False

physics_equation_T = Callable[[torch.tensor], torch.tensor]
y_func_T = Union[Callable[[np.ndarray],np.ndarray], Callable[[float],float]]

class TensorShapeError(Exception):
    pass

class PINNLayerSizeError(Exception):
    pass

class PINNGridSizeError(Exception):
    pass

# def setdiff1d_torch(t1: torch.tensor, t2: torch.tensor) -> torch.tensor:
#     # https://stackoverflow.com/questions/55110047/finding-non-intersection-of-two-pytorch-tensors
#     # all values in t2 have to be in t1 as well
#     combined = torch.cat((t1, t2))
#     uniques, counts = combined.unique(return_counts=True)
#     difference = uniques[counts == 1]
#     # intersection = uniques[counts > 1]
#     return difference

if TORCH_EXISTS:
    class MLP(torch.nn.Module):
        '''
            Multilayer perceptron (MLP) // Perceptríon Multicapa .

            Esta clase define una red neuronal feedforward con múltiples capas ocultas
            lineales, funciones de activación tangente hiperbólica en  las capas ocultas
            y una salida lineal.

            Args:
                sizes (lista): Lista de enteros que especifica el número de neuronas en
                cada capa. El primer elemento debe coincidir con la dimensión de entrada
                y el último con la dimensión de salida.

            Atributos:
                capas (torch.nn.ModuleList): Lista que contiene las capas lineales del MLP.

            Métodos:
                forward(x): Realiza una pasada hacia adelante a través de la red MLP.

            Ejemplo:
                tamaños = [entrada_dim, oculta1_dim, oculta2_dim, salida_dim]
                mlp = MLP(tamaños)
                tensor_entrada = torch.tensor([...])
                salida = mlp(tensor_entrada)
        '''
        def __init__(self,sizes):
            super().__init__()
            self.layers = torch.nn.ModuleList()
            for i in range(len(sizes)-1):
                self.layers.append(torch.nn.Linear(sizes[i],sizes[i+1]))
        def forward(self,x):
            h = x
            for hidden in self.layers[:-1]:
                h = torch.tanh(hidden(h))
            output = self.layers[-1]
            y = output(h)
            return y

    class PINN:
        def __init__(self, sizes: Tuple[int,...], physics_weight: float=1e-1, learning_rate: float=1e-4, device: Optional[Union[torch.device, str]]=None) -> None:
            self.pinn_sizes = sizes
            self.physics_weight = physics_weight
            self.pinn_learning_rate = learning_rate

            self.ts_training_physics: Optional[torch.tensor] = None

            if isinstance(device, str):
                try:
                    device = torch.device(device)
                except:
                    device = None
            if device is None:
                self.device: torch.device = torch.device("cuda:0" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu")
            else:
                self.device: torch.device = device

            self.pinn = MLP(self.pinn_sizes).to(self.device)
            self.pinn_optimizer = torch.optim.Adam(self.pinn.parameters(), lr=self.pinn_learning_rate)

            self.input_init: Optional[torch.tensor] = None
            self.ys_init: Optional[torch.tensor] = None # ys work as output

            self.input_boundary: Optional[torch.tensor] = None
            self.ys_boundary: Optional[torch.tensor] = None

            self.input_physics: Optional[torch.tensor] = None

            self.physics_equation: physics_equation_T = lambda x: x

        def _numpy2torch(self, arr: np.ndarray, requires_grad: bool=False) -> torch.tensor:
            if self.device.type == 'mps':
                if arr.dtype in (np.float64, np.float80, np.float96, np.float128, np.float256):
                    arr = arr.astype(np.float32)
            return torch.tensor(arr, requires_grad=requires_grad)

        def _get_input_compatible(self, input: np.ndarray) -> np.ndarray:
            if input.shape[-1] == self.pinn_sizes[0]:
                input_reshape = input
            else:
                input_reshape = input.reshape(-1, self.pinn_sizes[0])
                print('Had to reshape input')
            return input_reshape

        def _get_input_compatible_torch(self, input: torch.tensor) -> torch.tensor:
            if input.shape[-1] == self.pinn_sizes[0]:
                input_reshape = input
            else:
                input_reshape = input.view(-1, self.pinn_sizes[0])
                print('Had to reshape input')
            return input_reshape

        def _get_ys_compatible(self, ys: np.ndarray, verbose: bool=True) -> np.ndarray:
            if ys.shape[-1] == self.pinn_sizes[-1]:
                ys_reshape = ys
            else:
                ys_reshape = ys.reshape(-1, self.pinn_sizes[-1])
                if verbose:
                    print('Had to reshape ys')
            return ys_reshape

        def _get_input_ys_compatible(self, input: np.ndarray, ys: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
            input_reshape = self._get_input_compatible(input)
            ys_reshape = self._get_ys_compatible(ys)
            return input_reshape, ys_reshape

        def _check_input_ys_compatible(self, input: np.ndarray, ys: np.ndarray) -> bool:
            input_reshape, ys_reshape = self._get_input_ys_compatible(input, ys)
            return (
                np.sum(input_reshape.shape[:-1]) == np.sum(ys_reshape.shape[:-1])
            )

        def set_physics_equation(self, equation: physics_equation_T) -> None:
            '''
            equation is a function that takes a torch.tensor as input and outputs a torch.tensor
            The input is the currently calculated values by the pinn. The equation function should
            manipulate these values to shape them in to the physical equation that describes the system
            equated to zero. You can use the gradient, dx and dt member methods to calculate derivatives
            '''
            self.physics_equation = equation

        def set_init_condition(self, input: np.ndarray, ys: np.ndarray, requires_grad: bool=False) -> None:
            input_init, ys_init = self._get_input_ys_compatible(input, ys)
            if not self._check_input_ys_compatible(input_init, ys_init):
                raise TensorShapeError('input shape or output shapes are wrong')
            self.input_init = self._numpy2torch(input_init, requires_grad).to(self.device)
            self.ys_init = self._numpy2torch(ys_init).to(self.device)

        def set_init_condition_constant(self, input: np.ndarray, y: float, requires_grad: bool=False) -> None:
            input_init = self._get_input_compatible(input)
            ys = np.empty((*input_init.shape[:-1], self.pinn_sizes[-1])).fill(y)
            self.set_init_condition(input, ys, requires_grad)

        def set_boundary_condition(self, input: np.ndarray, ys: np.ndarray, requires_grad: bool=False) -> None:
            input_boundary, ys_boundary = self._get_input_ys_compatible(input, ys)
            if not self._check_input_ys_compatible(input_boundary, ys_boundary):
                raise TensorShapeError('input shape or output shapes are wrong')
            self.input_boundary = self._numpy2torch(input_boundary, requires_grad).to(self.device)
            self.ys_boundary = self._numpy2torch(ys_boundary).to(self.device)

        def set_boundary_condition_constant(self, input: np.ndarray, y: float, requires_grad: bool=False) -> None:
            input_boundary = self._get_input_compatible(input)
            ys = np.empty((*input_boundary.shape[:-1], self.pinn_sizes[-1])).fill(y)
            self.input_boundary(input, ys, requires_grad)

        def set_physics_condition(self, input: np.ndarray, requires_grad: bool=True) -> None:
            input_physics = self._get_input_compatible(input)
            self.input_physics = self._numpy2torch(input_physics, requires_grad).to(self.device)

        @staticmethod
        def gradient(y: torch.tensor, var: torch.tensor) -> torch.tensor:
            '''
            calculates d(y)/d(var)
            var should be a slice (or the whole tensor) of self.input_physics
            (or self.input_init or self.input_boundary, if they have requires_grade = True)
            (because these values are used as input for the pinn)
            '''
            return torch.autograd.grad(y, var, torch.ones_like(y), create_graph=True)[0]

        # def _partial_derivative(self, y: torch.tensor, var: torch.tensor, axis: Optional[Union[int, torch.tensor]]=None) -> torch.tensor:
        #     '''
        #     Calculates the partial derivative of y with respect to the axis indicated. The shape of the resulting tensor is the same as self.graident
        #     but zeroes out the axes that do not correspond to the axis that was differentiated against
        #     '''
        #     if not y.requires_grad or not var.requires_grad:
        #         raise Exception('Not all tensors require grad. set requires_grad to True when creating them.')
        #     grad = self.gradient(y, var)
        #     if axis is None:
        #         return grad
        #     if isinstance(axis, int):
        #         axis = torch.tensor((axis,), dtype=torch.int)
        #     indices_to_nullify = setdiff1d_torch(torch.arange(var.shape[-1], dtype=torch.int), axis)
        #     return grad[...,indices_to_nullify]

        @staticmethod
        def loss_function(tensor: torch.tensor) -> float:
            return torch.mean(tensor**2) # MSE

        def train_step(self, input: torch.tensor, optimal: torch.tensor) -> None:
            if input.shape[-1] != self.pinn_sizes[0] or optimal.shape[-1] != self.pinn_sizes[-1]:
                raise PINNLayerSizeError('input or optimal are wrong shape')
            self.pinn_optimizer.zero_grad()
            res = self.pinn(input)
            loss = self.loss_function(res - optimal)
            loss.backward()
            self.pinn_optimizer.step()

        def train(self, iterations: int):
            if TQDM_EXISTS:
                iter = trange(iterations)
            else:
                iter = range(iterations)
            for epoch in iter:
                self.pinn_optimizer.zero_grad()

                # initial conditions
                if self.input_init is not None:
                    y_init = self.pinn(self.input_init)
                    loss_init = self.loss_function(y_init-self.ys_init)
                else:
                    loss_init = 0

                # boundary conditions
                if self.input_boundary is not None:
                    y_boundary = self.pinn(self.input_boundary)
                    loss_boundary = self.loss_function(y_boundary - self.ys_boundary)
                else:
                    loss_boundary = 0

                # physics
                if self.input_physics is not None:
                    y_physics = self.pinn(self.input_physics)
                    equation = self.physics_equation(y_physics)
                    loss_physics = self.loss_function(equation)
                else:
                    loss_physics = 0

                loss = loss_init + loss_boundary + self.physics_weight * loss_physics #Se suma el error de la física con el de los datos
                loss.backward()
                self.pinn_optimizer.step()

                if epoch % 100 == 0:
                    with torch.autograd.no_grad():
                        if TQDM_EXISTS:
                            iter.set_description(f'Loss: {loss.data:.4e}, Loss_init: {loss_init:.3e}, Loss_boundary: {loss_boundary:.3e}, Loss_physics: {loss_physics:.3e}')
                            iter.refresh()
                        else:
                            print(epoch,"- Traning Loss:",loss.data)

        def eval(self, input: Union[np.ndarray, torch.tensor], auto_reshape: bool=True, auto_squeeze: bool=True) -> np.ndarray:
            if isinstance(input, np.ndarray):
                input_compatible = self._get_input_compatible(input) if auto_reshape else input
                input_compatible = self._numpy2torch(input_compatible).to(self.device)
            elif input.device != self.device:
                input_compatible = (self._get_input_compatible_torch(input) if auto_reshape else input).to(self.device)
            result = self.pinn(input_compatible)
            if auto_squeeze:
                return result.detach().cpu().numpy().squeeze()
            return result.detach().cpu().numpy()

        def __call__(self, input: Union[np.ndarray, torch.tensor], auto_reshape: bool=True, auto_squeeze: bool=True) -> np.ndarray:
            return self.eval(input, auto_reshape, auto_squeeze)

        def __str__(self) -> str:
            return f'PINN({self.pinn_sizes})'

        def __repr__(self) -> str:
            return self.__str__()

    class PINN_T(PINN):
        def __init__(self, sizes: Tuple[int, ...], physics_weight: float = 0.1, learning_rate: float = 0.0001, device: Optional[Union[torch.device, str]] = None) -> None:
            if sizes[0] != 1:
                raise PINNLayerSizeError(f'Time based PINN should have a input layer of dimension 1, not {sizes[0]}')
            super().__init__(sizes, physics_weight, learning_rate, device)

        def set_init_condition(self, ts: np.ndarray, ys: np.ndarray, requires_grad: bool=False) -> None:
            return super().set_init_condition(ts, ys, requires_grad)

        def set_boundary_condition(self, ts: np.ndarray, ys: np.ndarray, requires_grad: bool=False) -> None:
            return super().set_boundary_condition(ts, ys, requires_grad)

        def set_physics_condition(self, ts: np.ndarray, requires_grad: bool=True) -> None:
            return super().set_physics_condition(ts, requires_grad)

        def dt(self, y_physics: torch.tensor) -> torch.tensor:
            return self.gradient(y_physics, self.input_physics)

        def __str__(self) -> str:
            return f'PINN_T({self.pinn_sizes})'

    class PINN_X(PINN):
        def __init__(self, sizes: Tuple[int, ...], physics_weight: float = 0.1, learning_rate: float = 0.0001, device: Optional[Union[torch.device, str]] = None) -> None:
            super().__init__(sizes, physics_weight, learning_rate, device)

            self.x_grids_init: Optional[Tuple[torch.tensor]] = None # we have to store this to be able to differentiate later
            self.x_grids_boundary: Optional[Tuple[torch.tensor]] = None # we have to store this to be able to differentiate later
            self.x_grids_physics: Optional[Tuple[torch.tensor]] = None # we have to store this to be able to differentiate later

        def _xs_to_x_grid_torch(self, *xss, requires_grad: bool=True) -> Tuple[torch.tensor, Tuple[torch.tensor]]:
            '''
            x_mesh is the mesh which serves as input
            x_grid contains at each index the grid of points relevant to make a partial derivative with respect to the variable of that index
            (that correspondance may be x->0, y->1, z->2, and so on)
            '''
            x_grids = tuple(torch.unsqueeze(x_grid, x_grid.ndim).requires_grad_(requires_grad).to(self.device) for x_grid in torch.meshgrid(*xss, indexing='ij'))
            x_mesh = torch.cat(x_grids, dim=-1)
            return x_mesh, x_grids

        def set_init_condition(self, ys: np.ndarray, *xss: np.ndarray, requires_grad: bool=False) -> None:
            if any(xs.ndim != 1 for xs in xss) or len(xss) != self.pinn_sizes[0] or ys.shape[-1] != self.pinn_sizes[-1] or np.sum(np.sum(xs.shape[:-1]) for xs in xss) != np.sum(ys.shape[:-1]):
                raise PINNGridSizeError('Shapes are not right')
            x_mesh, x_grids = self._xs_to_x_grid_torch(*xss, requires_grad)
            self.x_grids_init = x_grids
            self.input_init = x_mesh

        def set_boundary_condition(self, ys: np.ndarray, *xss: np.ndarray, requires_grad: bool=False) -> None:
            if any(xs.ndim != 1 for xs in xss) or len(xss) != self.pinn_sizes[0] or ys.shape[-1] != self.pinn_sizes[-1] or np.sum(np.sum(xs.shape[:-1]) for xs in xss) != np.sum(ys.shape[:-1]):
                raise PINNGridSizeError('Shapes are not right')
            x_mesh, x_grids = self._xs_to_x_grid_torch(*xss, requires_grad)
            self.x_grids_boundary = x_grids
            self.input_boundary = x_mesh

        def set_physics_condition(self, *xss: np.ndarray, requires_grad: bool=True) -> None:
            if any(xs.ndim != 1 for xs in xss) or len(xss) != self.pinn_sizes[0]:
                raise PINNGridSizeError('Shapes are not right')
            x_mesh, x_grids = self._xs_to_x_grid_torch(*xss, requires_grad)
            self.x_grids_physics = x_grids
            self.input_physics = x_mesh

        def diff(self, y: torch.tensor, var: Tuple[torch.tensor], axis: int) -> torch.tensor:
            '''
            differentiates with respect to the variable of the axis provided, that is in var
            '''
            return self.gradient(y, var[axis])

        def diff_physics(self, y_physics: torch.tensor, axis: int) -> torch.tensor:
            return self.diff(y_physics, self.x_grids_physics, axis)

        def diff_init(self, y_init: torch.tensor, axis: int) -> torch.tensor:
            return self.diff(y_init, self.x_grids_init, axis)

        def diff_boundary(self, y_boundary: torch.tensor, axis: int) -> torch.tensor:
            return self.diff(y_boundary, self.x_grids_boundary, axis)

        def dx(self, y_physics: torch.tensor) -> torch.tensor:
            return self.diff_physics(y_physics, 0)

        def dy(self, y_physics: torch.tensor) -> torch.tensor:
            return self.diff_physics(y_physics, 1)

        def dz(self, y_physics: torch.tensor) -> torch.tensor:
            return self.diff_physics(y_physics, 2)

        def __str__(self) -> str:
            return f'PINN_X({self.pinn_sizes})'

    class PINN_XT(PINN_X):
        def __init__(self, sizes: Tuple[int, ...], physics_weight: float = 0.1, learning_rate: float = 0.0001, device: Optional[Union[torch.device, str]] = None) -> None:
            if sizes[0] < 2:
                raise PINNLayerSizeError(f'XT grid based PINN should have a input layer of dimension 2 or greater, not {sizes[0]}')
            super().__init__(sizes, physics_weight, learning_rate, device)

        def set_init_condition(self, ys: np.ndarray, ts:np.ndarray, *xss: np.ndarray, requires_grad: bool=False) -> None:
            return super().set_init_condition(ys, *xss, ts, requires_grad=requires_grad)

        def set_boundary_condition(self, ys: np.ndarray, ts:np.ndarray, *xss: np.ndarray, requires_grad: bool=False) -> None:
            return super().set_boundary_condition(ys, *xss, ts, requires_grad=requires_grad)

        def set_physics_condition(self, ts:np.ndarray, *xss: np.ndarray, requires_grad: bool=True) -> None:
            return super().set_physics_condition(*xss, ts, requires_grad=requires_grad)

        def dt(self, y_physics: torch.tensor) -> torch.tensor:
            return self.diff_physics(y_physics, self.pinn_sizes[0]-1)

        def __str__(self) -> str:
            return f'PINN_XT({self.pinn_sizes})'

else:
    class NoTorch:
        def __init__(self) -> None:
            raise ModuleNotFoundError("torch was not found!")

    class MLP(NoTorch):
        pass

    class PINN(NoTorch):
        pass

    class PINN_T(NoTorch):
        pass

    class PINN_X(NoTorch):
        pass

    class PINN_XT(NoTorch):
        pass

if __name__ == '__main__':
    import matplotlib.pyplot as plt

    def damped_oscillator_pinn():
        from examples import damped_oscillator_analytical
        pinn = PINN([1] + [16]*4 + [1], learning_rate=1e-2, physics_weight=5e-1, device='cpu')

        t_init = np.array([0], dtype=np.float32)
        y_init = np.array([1], dtype=np.float32)

        t_physics = np.linspace(0, 10, 1000, dtype=np.float32)

        def equation(y):
            # \ddot{x} - mu\dot{x} - kx = 0
            mu = 1
            k = 10
            dxdt = pinn.gradient(y, pinn.input_physics)
            dxxddt = pinn.gradient(dxdt, pinn.input_physics)
            return dxxddt + mu*dxdt + k*y

        pinn.set_physics_equation(equation)
        pinn.set_init_condition(t_init, y_init)
        pinn.set_physics_condition(t_physics)

        pinn.train(5000)

        res = pinn(t_physics)
        plt.plot(t_physics, res)
        plt.plot(t_physics, damped_oscillator_analytical(t_physics, (1, 0), 10, 1))
        plt.show()

    damped_oscillator_pinn()
    def damped_oscillator_pinn_t():
        from examples import damped_oscillator_analytical
        pinn = PINN_T([1] + [16]*4 + [1], learning_rate=1e-2, physics_weight=5e-1, device='cpu')

        t_init = np.array([0], dtype=np.float32)
        y_init = np.array([1], dtype=np.float32)

        t_physics = np.linspace(0, 10, 1000, dtype=np.float32)

        def equation(y):
            # \ddot{x} - mu\dot{x} - kx = 0
            mu = 1
            k = 10
            dxdt = pinn.dt(y)
            dxxddt = pinn.dt(dxdt)
            return dxxddt + mu*dxdt + k*y

        pinn.set_physics_equation(equation)
        pinn.set_init_condition(t_init, y_init)
        pinn.set_physics_condition(t_physics)

        pinn.train(5000)

        res = pinn(t_physics)
        plt.plot(t_physics, res)
        plt.plot(t_physics, damped_oscillator_analytical(t_physics, (1, 0), 10, 1))
        plt.show()

    def pinn_xt():
        Nx = Nt = 100
        tf = 2

        pinn = PINN_XT([2] + ([20]*8) + [1], learning_rate=1e-5, physics_weight=1e-1, device='cpu')

        t_init = np.zeros(Nt)
        x_init = np.linspace(0, 2*np.pi, Nx)
        xt_init = pinn.create_grid(x_init, t_init)

        t_boundary = np.concatenate((np.linspace(0,tf,Nt), np.linspace(0,tf,Nt)), axis=0)
        x_boundary = 2*np.pi*np.concatenate((np.zeros(Nx), np.ones(Nx)), axis=0)
        y_boundary = np.concatenate((np.zeros(Nx), np.zeros(Nt)), axis=0)

        t_physics = np.linspace(0, tf, Nt)
        x_physics = np.linspace(0, 2*np.pi, Nx)

        def equation(ys: torch.tensor) -> torch.tensor:
            dt = pinn.dt(ys)
            dx = pinn.dx(ys)
            return dt + ys * dx

        pinn.set_physics_equation(equation)
        pinn.set_init_condition_func(x_init, t_init, np.sin, axis=0)
        pinn.set_boundary_condition(x_boundary, t_boundary, y_boundary)
        pinn.set_physics_condition(x_physics, t_physics)

        pinn.train(10)

        input = pinn._get_input_compatible(x_physics, t_physics)
        res = pinn(input)
        plt.close('all')
        plt.imshow(res)
        plt.show()

    # from examples import damped_oscillator_analytical

    # X0 = (1.0, 0.0)
    # k, nu = (324, 4)
    # t_data = np.linspace(0, 0.5, 20)
    # t_physics = np.linspace(0, 1, 1000)

    # pinn = PINN([1,32,32,32,1], physics_weight=0.1, learning_rate=1e-4)

    # def equation(ys: torch.tensor) -> torch.tensor:
    #     dt = pinn.dt(ys)
    #     dtt = pinn.dt(dt)
    #     return dtt - nu*dt - ys

    # pinn.set_physics_equation(equation)
    # pinn.set_init_condition_t(t_data, damped_oscillator_analytical(t_data, X0, k, nu))
    # pinn.set_physics_condition_t(t_physics)
    # pinn.train(10_000)

    # res = pinn(t_physics)
    # plt.plot(t_physics, res)
    # plt.plot(t_physics, damped_oscillator_analytical(t_physics, X0, k, nu), ls=':')
    # plt.show()


# Escribir una función llamada superposición() que reciba dos listas y devuelva True si
# tienen al menos un miembro en común y False si lo contrario.

def superposicion(l1, l2):
    for i in l1:
        if i in l2:
            return True
    return False

lista1 = []
lista2 = []
for i in range(3):
    lista1.append(input("Palabra Lista1: "))
for i in range(3):
    lista2.append(input("Palabra Lista2: "))

if superposicion(lista1, lista2):
    print("Tienen al menos un elemento en común")
else:
    print("No tienen elementos en común")


# -*- coding: utf-8 -*-
"""
Created on Wed Nov 18 15:55:41 2020

@author: Ankit Parashar
"""

def near_hundred(n):
  flag = False
  if ((abs(200 - n) <= 10) & (abs(200 - n) >= 0)) | ((abs(100 - n) <= 10) & (abs(100 - n) >= 0)):
    flag = True
  return flag

print(near_hundred(89))


import json

from realms_cli.binary_converter import decimal_to_binary, map_realm, map_crypt

# f = open("data/realms_bit.json", "a")
# output = []
# for index in range(8000):
#     output.append({str(index + 1): map_realm(realms[str(index + 1)])})

# f.write(str(output))

# # with open('scripts/json_data.json', 'w') as outfile:
# #     outfile.write(str(create_output(buildings, 6)))

building_costs = [6, 6, 6, 6, 6, 6, 6, 6, 6]

resource_ids = [1, 4, 6]
resource_values = [10, 10, 10, 10, 10]

buildings = [
    {
        "name": "Fairgrounds",
        "id": 1,
        "costs": [2, 12, 31, 21, 7],
        "ids":[2, 2, 3, 4, 7]
    }
]

# Quickly test Realms metadata
realms = json.load(open('data/realms.json'))
resources = json.load(open('data/resources.json'))
orders = json.load(open('data/orders.json'))
wonders = json.load(open('data/wonders.json'))

print(decimal_to_binary(resource_ids, 8))
print(decimal_to_binary(resource_values, 12))

print(map_realm(realms["1"], resources, wonders, orders))

# Quickly test Crypts metadata
crypts = json.load(open("data/crypts.json"))
environments = json.load(open("data/crypts_environments.json"))
affinities = json.load(open("data/crypts_affinities.json"))

print(map_crypt(crypts["1"], environments, affinities))


class Card:
    def __init__(self, suit, rank, location, revealed):
        self._suit = suit
        self._rank = rank
        self._location = location
        self._revealed = revealed #which side faces up
        self.child = None

    def get_suit(self):
        return self._suit

    def get_rank(self):
        return self._rank

    def get_location(self):
        return self._location
    def set_location(self, location):
        self._location = location

    def get_color_name(self): # determine color based on the suit
        if self._suit in ("hearts", "diamonds"):
            return "red"
        elif self._suit in ("spades", "clubs"):
            return "black"
        else:
            return None

    def is_revealed(self):
        return self._revealed
    def reveal(self, revealed=True):
        self._revealed = revealed
    def hide(self, revealed=False):
        self._revealed = revealed

class TableauCard(Card):
    def __init__(self, card, tableau_index, tableau_depth):
        suit, rank, location, revealed = card.get_suit(), card.get_rank(), card.get_location(), card.is_revealed()
        super().__init__(suit, rank, location, revealed)
        card.child = self
        self.parent = card
        self.x = tableau_index*(25 + 112.5) + 25 + 112.5/2
        self.y = tableau_depth*40 + 2*25 + 3/2*175
        self._type = "tableau"

class DeckCard(Card):
    def __init__(self, card, deck_depth):
        suit, rank, location, revealed = card.get_suit(), card.get_rank(), card.get_location(), card.is_revealed()
        super().__init__(suit, rank, location, revealed)
        card.child = self
        self.parent = card
        self.x = deck_depth*0 + 25 + 112.5/2
        self.y = - deck_depth*1 + 25 + 1/2*175
        self._type = "deck"

class WasteCard(Card):
    def __init__(self, card, waste_depth):
        suit, rank, location, revealed = card.get_suit(), card.get_rank(), card.get_location(), card.is_revealed()
        super().__init__(suit, rank, location, revealed)
        card.child = self
        self.parent = card
        self.x = waste_depth*0 + 2*25 + 3/2 * 112.5
        self.y = - waste_depth*1 + 25 + 1/2*175
        self._type = "waste"

class FoundationCard(Card):
    def __init__(self, card, foundation_index, foundation_depth):
        suit, rank, location, revealed = card.get_suit(), card.get_rank(), card.get_location(), card.is_revealed()
        super().__init__(suit, rank, location, revealed)
        card.child = self
        self.parent = card
        self.x = foundation_index*(25 + 112.5) + 4*25 + 7/2 * 112.5
        self.y = - foundation_depth*1 + 25 + 1/2*175
        self._type = "foundation"

class HoldingCard(Card):
    def __init__(self, card, x, y):
        suit, rank, location, revealed = card.get_suit(), card.get_rank(), card.get_location(), card.is_revealed()
        super().__init__(suit, rank, location, revealed)
        self.parent = card
        self.x = x
        self.y = y
        self._type = "holding"


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/2/14 15:11
# @Author  : Baimohan/PH
# @Site    : https://github.com/BaiMoHan
# @File    : int_transfer_test.py
# @Software: PyCharm
def swap(a, b):
    a, b = b, a
    print('swap:',a,b)

if __name__ == '__main__':
    a = 3
    b = 4
    swap(a, b)
    print('main:', a, b)


from turtle import *
def draw(n,s=2,l=10):
	j="00"
	pu()
	goto(0,0)
	pd()
	seth(0)
	pensize(s)
	for i in n:
		if len(j)==2:
			j=i
		else:
			j+=i
			lt(int(j[0])*10)
			fd(int(j[1])*l)
			if isdown():
				pu()
			else:
				pd()
	pu()
	goto(999,999)


import sys; sys.stdin = open('o.txt', 'r')

def operator(r, idx, op):
    global m, M
    if op == 0:
        r += A[idx]
    elif op == 1:
        r -= A[idx]
    elif op == 2:
        r *= A[idx]
    else:
        if r<0:
            r = (-1)*(((-1)*r)//A[idx])
        else:
            r = r//A[idx]
    if idx == N-1:
        if r<m:
            m = r
        if r>M:
            M = r
        return
    for i in range(len(O)):
        if v[i]: continue
        v[i] =True
        operator(r, idx+1, O[i])
        v[i] = False

N = int(input())
A = list(map(int, input().split()))
o = list(map(int, input().split()))
O = []
for i in range(len(o)):
    if not o[i]:continue
    for j in range(o[i]):
        O.append(i)

m = 0xffffffff
M = m*(-1)
for i in range(len(O)):
    v = [False]*(N-1)
    v[i] = True
    operator(A[0], 1, O[i])
print(M); print(m)


# -*- coding: utf-8 -*-
from biocluster.workflow import Workflow
import pandas as pd
import glob
import os
import json
import time
import re
from biocluster.file import getsize, exists
from biocluster.file import download
from mbio.packages.ref_rna_v2.functions import tryforgood
from mbio.packages.project_demo.run_log.get_run_log import GetRunLog
from biocluster.core.function import filter_error_info, link, CJsonEncoder
import shutil

class DiffexpBatchNewWorkflow(Workflow):
    """
    差异分析
    """
    def __init__(self, wsheet_object):
        self._sheet = wsheet_object
        super(DiffexpBatchNewWorkflow, self).__init__(wsheet_object)
        options = [
            dict(name='exp_type', type='string', default="tpm"),
            dict(name='exp_matrix', type='string'),
            dict(name="group_dict", type="string"),
            dict(name="diff_main_id", type="string"),
            dict(name="count", type="infile", format="lnc_rna.common"),
            dict(name="group", type="string"),
            dict(name="cmp", type="string"),
            dict(name="type", type="string"),
            dict(name="task_id", type="string"),
            dict(name="exp_level", type="string"),
            dict(name="seq_type_path",type="infile",format="lnc_rna.common"),#20190423 fwy新增，rna_seq_type文件路径
            # pvalue 统计判断阈值
            dict(name="pvalue", type="float", default=0.05),
            dict(name="pvalue_padjust", type="string", default="padjust"),
            dict(name="fc", type="float", default=2),
            dict(name="padjust_way", type='string', default="BH"),
            # method: DESeq2, edgeR, DEGseq
            dict(name="method", type="string", default="DESeq2"),
            dict(name="rna_type", type="string"),
            dict(name="filter_method", type="string", default=None),
            dict(name="tpm_filter_threshold", type="float", default="0"),
            # batch by zjx 20200917
            dict(name="is_batch", type="bool", default=False),
            dict(name="has_batch", type="bool"),
            dict(name="batch_matrix", type="infile", format="lnc_rna.common"),
            # noiseq
            dict(name='prob', type='float', default=0.8),
            # to update sg_status
            {"name": "update_info", "type": "string"},
        ]
        self.add_option(options)
        self.set_options(self._sheet.options())
        self.tool = self.add_tool("lnc_rna.diffexp_batch")
        # self.all_exp = self.api.api("lnc_rna.all_exp")
        self._sheet.output = self._sheet.output.replace('interaction_results',
                                                        'interaction_results/02 Diff_Express')
        self.inter_dirs = []

    def send_log(self, data):
        # 中间目录修改
        m = re.match("^([\w\-]+)://(.*)interaction_result.*$", self._sheet.output)
        region = m.group(1)
        inter_dir = m.group(2)
        self.logger.info("更新结果目录")

        if "dirs" in data["data"]["sync_task_log"]:
            for dir_path in self.inter_dirs:
                dir_dict = {
                    "path": os.path.join(inter_dir, "interaction_results", dir_path[0]),
                    "size": "",
                    "format": dir_path[1],
                    "description": dir_path[2],
                    "region": region,
                }
                if len(dir_path) >= 5:
                    dir_dict.update({"code": "D" + dir_path[5]})

                data["data"]["sync_task_log"]["dirs"].append(dir_dict)
        with open(self.work_dir + "/post.changed.json", "w") as f:
            json.dump(data, f, indent=4, cls=CJsonEncoder)
        super(DiffexpBatchNewWorkflow, self).send_log(data)

    def run(self):
        self.tool.on("end", self.run_uniform)
        self.get_run_log()
        self.run_tool()
        super(DiffexpBatchNewWorkflow, self).run()

    def get_run_log(self):
        get_run_log = GetRunLog("lnc_rna", table="sg_diff", main_id=self.option('diff_main_id'),
                                dir_path=self.work_dir)
        self.run_log = get_run_log.run()

    def set_db(self):
        """
        保存结果表到mongo数据库中
        """
        # add result info
        seq_type_path=self.option("seq_type_path").prop['path']
        self.stop_timeout_check()
        self.all_exp = self.api.api("lnc_rna.all_exp")
        # add result info
        self.all_exp.add_diffexp_all(self.uniform.output_dir, self.tool.output_dir,
                                     group_dict=self.option('group_dict'),
                                     main_id=self.option('diff_main_id'),
                                     diff_method=self.option('method'),
                                     create_geneset=False,
                                     pvalue_padjust=self.option('pvalue_padjust'),
                                     seq_type=seq_type_path,
                                     rna_type=self.option("rna_type")
                                     )
        self.paste_annotation()
        self.set_output()
        self.end()

    def end(self):
        if os.path.exists(os.path.join(self.tool.output_dir, os.path.basename(self.run_log))):
            os.remove(os.path.join(self.tool.output_dir, os.path.basename(self.run_log)))
        os.link(self.run_log, os.path.join(self.tool.output_dir, os.path.basename(self.run_log)))

        if os.path.exists(self.output_dir + '/upload'):
            os.remove(self.output_dir + '/upload')
        shutil.copytree(self.tool.output_dir, self.output_dir + '/upload')
        rm_files = glob.glob(self.output_dir + '/upload/*.DE.list')
        rm_files += glob.glob(self.output_dir + '/upload/*.normalize.xls')
        rm_files += glob.glob(self.output_dir + '/upload/*.sizeFactor.xls')
        rm_files += glob.glob(self.output_dir + '/upload/*.normFactor.xls')
        for each in rm_files:
            os.remove(each)

        result_dir = self.add_upload_dir(self.output_dir + '/upload')
        self.inter_dirs = [
            ["02 Diff_Express", "", "表达量差异分析结果目录", 0],
        ]
        result_dir.add_relpath_rules([
            [".", "", "基因表达量差异分析文件", 0, "211063"],
            ['run_parameter.txt', 'txt', '运行参数日志', 0]
        ])
        result_dir.add_regexp_rules([
            [r'.*_diff_summary.xls', 'xls', '表达量差异统计表', 0],
            [r'.*_vs_.*\..*\.xls', 'xls', '表达量差异详情表', 0],
            [r'.*_vs_.*\..*\.annot.xls', 'xls', '表达量差异注释表', 0],
        ])

        super(DiffexpBatchNewWorkflow, self).end()

    def set_output(self):
        diff_total=pd.read_table(os.path.join(self.tool.output_dir,"total_diff_stat.{}.xls".format(self.option("method").lower())),index_col="seq_id")
        diff_files_stat = glob.glob(os.path.join(self.tool.output_dir, '*.{}.xls'.format(self.option("method").lower())))
        df_anno = pd.read_table(diff_files_stat[0], index_col="seq_id")
        df1_genebase = pd.DataFrame(df_anno, columns=["length"])
        df1_geneanno=pd.DataFrame(df_anno,columns=["nr", "go", "KO_id", "KO_name", "paths", "cog", "cog_description", "pfam", "swissprot"])
        dff1 = pd.concat([df1_genebase, diff_total], axis=1)
        dff2 = pd.concat([dff1, df1_geneanno], axis=1)
        dff2.index.set_names("seq_id", inplace=True)
        dff2.to_csv(self.tool.output_dir + "/total_diff_stat.{}.xls".format(self.option("method").lower()), sep="\t")

    def run_tool(self):
        count_file=os.path.join(self.work_dir,"seqs_count.matrix")
        with open(self.option('count').prop['path'], "r") as cf:
            with open(count_file,"w") as ff:
                        firstline = cf.readline()
                        ff.write(firstline)
                        exp_records = cf.readlines()
                        if self.option('type') == "ref":
                            for record in exp_records:
                                line_info = record.strip().split()
                                if line_info[-1] == "false":
                                    if self.option('rna_type') == "lncRNA":
                                        numinfo1 = len(line_info)
                                        if line_info[numinfo1-2] == "lncRNA":
                                            ff.write(record)
                                    elif self.option('rna_type') == "mRNA":
                                        numinfo1 = len(line_info)
                                        if line_info[numinfo1-2] == "mRNA":
                                            ff.write(record)
                                    else:
                                        ff.write(record)
                        else:
                            for record in exp_records:
                                line_info = record.strip().split()
                                if self.option('rna_type') == "lncRNA":
                                    numinfo1 = len(line_info)
                                    if line_info[numinfo1-2] == "lncRNA":
                                        ff.write(record)
                                elif self.option('rna_type') == "mRNA":
                                    numinfo1 = len(line_info)
                                    if line_info[numinfo1-2] == "mRNA":
                                        ff.write(record)
                                else:
                                    ff.write(record)
        ff.close()
        count_matrix = pd.read_table(count_file)
        count_matrix = count_matrix.set_index('seq_id')
        # exp_matrix.drop(exp_matrix.columns[len(exp_matrix.columns) - 1], axis=1, inplace=True)
        count_matrix.drop(['rna_type'], axis=1, inplace=True)
        count_matrix.drop(['is_new'], axis=1, inplace=True)
        count_output = os.path.join(self.work_dir,"count_matrix")
        count_matrix.to_csv(count_output, sep='\t', header=True, index=True)
        print('success to export count matrix')
        opts = dict(
            exp=self.option('exp_matrix'),
            exp_type=self.option('exp_type'),
            count=count_output,
            group=self.option('group'),
            method=self.option('method'),
            cmp=self.option('cmp'),
            tpm_filter_threshold=self.option("tpm_filter_threshold"),
            is_batch=self.option('is_batch'),
            filter_method=self.option("filter_method"),
            no_filter=True,
            analysis='split',
            fc=self.option('fc'),
        )
        if self.option('is_batch') == False:
            if self.option("method").lower() in ["degseq", "edger", "deseq2", 'limma', 'svaseqlimma']:
                opts.update(
                    pvalue=self.option('pvalue'),
                    pvalue_padjust=self.option('pvalue_padjust'),
                    padjust_way=self.option('padjust_way'),
                )
            else:
                opts.update(
                    prob=self.option('prob')
                )
        else:
            if self.option('has_batch') == True:
                opts = dict(
                    exp=self.option('exp_matrix'),
                    exp_type=self.option('exp_type'),
                    count=count_output,
                    group=self.option('group'),
                    method=self.option('method'),
                    cmp=self.option('cmp'),
                    pvalue=self.option('pvalue'),
                    pvalue_padjust=self.option('pvalue_padjust'),
                    padjust_way=self.option('padjust_way'),
                    fc=self.option('fc'),
                    tpm_filter_threshold=self.option("tpm_filter_threshold"),
                    is_batch=self.option('is_batch'),
                    has_batch=self.option('has_batch'),
                    batch_matrix=self.option('batch_matrix'),
                    filter_method=self.option("filter_method"),
                    no_filter=True,
                    analysis='split'
                )
            else:
                opts = dict(
                    exp=self.option('exp_matrix'),
                    exp_type=self.option('exp_type'),
                    count=count_output,
                    group=self.option('group'),
                    method=self.option('method'),
                    cmp=self.option('cmp'),
                    pvalue=self.option('pvalue'),
                    pvalue_padjust=self.option('pvalue_padjust'),
                    padjust_way=self.option('padjust_way'),
                    fc=self.option('fc'),
                    tpm_filter_threshold=self.option("tpm_filter_threshold"),
                    is_batch=self.option('is_batch'),
                    has_batch=self.option('has_batch'),
                    filter_method=self.option("filter_method"),
                    no_filter=True,
                    analysis='split'
                )
        self.tool.set_options(opts)
        self.tool.run()

    def run_uniform(self):
        self.uniform = self.add_tool('denovo_rna_v3.batch.uniform')
        opts = {
            'method': self.option('method'),
            'input_dir': self.tool.output_dir,
        }
        if self.option('method').lower() in ['deseq2', 'degseq', 'edger', 'limma']:
            opts.update({'pvalue_padjust': self.option('pvalue_padjust')})
        self.uniform.set_options(opts)
        self.uniform.on('end', self.set_db)
        self.uniform.run()

    @tryforgood
    def download_s3_file(self, path, to_path):
        """
        判断文件是否在对象存储上
        """
        if not to_path.startswith("/"):
            to_path = os.path.join(self.work_dir, to_path)
        if os.path.exists(to_path):
            os.remove(to_path)
        elif os.path.exists(path):
            to_path = path
        elif exists(path):
            download(path, to_path)
        else:
            self.set_error('file can not find %s', variables=(path), code = '13700502')
        return to_path

    def paste_annotation(self):
        conn = self.all_exp.db['sg_annotation_stat']
        task_id = self.option('task_id')
        try:
            find_result = conn.find_one({"task_id": task_id, "type": "latest", "status": "end"})
        except:
            self.set_error('annotation result file cannot found', code = "13700501")
        else:
            if find_result is None:
                find_result = conn.find_one({"task_id": task_id, "type": "origin"})
        annot = os.path.join(find_result['result_dir'], 'allannot_class/all_annot.xls')
        annot = self.download_s3_file(annot, "annot.xls")
        self.logger.info("annot dir is {}".format(annot))

        exp_level = self.option('exp_level')
        all_annot = pd.read_table(annot, header=0, index_col=0, )
        if exp_level[0].upper() == 'G':
            annot_pd = all_annot[all_annot["is_gene"] == "yes"].drop(columns=['transcript_id', 'is_gene'])
        else:
            annot_pd = all_annot.reset_index().drop(columns=['is_gene']).set_index('transcript_id')
        for each in glob.glob(os.path.join(self.tool.output_dir, '*_vs_*.*.xls')):
            if each.endswith('.annot.xls'):
                continue
            if each.endswith('.normalize.xls'):
                continue
            if each.endswith('.sizeFactor.xls'):
                continue
            if each.endswith('.normFactor.xls'):
                continue
            # diff_pd = pd.read_table(each, header=0, sep='\t', index_col=0)
            # diff_pd = diff_pd.join(annot_pd, how='left')
            # out_diff = each[:-3] + 'annot.xls'
            # diff_pd.to_csv(out_diff, sep='\t', header=True, index=True)
            diff_pd = pd.read_table(each, header=0, sep='\t', index_col="seq_id")
            ctrl, test = os.path.basename(each).split('.{}.xls'.format(self.option("method").lower()))[0].split('_vs_')
            if self.option("method").lower() in ["degseq", "edger", "deseq2", 'limma', 'svaseqlimma']:
                b = pd.DataFrame(diff_pd,columns = ["fc","log2fc", "pvalue", "padjust", "significant", "regulate"])
                c=diff_pd.drop(["fc","log2fc", "pvalue", "padjust", "significant", "regulate"], axis=1)
            else:
                try:
                    b = pd.DataFrame(diff_pd,columns = ['{}_mean'.format(ctrl), '{}_mean'.format(test),"fc","log2fc", "theta", "D", 'prob', "significant", "regulate"])
                    c = diff_pd.drop(['{}_mean'.format(ctrl), '{}_mean'.format(test),"fc","log2fc", "theta", "D", 'prob', "significant", "regulate"], axis=1)
                except:
                    b = pd.DataFrame(diff_pd,columns = ['{}_mean'.format(ctrl), '{}_mean'.format(test),"fc","log2fc", "D", 'prob', "significant", "regulate"])
                    c = diff_pd.drop(['{}_mean'.format(ctrl), '{}_mean'.format(test),"fc","log2fc", "D", 'prob', "significant", "regulate"], axis=1)
            result = pd.concat([b, c], axis=1)
            order = ["nr", "go", "KO_id", "KO_name", "paths", "cog", "cog_description", "pfam", "swissprot"]
            order2 = ["length"]
            pd1 = pd.DataFrame(annot_pd, columns=order)
            pd2 = pd.DataFrame(annot_pd, columns=order2)
            pd3 = pd.concat([pd2, result], axis=1, join_axes=[result.index])
            pd4 = pd.concat([pd3, pd1], axis=1, join_axes=[pd3.index])
            pd4.to_csv(each, sep='\t', header=True, index=True)


import datetime
import os

import openpyxl
from openpyxl.styles import Alignment

from postgre.commands_db import select_user

path = os.getenv("PATH_XLSX")

long_text = Alignment(
    horizontal='left',
    vertical='top',
    wrap_text=True,
    shrink_to_fit=True
)
small_text = Alignment(
    horizontal='left',
    vertical='top',
    wrap_text=True,
    shrink_to_fit=True
)

def create_answer_xlsx(from_user, about_user, txt_about_place, txt_about_user):
    from_user_data = select_user(from_user)[0]
    about_user_data = select_user(about_user)[0]
    print(from_user_data)

    workbook = openpyxl.load_workbook(path)
    sheet = workbook.active
    max_row = sheet.max_row + 1
    date = datetime.date.today()
    print(date.strftime('%d.%m.%y'))
    sheet[f'A{max_row}'].alignment = long_text
    sheet[f'A{max_row}'] = date
    sheet[f'B{max_row}'].alignment = long_text
    sheet[f'B{max_row}'] = f'{from_user_data[1]} - (@{from_user_data[2]})'
    sheet[f'C{max_row}'].alignment = long_text
    sheet[f'C{max_row}'] = f'{about_user_data[1]} - (@{about_user_data[2]})'
    sheet[f'D{max_row}'].alignment = long_text
    sheet[f'D{max_row}'] = txt_about_place
    sheet[f'E{max_row}'].alignment = long_text
    sheet[f'E{max_row}'] = txt_about_user

    workbook.save(path)


import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize
from scipy.integrate import quad
from RealIntegratedLuminosity import L_int_summary_18

plt.rcParams.update({
  "text.usetex": True,
  "font.family": "Helvetica",
  "font.size": 12
})

f=open('Data/a_18_4Par.txt',"r")
lines=f.readlines()
a_18=[]
for x in lines:
    a_18.append(float(x.split(' ')[0]))

f.close()

f=open('Data/b_18_4Par.txt',"r")
lines=f.readlines()
b_18=[]
for x in lines:
    b_18.append(float(x.split(' ')[0]))

f.close()

f=open('Data/c_18_4Par.txt',"r")
lines=f.readlines()
c_18=[]
for x in lines:
    c_18.append(float(x.split(' ')[0]))

f.close()

f=open('Data/d_18_4Par.txt',"r")
lines=f.readlines()
d_18=[]
for x in lines:
    d_18.append(float(x.split(' ')[0]))

f.close()

f=open('Data/ts_18_4Par.txt',"r")
lines=f.readlines()
ts_18=[]
for x in lines:
    ts_18.append(float(x.split(' ')[0]))

f.close()

#model parameters and initial guesses
ts_18=np.array(ts_18)
a_18=np.array(a_18)
b_18=np.array(b_18)
c_18=np.array(c_18)
d_18=np.array(d_18)

#Objective Function
def fun(t1):
    result=np.empty(len(x0))
    for i in range(len(x0)):
        lam=lambda x1: a_18[i]*np.exp(-(b_18[i]*x1))+c_18[i]*np.exp(-d_18[i]*x1)
        result[i]=-quad(lam, 0, t1[i])[0]

    result = np.sum(result)
    return result

#constraint
def cons(t1):
    res = np.sum(t1) - (tot)
    return res

#jacobian of the objective function
def jacb(t1):
    der=-a_18*np.exp(-(b_18*t1))-c_18*np.exp(-d_18*t1)
    #result=np.sum(der)
    return der

#Initial guesses
x0=ts_18

#constraint determination
tot=sum(x0)

#bounds
list=[[1800,86400]]
for li in range(1, len(a_18)):
    list=list+[[1800, 86400]]

bnd=list

#optimization
res = minimize(fun, x0, options={'disp': True, 'maxiter':10000}, constraints={'type':'eq', 'fun': cons, 'jac': lambda x: np.ones(len(x0))}, jac=jacb, method='SLSQP', bounds=bnd) #

#saving optimized times
with open('Data/res_opt_2018.txt', 'w') as f:
        f.write('')
        f.close()
for el in res.x:
    with open('Data/res_opt_2018.txt', 'a') as f:
        f.write(str(el))
        f.write('\n')