from contextlib import contextmanager
from nagini_translation.lib.constants import ERROR_NAME, RESULT_NAME
from nagini_translation.lib.io_context import IOOpenContext
from nagini_translation.lib.obligation_context import ObligationContext
from nagini_translation.lib.program_nodes import (
    PythonMethod,
    PythonType,
    PythonVar,
    PythonVarBase,
)
from nagini_translation.lib.typedefs import Expr
from typing import Dict, List

class Context:
    """
    Contains the current state of the entire translation process.
    """

    def __init__(self) -> None:
        self.current_function = None
        self.current_class = None
        self.current_contract_exception = None
        self.var_aliases = {}
        self.old_aliases = {}
        self.label_aliases = {}
        self.position = []
        self.info = None
        self.module = None
        self.inlined_calls = []
        self.ignore_family_folds = False
        self.added_handlers = []
        self.loop_iterators = {}
        self.io_open_context = IOOpenContext()
        self.obligation_context = ObligationContext()
        self._alias_context_stack = []
        self._current_alias_context = []
        self.bound_type_vars = {}
        self._global_counter = 0
        self.perm_factor = None     # If this is set, all translated permission amounts
                                    # are multiplied by this factor.
        self._old_aliases = {}      # Keys are pretty-printed Python expressions,
                                    # values are Silver expressions they should be
                                    # translated to.
        self.ignore_waitlevel_constraints = False      # If this is set, all encountered
                                                       # WaitLevel() < e constraints will
                                                       # be translated to true.
        # Whether Abstract Read Permissions may be used
        self.arp = False
        # Stores the thread object for which the contracts are currently translated.
        self.current_thread_object = None
        # True iff contracts for a thread start are translated.
        # Used to differentiate fresh token from old token permission.
        self.is_thread_start = False
        self.are_function_constants_used = False
        self.are_threading_constants_used = False
        self.sif = False
        self.allow_statements = False

    def get_fresh_int(self) -> int:
        """
        Returns a fresh integer value, to be used as a globally used counter
        where needed. Current use case is as an argument to constructors for
        various data types, to make the instances unique.
        """
        result = self._global_counter
        self._global_counter += 1
        return result

    @property
    def all_vars(self) -> List[PythonVar]:
        """
        Returns all variables accessible in the current context, i.e., global
        variables as well as local variables and arguments of the current
        function, if any.
        """
        res = []
        if self.current_function:
            res += list(self.current_function.locals.items())
            res += list(self.current_function.args.items())
        if self.module:
            res += list(self.module.global_vars.items())
        return res

    @property
    def actual_function(self) -> PythonMethod:
        """
        Returns the function/method which is actually currently being
        translated, i.e. if a function is currently being inlined, that
        function and not the one it is being inlined into.
        """
        if not self.inlined_calls:
            return self.current_function
        return self.inlined_calls[-1]

    @property
    def result_var(self) -> PythonVar:
        """
        Returns the result var of the current function or the current alias for
        it.
        """
        if RESULT_NAME in self.var_aliases:
            return self.var_aliases[RESULT_NAME]
        if self.current_function.result:
            return self.current_function.result
        return None

    @property
    def error_var(self) -> PythonVar:
        """
        Returns the error var of the current function or the current alias for
        it.
        """
        if ERROR_NAME in self.var_aliases:
            return self.var_aliases[ERROR_NAME]
        return self.current_function.error_var

    def get_label_name(self, name: str) -> str:
        """
        Returns the actual name of the given label in the current context, i.e.,
        looks for aliases.
        """
        if name in self.label_aliases:
            return self.label_aliases[name]
        return name

    @contextmanager
    def additional_aliases(self, aliases: Dict[str, PythonVarBase]) -> None:
        """
        Execute in a context with additional aliases.
        """
        for name, var in aliases.items():
            self.set_alias(name, var, None)
        try:
            yield
        finally:
            for name in aliases:
                self.remove_alias(name)

    @contextmanager
    def aliases_context(self) -> None:
        """
        All aliases added in this context are automatically removed at
        the end of it.
        """
        self._alias_context_stack.append(self._current_alias_context)
        self._current_alias_context = []
        try:
            yield
        finally:
            for name in self._current_alias_context:
                self.remove_alias(name)
            self._current_alias_context = self._alias_context_stack.pop()

    def set_alias(self, name: str, var: PythonVar,
                  replaces: PythonVar=None) -> None:
        """
        Sets an alias for a variable. Makes sure the alt_types of the alias
        variable match those of the variable it replaces. If there already is
        an alias for the given name, memorizes the old one and replaces it.
        """
        if name in self.var_aliases:
            if name not in self.old_aliases:
                self.old_aliases[name] = []
            self.old_aliases[name].append(self.var_aliases[name])
        if replaces:
            if replaces.alt_types:
                assert not var.alt_types
                var.alt_types = replaces.alt_types
        self.var_aliases[name] = var
        self._current_alias_context.append(name)

    def remove_alias(self, name: str) -> None:
        """
        Removes the alias for the given variable. If there was a different alias
        before, that one will be used again afterwards. Otherwise, there will
        no longer be an alias for this name.
        """
        if name in self.old_aliases and self.old_aliases[name]:
            old = self.old_aliases[name].pop()
            self.var_aliases[name] = old
        elif name in self.var_aliases:
            del self.var_aliases[name]

    def set_old_expr_alias(self, key: str, val: Expr) -> None:
        self._old_aliases[key] = val

    def clear_old_expr_aliases(self) -> None:
        self._old_aliases.clear()

    @property
    def old_expr_aliases(self):
        return self._old_aliases

    def get_contents(self, only_top: bool) -> Dict:
        """
        Returns the elements that can be accessed from this container (to be
        used by get_target). If 'only_top' is true, returns only top level
        elements that can be accessed without a receiver.
        """
        return self.var_aliases


import collections

class Solution(object):
    def minWindow(self, s: str, t: str) -> str:
        dict_t = collections.Counter(t)
        left = right = 0
        temp = {}
        ans = (float("inf"), 0, 0)
        required = len(dict_t)
        in_window = 0
        while right < len(s):
            character = s[right]
            temp[character] = temp.get(character, 0) + 1
            if temp[character] == dict_t[character]:
                in_window += 1
            while left <= right and in_window == required:
                character = s[left]
                if right - left + 1 < ans[0]:
                    ans = (right - left + 1, left, right)
                temp[character] -= 1
                if character in dict_t and temp[character] < dict_t[character]:
                    in_window -= 1
                left += 1
            right += 1
        return "" if ans[0] == float("inf") else s[ans[1]: ans[2] + 1]

if __name__ == '__main__':
    print(
        Solution().minWindow("ADOBECODEBANC", "ABC")
    )


from fastapi import APIRouter
from fastapi import Depends, HTTPException, status
from requests import Session
from fastapi_sqlalchemy import db

from core.schemas import model
from core.services import model_crud
from v1.api.base import get_db

router = APIRouter()

#region MODELS STA --------------------------------------------------------
@router.post("/create-model/", status_code=status.HTTP_201_CREATED)
def create_model(name: str, description: str, maker_id: int, type_id: int, model: model.ModelCreateRequest):
    session = db.session
    modelDB = model.Model.ModelCreateRequest(
        name = name,
        description = description,
        maker_id= maker_id,
        type_id= type_id,
        # name = model.name,
        # description = model.description,
        # maker_id= model.maker_id,
        # type_id= model.type_id,
    )

    model_crud.create_Model(session, modelDB)
    session.close()

@router.get("/model/{id}", response_model=model.Model)
def search_Models(id: int, db: Session = Depends(get_db)):
    print(id)
    model = model_crud.get_model(db, id)

    if not id:
        raise HTTPException(status_code=404, detail=f" item with id {id} not found")
    return model

@router.get("/models/", response_model=list[model.Model])
def search_Models(skip: int=0, limit: int=100, db: Session = Depends(get_db)):
    models = model_crud.get_models(db, skip=skip, limit=limit)
    return models

@router.post("/update-model/", status_code=status.HTTP_200_OK)
def update_Models(id: int, name: str, description: str, maker_id: int, type_id: int, model: model.ModelUpdateRequest):

    ModelsDB = model.ModelUpdateRequest(
            id= id,
            name = name,
            maker_id = maker_id,
            type_id = type_id,
            description = description,
        )
    session = db.session
    model_crud.update_Model(session, ModelsDB)
    session.close()

@router.post("/delete-model/{id}", status_code=status.HTTP_200_OK)
def delete_Models(id: int):
    ModelsDB = model.ModelDeleteRequest(
        id= id
    )
    session = db.session
    model_crud.delete_Model(session, ModelsDB)
    session.close()

#region MODELS END --------------------------------------------------------


from django.conf.urls import patterns, include, url
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static

admin.autodiscover()

urlpatterns = patterns(
    '',
    url(r'^profile_edit/$', 'persons.views.profile_edit', name='profile_edit'),
    url(r'^profile/(?P<username>\w+)/$', 'persons.views.profile', name='profile'),
    url(r'^checkin/$', 'checkin.views.checkin', name='checkin'),
    url(r'^diary/$', 'diary.views.diary', name='diary'),
    url(r'^statistics/$', 'statistics.views.statistics', name='statistics'),
    url(r'^notifications/$', 'notifications.views.notifications', name='notifications'),
    url(r'^dice/$', 'dice.views.dice', name='dice'),
    url(r'^$', 'persons.views.home', name='home'),
    url(r'^login/$', 'persons.views.login_user', name='login'),
    url(r'^register/$', 'persons.views.register', name='register'),
    url(r'^register_success/$', 'persons.views.register_success', name='register_success'),
    url(r'^logout/$', 'django.contrib.auth.views.logout', {'template_name': 'logout.html'}, name='logout'),
    url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
    url(r'^admin/', include(admin.site.urls)),
)

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)


from django.db import connections
from rest_framework.filters import OrderingFilter
from core.api.base.views import BaseVectorOnModelApiView, IntersectsBBoxFilter, MODE_DATA, MODE_CONFIG, APIException
from core.api.base.vector import MetadataVectorLayer
from core.utils.structure import mapLayerAttributesFromModel
from core.utils.models import create_geomodel_from_qdjango_layer, get_geometry_column
from core.utils.vector import BaseUserMediaHandler
from core.api.permissions import ProjectPermission
from core.api.filters import DatatablesFilterBackend, SuggestFilterBackend
from .utils.edittype import MAPPING_EDITTYPE_QGISEDITTYPE
from .utils.data import QGIS_LAYER_TYPE_NO_GEOM
from .api.serializers import QGISLayerSerializer, QGISGeoLayerSerializer
from .models import Layer

MODE_WIDGET = 'widget'

class QGISLayerVectorViewMixin(object):

    def set_reprojecting_status(self):
        """
        Check if data have to reproject
        :return:
        """
        # check if data to reproject
        if self.metadata_layer.geometry_type != QGIS_LAYER_TYPE_NO_GEOM:
            self.reproject = not self.layer.project.group.srid.auth_srid == self.layer.srid
        else:
            self.reproject = False

    def set_geo_filter(self):

        # Instance bbox filter
        self.bbox_filter = IntersectsBBoxFilter() if self.metadata_layer.geometry_type != QGIS_LAYER_TYPE_NO_GEOM \
            else None

    def get_layer_by_params(self, params):

        layer_id = params['layer_name']
        project_id = params['project_id']

        # get layer object from qdjango model layer
        return Layer.objects.get(project_id=project_id, qgs_layer_id=layer_id)

    def get_geoserializer_kwargs(self):

        kwargs = {'model': self.metadata_layer.model, 'using': self.database_to_use}
        if hasattr(self, 'layer') and self.layer.exclude_attribute_wms:
            kwargs['exclude'] = eval(self.layer.exclude_attribute_wms)
            if self.metadata_layer.model._meta.pk.name in kwargs['exclude']:
                kwargs['exclude'].remove(self.metadata_layer.model._meta.pk.name)

        return kwargs

    def set_relations(self):

        # get relations on project
        self.relations = {} if not self.layer.project.relations else \
            {r['id']: r for r in eval(self.layer.project.relations)}

        # get relations on layer
        if self.layer.vectorjoins:
            joins = eval(self.layer.vectorjoins)
            for n, join in enumerate(joins):
                if Layer.objects.get(qgs_layer_id=join['joinLayerId'], project=self.layer.project).layer_type \
                        in (('postgres', 'spatialite')):
                    name = '{}_vectorjoin_{}'.format(self.layer.qgs_layer_id, n)
                    self.relations[name] = {
                        'id': name,
                        'name': name,
                        'referencedLayer': self.layer.qgs_layer_id,
                        'referencingLayer': join['joinLayerId'],
                        'fieldRef': {
                            'referencedField': join['targetFieldName'],
                            'referencingField': join['joinFieldName']
                        }
                    }

    def set_metadata_relations(self, request, **kwargs):

        # init relations
        self.set_relations()

        for idr, relation in self.relations.items():

            # check if in relation there is referencedLayer == self layer
            if relation['referencedLayer'] == self.layer.qgs_layer_id:
                # get relation layer object
                relation_layer = Layer.objects.get(qgs_layer_id=relation['referencingLayer'],
                                                   project=self.layer.project)

                geomodel, database_to_use, geometrytype = create_geomodel_from_qdjango_layer(relation_layer)

                if geometrytype and geometrytype != QGIS_LAYER_TYPE_NO_GEOM:
                    serializer = QGISGeoLayerSerializer
                else:
                    serializer = QGISLayerSerializer

                self.metadata_relations[relation['referencingLayer']] = MetadataVectorLayer(
                    geomodel,
                    serializer,
                    geometrytype,
                    relation_layer.origname,
                    idr,
                    using=database_to_use,
                    layer=relation_layer,
                    referencing_field=relation['fieldRef']['referencingField'],
                    referenced_field_is_pk=
                    self.metadata_layer.model._meta.pk.name==relation['fieldRef']['referencedField'],
                    layer_id=relation_layer.pk
                )

    def set_metadata_layer(self, request, **kwargs):

        self.layer = self.get_layer_by_params(kwargs)

        # set layer_name
        self.layer_name = self.layer.origname

        geomodel, self.database_to_use, geometrytype = create_geomodel_from_qdjango_layer(self.layer)

        if geometrytype is None:
            geometrytype = QGIS_LAYER_TYPE_NO_GEOM

        # set bbox_filter_field with geomentry model field
        if geometrytype != QGIS_LAYER_TYPE_NO_GEOM:
            serializer = QGISGeoLayerSerializer
            self.bbox_filter_field = get_geometry_column(geomodel).name
        else:
            serializer = QGISLayerSerializer

        # create model and add to editing_layers
        self.metadata_layer = MetadataVectorLayer(
            geomodel,
            serializer,
            geometrytype,
            self.layer.origname,
            layer_id=self.layer.pk
        )

class LayerVectorView(QGISLayerVectorViewMixin, BaseVectorOnModelApiView):

    permission_classes = (ProjectPermission,)

    filter_backends = (OrderingFilter, DatatablesFilterBackend, SuggestFilterBackend)
    ordering_fields = '__all__'

    # Modes call avilable
    modes_call_available = [
        MODE_CONFIG,
        MODE_DATA,
        MODE_WIDGET
    ]

    mapping_layer_attributes_function = mapLayerAttributesFromModel

    def initial(self, request, *args, **kwargs):

        if 'widget_type' in kwargs:
            self.widget_type = kwargs['widget_type']

        super(LayerVectorView, self).initial(request, *args, **kwargs)

    def get_forms(self):
        """
        Check if edittype is se for layer and build inputtype
        """

        fields = super(LayerVectorView, self).get_forms()

        fields = {
            self.layer_name: {
                'fields': {}
            }
        }

        # add label
        if self.layer:
            fields_layer = self.layer.database_columns_by_name()
            for field, data in fields_layer.items():
                fields[self.layer_name]['fields'][field] = {'label': data['label']}

        # add widgets
        if hasattr(self.layer, 'edittypes') and self.layer.edittypes:

            # reduild edittypes
            edittypes = eval(self.layer.edittypes)
            allow_edittypes = MAPPING_EDITTYPE_QGISEDITTYPE.keys()

            for field, data in edittypes.items():
                if data['widgetv2type'] in allow_edittypes:

                    # instance of QgisEditType
                    qet = MAPPING_EDITTYPE_QGISEDITTYPE[data['widgetv2type']](**data)
                    if field not in fields[self.layer_name]['fields']:
                        fields[self.layer_name]['fields'][field] = qet.input_form
                    else:
                        fields[self.layer_name]['fields'][field].update(qet.input_form)

        return fields

    def response_widget_unique_data(self, request_data):
        """
        Execute a distinc query for unique editing qgis widget
        """
        if 'fields' not in request_data:
            raise APIException('The \'fields\' param not in request data')

        # get fields to get unique value:
        fields = request_data['fields'].split(',')

        if len(fields) == 0:
            raise APIException('The \'fields\' param is empty')

        res = dict()
        for field in fields:

            # check if field is nullable
            nullable = False

            for ofield in self.metadata_layer.model._meta.fields:
                if ofield.column == field and ofield.null and ofield.blank:
                    nullable = True

            if self.layer.layer_type == 'spatialite':

                # query raw
                with connections[self.database_to_use].cursor() as cursor:
                    cursor.execute(
                        'select distinct {0} from {1} {2}'.format(
                            field,
                            self.metadata_layer.model._meta.db_table,
                            '' if nullable else 'where {} is not null'.format(field)
                        ))
                    raws = cursor.fetchall()
                    field_values = [r[0] for r in raws]

            else:

                # get value
                field_values = [getattr(r, field)
                                for r in self.metadata_layer.model.objects.order_by(field).distinct(field)]
            res[field] = field_values

        return res

    def response_widget_mode(self, request):
        """
        Get data for qdjango editing widget
        """
        # check for fields data in GET OR POST
        if request.method == 'POST':
            request_data = request.data
        else:
            request_data = request.query_params

        method = getattr(self, 'response_widget_{}_data'.format(self.widget_type))
        res = method(request_data)

        self.results.update({'data': res})

class UserMediaHandler(BaseUserMediaHandler):
    """
    Class to handle input/output user media file uploaded in editing mode
    """
    pass


"""eluci_data URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path

from .views import file_upload_handler, get_main_df, get_pc_df, get_lpc_df, get_plasmalogen_df, get_retention_rf_df, get_mean_agg_rf_df

urlpatterns = [
    path('upload/',file_upload_handler,name="file_upload_handler"),
    path('get_main_df/',get_main_df,name="get_main_df"),
    path('get_pc_df/',get_pc_df,name="get_pc_df"),
    path('get_lpc_df/',get_lpc_df,name="get_lpc_df"),
    path('get_plasmalogen_df/',get_plasmalogen_df,name="get_plasmalogen_df"),
    path('get_retention_rf_df/',get_retention_rf_df,name="get_retention_rf_df"),
    path('get_mean_agg_rf_df/',get_mean_agg_rf_df,name="get_mean_agg_rf_df"),
]


"""wirecard_python URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from django.urls import path
from main.views import *

urlpatterns = [

    url(r'^$', BasicApi, name='BasicApi'),
    url(r'^ApiPlus/', ApiPlus, name='ApiPlus'),
    url(r'^ProApi/', ProApi, name='ProApi'),
    url(r'^MarketPlaceDeactiveSubPartner/', MarketPlaceDeactiveSubPartner, name='MarketPlaceDeactiveSubPartner'),
    url(r'^SendInformationSmsService/', SendInformationSmsService, name='SendInformationSmsService'),
    url(r'^SelectSubscriber/', SelectSubscriber, name='SelectSubscriber'),
    url(r'^SelectSubscriberDetail/', SelectSubscriberDetail, name='SelectSubscriberDetail'),
    url(r'^MarketPlaceAddSubPartner/', MarketPlaceAddSubPartner, name='MarketPlaceAddSubPartner'),
    url(r'^MarketPlaceUpdateSubPartner/', MarketPlaceUpdateSubPartner, name='MarketPlaceUpdateSubPartner'),
    url(r'^DeactivateSubscriber/', DeactivateSubscriber, name='DeactivateSubscriber'),
    url(r'^MarketPlaceSale3DSec/', MarketPlaceSale3DSec, name='MarketPlaceSale3DSec'),
    url(r'^MarketPlaceMPSale/', MarketPlaceMPSale, name='MarketPlaceMPSale'),
    url(r'^MarketPlaceReleasePayment/', MarketPlaceReleasePayment, name='MarketPlaceReleasePayment'),
    url(r'^CCProxySale/', CCProxySale, name='CCProxySale'),
    url(r'^CCProxySale3D/', CCProxySale3D, name='CCProxySale3D'),
    url(r'^WDTicketSale3DURLProxy/', WDTicketSale3DURLProxy, name='WDTicketSale3DURLProxy'),
    url(r'^WDTicketSaleURLProxy/', WDTicketSaleURLProxy, name='WDTicketSaleURLProxy'),
    url(r'^TransactionQueryByOrderId/', TransactionQueryByOrderId, name='TransactionQueryByOrderId'),
    url(r'^TransactionQueryByMPAY/', TransactionQueryByMPAY, name='TransactionQueryByMPAY'),

    url(r'^success/', success, name='success'),
    url(r'^fail/', fail, name='fail'),

]


from collections import deque

def Resolve(do_print=False):

    with open('d22.txt', 'r') as f:
        content = f.read().split('Player ')[1:]

    player_cards = [[int(c) for c in deck.split('\n')[1:-1] if len(c) > 0] for deck in content]

    def CountScore(p):
        return sum([c * (i+1) for i, c in enumerate(reversed(p))])

    # Part1
    p1, p2 = deque(player_cards[0]), deque(player_cards[1])
    while len(p1) > 0 and len(p2) > 0:
        c1, c2 = p1.popleft(), p2.popleft()
        if c1 > c2:
            p1.append(c1)
            p1.append(c2)
        else:
            p2.append(c2)
            p2.append(c1)

    score1 = CountScore(p1) if len(p1) > 0 else CountScore(p2)

    # Part2
    def Bagarre(p1, p2, n=0):
        games_dict = {}
        while len(p1) > 0 and len(p2) > 0:
            # For a reason, checking only one hand is WAY faster, and yields to same results
            # Maybe, if one hand come back once, it announces the two hands will come back
            # in future draws. So checking one hand saves great amount of time.
            # (2800ms to 249ms)
            # Don't know if it is mathematically correct.
            #h = hash((tuple(p1), tuple(p2)))
            h = hash(tuple(p1))
            if h in games_dict:
                break
            games_dict[h] = True
            c1, c2 = p1.popleft(), p2.popleft()
            p1win = False
            if c1 <= len(p1) and c2 <= len(p2):
                p1win = Bagarre(deque([p1[i] for i in range(c1)]), deque([p2[i] for i in range(c2)]), 1)
            else:
                p1win = c1 > c2
            if p1win:
                p1.append(c1)
                p1.append(c2)
            else:
                p2.append(c2)
                p2.append(c1)
        return len(p1) > 0 if n > 0 else (len(p1) > 0, p1, p2)

    p1win, p1, p2 = Bagarre(deque(player_cards[0]), deque(player_cards[1]))
    score2 = CountScore(p1) if p1win else CountScore(p2)

    if do_print:
        print("Score gaulois 1:", score1)
        print("Score gaulois 2:", score2)

# #############################################################################
if __name__ == '__main__':
    Resolve(True)
    # Results with given input:
    #   1: 34324
    #   2: 33259


import torch
from torch import cos, sin

def get_small_and_large_angle_inds(theta: torch.Tensor, eps: float = 1e-3):
    r"""Returns the indices of small and non-small (large) angles, given
    a tensor of angles, and the threshold below (exclusive) which angles
    are considered 'small'.

    Args:
        theta (torch.Tensor): Angle (magnitude of axis-angle vector).
        eps (float): Threshold (exclusive) below which an angle is
            considered 'small'.
    """

    small_inds = torch.abs(theta) < eps
    large_inds = small_inds == 0

    return small_inds, large_inds

def sin_theta_by_theta(theta: torch.Tensor, eps: float = 1e-3):
    r"""Computes :math:`\frac{sin \theta}{\theta}`.

    Args:
        theta (torch.Tensor): Angle (magnitude of axis-angle vector).
        eps (float): Threshold (exclusive) below which an angle is
            considered 'small'.

    """

    # Tensor to store result.
    result = torch.zeros_like(theta)

    small_inds, large_inds = get_small_and_large_angle_inds(theta, eps)

    # Use Taylor series approximation for small angles
    # (upto powers O(theta**8)).
    theta_sq = theta[small_inds] ** 2
    result[small_inds] = 1 - theta_sq / 6 * (1 - theta_sq / 20 * (1 - theta_sq / 42))

    # For large angles, compute using torch.sin and torch.cos
    result[large_inds] = torch.sin(theta[large_inds]) / theta[large_inds]

    return result

def grad_sin_theta_by_theta(theta: torch.Tensor, eps: float = 1e-3):
    r"""Computes :math:`\frac{\partial sin \theta}{\partial \theta \theta}`.

    Args:
        theta (torch.Tensor): Angle (magnitude of axis-angle vector).
        eps (float): Threshold below which an angle is considered small.

    """

    # Tensor to store result.
    result = torch.zeros_like(theta)

    s, l = get_small_and_large_angle_inds(theta, eps)

    # Use Taylor series approximation for small angles
    # (upto powers O(theta**8)).
    theta_sq = theta ** 2
    result[s] = (
        -theta[s]
        / 3
        * (1 - theta_sq[s] / 10 * (1 - theta_sq[s] / 28 * (1 - theta_sq[s] / 54)))
    )

    # For large angles, compute using torch.sin and torch.cos
    result[l] = cos(theta[l]) / theta[l] - sin(theta[l]) / theta_sq[l]

    return result

def grad_sin_theta_by_theta_div_theta(theta: torch.Tensor, eps: float = 1e-3):
    r"""Computes :math:`\frac{\partial sin \theta}{\partial \theta \theta} \frac{1}{\theta}`.

    Args:
        theta (torch.Tensor): Angle (magnitude of axis-angle vector).
        eps (float): Threshold below which an angle is considered small.

    """

    # Tensor to store result.
    result = torch.zeros_like(theta)

    s, l = get_small_and_large_angle_inds(theta, eps)

    # Use Taylor series approximation for small angles
    # (upto powers O(theta**8)).
    theta_sq = theta ** 2
    result[s] = (
        -1
        / 3
        * (1 - theta_sq[s] / 10 * (1 - theta_sq[s] / 28 * (1 - theta_sq[s] / 54)))
    )

    # For large angles, compute using torch.sin and torch.cos
    result[l] = (cos(theta[l]) / theta[l] - sin(theta[l]) / theta_sq[l]) / theta[l]

    return result

def one_minus_cos_theta_by_theta_sq(theta: torch.Tensor, eps: float = 1e-3):
    r"""Computes :math:`\frac{\theta}{sin \theta}`.

    Args:
        theta (torch.Tensor): Angle (magnitude of axis-angle vector).
        eps (float): Threshold (exclusive) below which an angle is
            considered 'small'.

    """

    # Tensor to store result.
    result = torch.zeros_like(theta)

    s, l = get_small_and_large_angle_inds(theta, eps)

    # Use Taylor series approximation for small angles
    # (upto powers O(theta**8)).
    theta_sq = theta[s] ** 2
    result[s] = (((31 * theta_sq) / 42 + 7) * theta_sq / 60 + 1) * theta_sq / 6 + 1

    # For large angles, compute using torch.sin and torch.cos
    result[l] = theta[l] / torch.sin(theta[l])

    return result

def grad_one_minus_cos_theta_by_theta_sq(theta: torch.Tensor, eps: float = 1e-3):
    r"""Computes :math:`\frac{\partial \theta}{\partial \theta sin \theta}`.

    Args:
        theta (torch.Tensor): Angle (magnitude of axis-angle vector).
        eps (float): Threshold below which an angle is considered small.

    """

    # Tensor to store result.
    result = torch.zeros_like(theta)

    s, l = get_small_and_large_angle_inds(theta, eps)

    # Use Taylor series approximation for small angles
    # (upto powers O(theta**8)).
    theta_sq = theta[s] ** 2
    result[s] = (
        ((((127 * theta_sq) / 30 + 31) * theta_sq / 28 + 7) * theta_sq / 30 + 1)
        * theta[s]
        / 3
    )

    # For large angles, compute using torch.sin and torch.cos
    result[l] = 1 / sin(theta[l]) - (theta[l] * cos(theta[l])) / (
        sin(theta[l]) * sin(theta[l])
    )

    return result

def grad_one_minus_cos_theta_by_theta_sq_div_sin_theta(
    theta: torch.Tensor, eps: float = 1e-3
):
    r"""Computes :math:`\frac{\partial \theta}{\partial \theta sin \theta} \frac{1}{sin \theta}`.

    Args:
        theta (torch.Tensor): Angle (magnitude of axis-angle vector).
        eps (float): Threshold below which an angle is considered small.

    """

    # Tensor to store result.
    result = torch.zeros_like(theta)

    s, l = get_small_and_large_angle_inds(theta, eps)

    # Use Taylor series approximation for small angles
    # (upto powers O(theta**8)).
    theta_sq = theta[s] ** 2
    result[s] = theta_sq * (theta_sq * ((4 * theta_sq) / 675 + 2 / 63) + 2 / 15) + 1 / 3

    # For large angles, compute using torch.sin and torch.cos
    result[l] = (
        1 / sin(theta[l]) - (theta[l] * cos(theta[l])) / (sin(theta[l]) * sin(theta[l]))
    ) / sin(theta[l])

    return result

def one_minus_cos_theta_by_theta_sq(theta: torch.Tensor, eps: float = 1e-3):
    r"""Computes :math:`\frac{1 - cos \theta}{\theta^2}`.

    Args:
        theta (torch.Tensor): Angle (magnitude of axis-angle vector).
        eps (float): Threshold (exclusive) below which an angle is
            considered 'small'.

    """

    # Tensor to store result.
    result = torch.zeros_like(theta)

    s, l = get_small_and_large_angle_inds(theta, eps)

    # Use Taylor series approximation for small angles
    # (upto powers O(theta**8)).
    theta_sq = theta ** 2
    result[s] = (
        1 / 2 * (1 - theta_sq[s] / 12 * (1 - theta_sq[s] / 30 * (1 - theta_sq[s] / 56)))
    )

    # For large angles, compute using torch.sin and torch.cos
    result[l] = (1 - cos(theta[l])) / theta_sq[l]

    return result

def grad_one_minus_cos_theta_by_theta_sq(theta: torch.Tensor, eps: float = 1e-3):
    r"""Computes :math:`\frac{\partial}{\partial \theta}\frac{1 - cos \theta}{\theta^2}`.

    Args:
        theta (torch.Tensor): Angle (magnitude of axis-angle vector).
        eps (float): Threshold (exclusive) below which an angle is
            considered 'small'.

    """

    # Tensor to store result.
    result = torch.zeros_like(theta)

    s, l = get_small_and_large_angle_inds(theta, eps)

    # Use Taylor series approximation for small angles
    # (upto powers O(theta**8)).
    theta_sq = theta ** 2
    result[s] = (
        -theta[s]
        / 12
        * (
            1
            - theta_sq[s] / 5 * (1 / 3 - theta_sq[s] / 56 * (1 / 2 - theta_sq[s] / 135))
        )
    )

    # For large angles, compute using torch.sin and torch.cos
    result[l] = sin(theta[l]) / theta_sq[l] - 2 * (1 - cos(theta[l])) / (
        theta_sq[l] * theta[l]
    )

    return result

def theta_minus_sin_theta_by_theta_cube(theta: torch.Tensor, eps: float = 1e-3):
    r"""Computes :math:`\frac{\theta - sin \theta}{\theta^3}`.

    Args:
        theta (torch.Tensor): Angle (magnitude of axis-angle vector).
        eps (float): Threshold (exclusive) below which an angle is
            considered 'small'.

    """

    # Tensor to store result.
    result = torch.zeros_like(theta)

    s, l = get_small_and_large_angle_inds(theta, eps)

    # Use Taylor series approximation for small angles
    # (upto powers O(theta**8)).
    theta_sq = theta[s] ** 2
    result[s] = 1 / 6 * (1 - theta_sq / 20 * (1 - theta_sq / 42 * (1 - theta_sq / 72)))

    # For large angles, compute using torch.sin and torch.cos
    result[l] = (theta[l] - sin(theta[l])) / (theta[l] ** 3)

    return result

def grad_theta_minus_sin_theta_by_theta_cube(theta: torch.Tensor, eps: float = 1e-3):
    r"""Computes :math:`\frac{\partial}{\partial \theta}\frac{\theta - sin \theta}{\theta^3}`.

    Args:
        theta (torch.Tensor): Angle (magnitude of axis-angle vector).
        eps (float): Threshold (exclusive) below which an angle is
            considered 'small'.

    """

    # Tensor to store result.
    result = torch.zeros_like(theta)

    s, l = get_small_and_large_angle_inds(theta, eps)

    # Use Taylor series approximation for small angles
    # (upto powers O(theta**8)).
    theta_sq = theta[s] ** 2
    result[s] = (
        -theta[s]
        / 60
        * (1 - theta_sq / 21 * (1 - theta_sq / 24 * (1 / 2 - theta_sq / 165)))
    )

    # For large angles, compute using torch.sin and torch.cos
    result[l] = (3 * sin(theta[l]) - theta[l] * (cos(theta[l]) + 2)) / (theta[l] ** 4)

    return result

class SinThetaByTheta_Function(torch.autograd.Function):
    @staticmethod
    def forward(ctx, theta):
        ctx.save_for_backward(theta)
        return sin_theta_by_theta(theta)

    @staticmethod
    def backward(ctx, grad_output):
        (theta,) = ctx.saved_tensors
        grad_theta = None
        if ctx.needs_input_grad[0]:
            grad_theta = grad_output * grad_sin_theta_by_theta(theta).to(
                grad_output.device
            )
        return grad_theta

class SinThetaByTheta(torch.nn.Module):
    def __init__(self):
        super(SinThetaByTheta, self).__init__()

    def forward(self, x):
        return SinThetaByTheta_Function.apply(x)

class ThetaBySinTheta_Function(torch.autograd.Function):
    @staticmethod
    def forward(ctx, theta):
        ctx.save_for_backward(theta)
        return one_minus_cos_theta_by_theta_sq(theta)

    @staticmethod
    def backward(ctx, grad_output):
        (theta,) = ctx.saved_tensors
        grad_theta = None
        if ctx.needs_input_grad[0]:
            grad_theta = grad_output * grad_one_minus_cos_theta_by_theta_sq(theta).to(
                grad_output.device
            )
        return grad_theta

class ThetaBySinTheta(torch.nn.Module):
    def __init__(self):
        super(ThetaBySinTheta, self).__init__()

    def forward(self, x):
        return ThetaBySinTheta_Function.apply(x)

class OneMinusCosThetaByThetaSq_Function(torch.autograd.Function):
    @staticmethod
    def forward(ctx, theta):
        ctx.save_for_backward(theta)
        return one_minus_cos_theta_by_theta_sq(theta)

    @staticmethod
    def backward(ctx, grad_output):
        (theta,) = ctx.saved_tensors
        grad_theta = None
        if ctx.needs_input_grad[0]:
            grad_theta = grad_output * grad_one_minus_cos_theta_by_theta_sq(theta).to(
                grad_output.device
            )
        return grad_theta

class OneMinusCosThetaByThetaSq(torch.nn.Module):
    def __init__(self):
        super(OneMinusCosThetaByThetaSq, self).__init__()

    def forward(self, x):
        return OneMinusCosThetaByThetaSq_Function.apply(x)

class ThetaMinusSinThetaByThetaCube_Function(torch.autograd.Function):
    @staticmethod
    def forward(ctx, theta):
        ctx.save_for_backward(theta)
        return theta_minus_sin_theta_by_theta_cube(theta)

    @staticmethod
    def backward(ctx, grad_output):
        (theta,) = ctx.saved_tensors
        grad_theta = None
        if ctx.needs_input_grad[0]:
            grad_theta = grad_output * grad_theta_minus_sin_theta_by_theta_cube(
                theta
            ).to(grad_output.device)
        return grad_theta

class ThetaMinusSinThetaByThetaCube(torch.nn.Module):
    def __init__(self):
        super(ThetaMinusSinThetaByThetaCube, self).__init__()

    def forward(self, x):
        return ThetaMinusSinThetaByThetaCube_Function.apply(x)

# Initialize the coefficient objects, for reuse
coeff_A = SinThetaByTheta()
coeff_B = OneMinusCosThetaByThetaSq()
coeff_C = ThetaMinusSinThetaByThetaCube()

class SO3:
    def __init__(self):
        pass

    @staticmethod
    def cross_product(x: torch.Tensor, y: torch.Tensor):
        return torch.cross(x.view(-1, 3), y.view(-1, 3), dim=1).view_as(x)

    @staticmethod
    def liebracket(x, y):
        return SO3.cross_product(x, y)

    @staticmethod
    def hat(x):
        # size: [B, 3] -> [B, 3, 3]
        x_ = x.view(-1, 3)
        x1, x2, x3 = x_[:, 0], x_[:, 1], x_[:, 2]
        O = torch.zeros_like(x1)

        X = torch.stack(
            (
                (torch.stack((O, -x3, x2), dim=1)),
                (torch.stack((x3, O, -x1), dim=1)),
                (torch.stack((-x2, x1, O), dim=1)),
            ),
            dim=1,
        )
        return X.view(*(x.size()[0:-1]), 3, 3)

    @staticmethod
    def vee(X):
        # size: [B, 3, 3] -> [B, 3]
        X_ = X.view(-1, 3, 3)
        x1, x2, x3 = X_[:, 2, 1], X_[:, 0, 2], X_[:, 1, 0]
        x = torch.stack((x1, x2, x3), dim=1)
        return x.view(*X.size()[0:-2], 3)

    @staticmethod
    def genvec():
        return torch.eye(3)

    @staticmethod
    def genmat():
        return SO3.hat(genvec())

    @staticmethod
    def Exp(x):
        # Exp map
        omega = x.view(-1, 3)
        theta = omega.norm(p=2, dim=1).view(-1, 1, 1)
        omega_hat = SO3.hat(omega)
        omega_hat_sq = omega_hat.bmm(omega_hat)
        I = torch.eye(3).to(omega.device)
        R = I + coeff_A(theta) * omega_hat + coeff_B(theta) * omega_hat_sq
        return R.view(*(x.size()[0:-1]), 3, 3)

    @staticmethod
    def inverse(g):
        # input: group element [B x 3 x 3]
        # output: group element [B x 3 x 3]
        R = g.view(-1, 3, 3)
        Rt = R.transpose(1, 2)
        return Rt.view_as(g)

    @staticmethod
    def btrace(X):
        # Batch trace: [B, N, N] -> [B]
        n = X.size(-1)
        X_ = X.view(-1, n, n)
        tr = torch.zeros(X_.size(0)).to(X.device)
        for i in range(tr.size(0)):
            m = X_[i, :, :]
            tr[i] = torch.trace(m)
        return tr.view(*(X.size()[0:-2]))

    @staticmethod
    def Log(g):
        # Log map
        # input: group element [B x 3 x 3]
        # output: tangent space element [B x 3 x 3]
        eps = 1e-7
        R = g.view(-1, 3, 3)
        tr = SO3.btrace(R)
        c = (tr - 1) / 2
        t = torch.acos(c)
        sc = coeff_A(t)
        idx0 = torch.abs(sc) <= eps
        idx1 = torch.abs(sc) > eps
        sc = sc.view(-1, 1, 1)

        X = torch.zeros_like(R)
        if idx1.any():
            X[idx1] = (R[idx1] - R[idx1].transpose(1, 2)) / (2 * sc[idx1])

        if idx0.any():
            t2 = t[idx0] ** 2
            A = (R[idx0] + torch.eye(3).type_as(R).unsqueeze(0)) * t2.view(-1, 1, 1) / 2
            aw1 = torch.sqrt(A[:, 0, 0])
            aw2 = torch.sqrt(A[:, 1, 1])
            aw3 = torch.sqrt(A[:, 2, 2])
            sgn_3 = torh.sign(A[:, 0, 2])
            sgn_3[sgn_3 == 0] = 1
            sgn_23 = torch.sign(A[:, 1, 2])
            sgn_23[sgn_23 == 0] = 1
            sgn_2 = sgn_23 * sgn_3
            w1 = aw1
            w2 = aw2 * sgn_2
            w3 = aw3 * sgn_3
            w = torch.stack((w1, w2, w3), dim=-1)
            omega_hat = SO3.hat(w)
            X[idx0] = omega_hat

        x = SO3.vee(X.view_as(g))
        return x

    @staticmethod
    def inv_vecs_Xg_ig(x):
        r""" H = inv(vecs_Xg_ig(x)) """
        t = x.view(-1, 3).norm(p=2, dim=1).view(-1, 1, 1)
        X = SO3.hat(x)
        S = X.bmm(X)
        I = torch.eye(3).to(x)

        s, l = get_small_and_large_angle_inds(t)
        eta = torch.zeros_like(t)
        t2 = t[s] ** 2
        eta[s] = ((t2 / 40 + 1) * t2 / 42 + 1) * t2 / 720 + 1 / 12
        eta[l] = (1 - (t[l] / 2) / torch.tan(t[l] / 2)) / (t[l] ** 2)
        H = I - 1 / 2 * X + eta * S
        return H.view(*(x.size()[0:-1]), 3, 3)

class SO3Exp_Function(torch.autograd.Function):
    @staticmethod
    def forward(ctx, x):
        ctx.save_for_backward(x)
        g = SO3.Exp(x)
        return g

    @staticmethod
    def backward(ctx, grad_output):
        (x,) = ctx.saved_tensors
        g = SO3.Exp(x)
        gen_k = SO3.genmat().to(x.device)

        dg = gen_k.matmul(g.view(-1, 1, 3, 3))
        dg = dg.to(grad_output.device)
        go = grad_output.contiguous().view(-1, 1, 3, 3)
        dd = go * dg
        grad_input = dd.sum(-1).sum(-1)

        return grad_input

class SE3:

    # Each SE3 element is [w, v] -> [rotation, translation]

    def __init__(self):
        pass

    @staticmethod
    def twist_product(x, y):
        x_ = x.view(-1, 6)
        y_ = y.view(-1, 6)

        xw, xv = x_[:, 0:3], x_[:, 3:6]
        yw, yv = y_[:, 0:3], y_[:, 3:6]

        zw = SO3.cross_product(xw, yw)
        zv = SO3.cross_product(xw, yv) + SO3.cross_product(xv, yw)

        z = torch.cat((zw, zv), dim=1)

        return z.view_as(x)

    @staticmethod
    def liebracket(x, y):
        return SE3.twist_product(x, y)

    @staticmethod
    def hat(x):
        # size: [B, 6] -> [B, 4, 4]
        x_ = x.view(-1, 6)
        w1, w2, w3 = x_[:, 0], x_[:, 1], x_[:, 2]
        v1, v2, v3 = x_[:, 3], x_[:, 4], x_[:, 5]
        O = torch.zeros_like(w1)

        X = torch.stack(
            (
                torch.stack((O, -w3, w2, v1), dim=1),
                torch.stack((w2, O, -w1, v2), dim=1),
                torch.stack((-w2, w1, O, v3), dim=1),
                torch.stack((O, O, O, O), dim=1),
            ),
            dim=1,
        )
        return X.view(*(x.size()[0:-1]), 4, 4)

    @staticmethod
    def vee(X):
        # size: [B, 4, 4] -> [B, 6]
        X_ = X.view(-1, 4, 4)
        w1, w2, w3 = X_[:, 2, 1], X_[:, 0, 2], X_[:, 1, 0]
        v1, v2, v3 = X_[:, 0, 3], X_[:, 1, 3], X_[:, 2, 3]
        x = torch.stack((w1, w2, w3, v1, v2, v3), dim=1)
        return x.view(*X.size()[0:-2], 6)

    @staticmethod
    def genvec():
        return torch.eye(6)

    @staticmethod
    def genmat():
        return SE3.hat(SE3.genvec())

    @staticmethod
    def Exp(x):
        x_ = x.view(-1, 6)
        w, v = x_[:, 0:3], x_[:, 3:6]
        t = w.norm(p=2, dim=1).view(-1, 1, 1)
        W = SO3.hat(w)
        S = W.bmm(W)
        I = torch.eye(3).to(w)

        R = I + coeff_A(t) * W + coeff_B(t) * S
        V = I + coeff_B(t) * W + coeff_C(t) * S

        p = V.bmm(v.contiguous().view(-1, 3, 1))
        z = (
            torch.Tensor([0, 0, 0, 1])
            .view(1, 1, 4)
            .repeat(x_.size(0), 1, 1)
            .to(x.device)
        )
        Rp = torch.cat((R, p), dim=2)
        g = torch.cat((Rp, z), dim=1)
        return g.view(*(x.size()[0:-1]), 4, 4)

    @staticmethod
    def inverse(g):
        g_ = g.view(-1, 4, 4)
        R = g_[:, 0:3, 0:3]
        p = g_[:, 0:3, 3]
        Q = R.transpose(1, 2)
        q = -Q.matmul(p.unsqueeze(-1))
        z = (
            torch.Tensor([0, 0, 0, 1])
            .view(1, 1, 4)
            .repeat(g_.size(0), 1, 1)
            .to(g.device)
        )
        Qq = torch.cat((Q, q), dim=2)
        ig = torch.cat((Qq, z), dim=1)
        return ig.view(*(g.size()[0:-2]), 4, 4)

    @staticmethod
    def Log(g):
        g_ = g.view(-1, 4, 4)
        R = g_[:, 0:3, 0:3]
        p = g_[:, 0:3, 3]
        w = SO3.Log(R)
        H = SO3.inv_vecs_Xg_ig(w)
        v = H.bmm(p.contiguous().view(-1, 3, 1)).view(-1, 3)
        x = torch.cat((w, v), dim=1)
        return x.view(*(g.size()[0:-2]), 6)

class SE3Exp_Function(torch.autograd.Function):
    @staticmethod
    def forward(ctx, x):
        ctx.save_for_backward(x)
        return SE3.Exp(x)

    @staticmethod
    def backward(ctx, grad_output):
        (x,) = ctx.saved_tensors
        g = SE3.Exp(x)
        gen_k = SE3.genmat().to(x.device)

        dg = gen_k.matmul(g.view(-1, 1, 4, 4))
        dg = dg.to(grad_output.device)
        go = grad_output.contiguous().view(-1, 1, 4, 4)
        dd = go * dg
        grad_input = dd.sum(-1).sum(-1)

        return grad_input

SO3Exp = SO3Exp_Function.apply
SE3Exp = SE3Exp_Function.apply

if __name__ == "__main__":

    theta1 = torch.randn(2, 6)
    theta2 = 0.1 * torch.randn(2, 6)
    theta3 = 0.01 * torch.randn(2, 6)
    theta4 = 0.001 * torch.randn(2, 6)

    from se3 import exp as lk_exp
    from se3 import log as lk_log

    our_exp = SE3.Exp
    our_log = SE3.Log
    theta = theta4
    print(our_log(our_exp(theta)) - lk_log(lk_exp(theta)))

    # from se3 import exp as lk_exp
    # our_exp = SE3.Exp
    # theta = theta2
    # print(our_exp(theta) - lk_exp(theta))

    # from so3 import exp as lk_exp
    # from so3 import log as lk_log
    # our_exp = SO3.Exp
    # our_log = SO3.Log
    # theta = theta4
    # print(our_log(our_exp(theta)) - lk_log(lk_exp(theta)))

    # from sinc import sinc3_dt as lk
    # our = grad_theta_minus_sin_theta_by_theta_cube
    # # print(theta1)
    # print(our(theta1, 0.01) - lk(theta1))
    # print(our(theta2, 0.01) - lk(theta2))
    # print(our(theta3, 0.01) - lk(theta3))
    # print(our(theta4, 0.01) - lk(theta4))
    # # print((our(theta1) - lk(theta1)).abs() < 1e-4)
    # # print((our(theta2) - lk(theta2)).abs() < 1e-4)
    # # print((our(theta3) - lk(theta3)).abs() < 1e-4)
    # # print((our(theta4) - lk(theta4)).abs() < 1e-4)

    # module = ThetaMinusSinThetaByThetaCube()
    # our = theta_minus_sin_theta_by_theta_cube
    # print(module(theta1))
    # print(our(theta1))

    # from so3 import mat as lk_hat
    # from so3 import vec as lk_vee
    # our_hat = SO3.hat
    # our_vee = SO3.vee
    # print(our_hat(theta1) - lk_hat(theta1))
    # print(our_vee(our_hat(theta1)) - lk_vee(our_hat(theta1)))
    # # print(our(theta1) - lk(theta1))
    # # x = torch.randn(3)
    # # y = torch.randn(3)
    # # print(our(x, y) - lk(x, y))


# Import Libraries

import numpy as np
from scipy import constants

# Constants

d = 400*10**-9
r = 128*10**-9
k = 1/(4*np.pi*constants.epsilon_0)
proton_charge = constants.elementary_charge
electron_charge = -constants.elementary_charge

# Locations

origin = np.array([0,0,0])
Cl_loc = np.array([0,0,0])
Fe_loc = np.array([Cl_loc[0] - d, 0, 0])
A_loc = np.array([Cl_loc[0] - r, 0, 0])
B_loc = np.array([Cl_loc[0] + r, 0, 0])

# E_A magnitude and direction

FeA_r_vec = A_loc - Fe_loc
FeA_r_hat = FeA_r_vec / np.linalg.norm(FeA_r_vec)
E_FeA = k * ((3 * proton_charge)/((d-r)**2)) * FeA_r_hat
ClA_r_vec = A_loc - Cl_loc
ClA_r_hat = ClA_r_vec / np.linalg.norm(ClA_r_vec)
E_ClA = k * (electron_charge)/((r)**2) * ClA_r_hat
E_Anet_vec = E_FeA + E_ClA
E_Anet_mag = np.linalg.norm(E_Anet_vec)

# E_B magnitude and direction

FeB_r_vec = B_loc - Fe_loc
FeB_r_hat = FeB_r_vec / np.linalg.norm(FeB_r_vec)
E_FeB = k * ((3 * proton_charge)/((d+r)**2)) * FeB_r_hat
ClB_r_vec = B_loc - Cl_loc
ClB_r_hat = ClB_r_vec / np.linalg.norm(ClB_r_vec)
E_ClB = k * (electron_charge)/((r)**2) * ClB_r_hat
E_Bnet_vec = E_FeB + E_ClB
E_Bnet_mag = np.linalg.norm(E_Bnet_vec)

# Force of electron at A

F_vec = electron_charge * E_Anet_vec
F_mag = np.linalg.norm(F_vec)

# Print

print("The magnitude at location A is", E_Anet_mag, "N/C")
if E_Anet_vec[0] < 0:
  print("The direction of E_B is to the left")
else:
  print("The direction of E_B is to the right")
print("The magnitude at location B is", E_Bnet_mag, "N/C")
if E_Bnet_vec[0] < 0:
  print("The direction of E_B is to the left")
else:
  print("The direction of E_B is to the right")
print("The magnitude of the force at A is", F_mag, "N")
if F_vec[0] < 0:
  print("The direction of the force is to the left")
else:
  print("The direction of the force is to the right")


import os
import sys
import argparse
import pandas as pd
from scipy import stats

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("--language", default='english', const='all', nargs='?',
                        help="Choose a language", choices=['english', 'latin'])
    parser.add_argument("--results_file", default="results_bert_english/results_english.csv", type=str,
                        help="Path to csv file with results")
    parser.add_argument("--gold_path", default='data/evaluation/en_graded.txt', type=str,
                        help="Path to gold data with annotator scores")
    parser.add_argument("--output_corr_file", default='results_bert_english.csv', type=str,
                        help="Path to output file with correlation score.")
    args = parser.parse_args()

    # language
    lang = args.language
    languages = ['english', 'latin']
    if lang not in languages:
        print("Language not valid, valid choices are: ", ", ".join(languages))
        sys.exit()
    print("Language:", lang.upper())

    results = list()

    df = pd.read_csv(args.results_file, sep='\t').sort_values(by=['word'])
    df_truth = pd.read_csv(args.gold_path, sep='\t', names=['word', 'score']).sort_values(by=['word'])

    baselines = ['cd', 'div']
    clustering = ['ap', 'iapna', 'app']
    measures = ['jsd', 'pdis', 'pdiv']

    for baseline in baselines:
        corr = stats.spearmanr(df[baseline].values, df_truth.score.values)
        score = corr.correlation
        pvalue = corr.pvalue
        print('\n=======', baseline.upper(), '=======')
        print('Corr:', round(score, 3), '\t\t', 'pvalue:', round(pvalue, 3))
        row = {'method': baseline, 'corr': score, 'pvalue':pvalue}
        results.append(row)

    for clus in clustering:
        for measure in measures:
            method = clus+'_'+measure
            corr = stats.spearmanr(df[method].values, df_truth.score.values)
            score = corr.correlation
            pvalue = corr.pvalue
            print('\n=======', method.upper(), '=======')
            print('Corr:', round(score, 3), '\t\t', 'pvalue:', round(pvalue, 3))
            row = {'method': method, 'corr': score, 'pvalue': pvalue}
            results.append(row)

    dir = os.path.dirname(args.output_corr_file)
    if dir:
        os.makedirs(dir, exist_ok=True)
    results = pd.DataFrame(results)
    results.to_csv(args.output_corr_file, sep='\t', index=False)

    print("Done!")


from django.http import JsonResponse, HttpResponse
from django.shortcuts import get_object_or_404
from drf_yasg.utils import swagger_auto_schema
from rest_framework import viewsets, generics
from rest_framework.permissions import IsAuthenticated
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter
from rest_framework.views import APIView
from rest_framework.response import Response

from config import settings
from vehicle.models import Motorcycle, Car, Milage
from vehicle.pagination import MaterialsPagination, MotoPagination
from vehicle.permissions import OwnerOrStuff
from vehicle.serializers import *
from vehicle.tasks import milage_check, send_message_about_like

class MotorcycleViewSet(viewsets.ModelViewSet):
    serializer_class = MotorcycleSerializers
    queryset = Motorcycle.objects.all()
    pagination_class = MotoPagination

class MotoCreateAPIView(generics.CreateAPIView):
    serializer_class = MotorcycleSerializers

class CarRetrieveView(generics.RetrieveAPIView):
    serializer_class = CarSerializers
    queryset = Car.objects.all()

class CarListView(generics.ListAPIView):
    serializer_class = CarSerializers
    queryset = Car.objects.all()
    permission_classes = [IsAuthenticated]
    pagination_class = MaterialsPagination  # пагинация

class Car_ListView(generics.ListAPIView):
    serializer_class = Car_Serializers
    queryset = Car.objects.all()

class CarUpdateAPIView(generics.UpdateAPIView):
    serializer_class = CarSerializers

class CarRetrieveAPIView(generics.RetrieveAPIView):
    serializer_class = CarSerializers
    queryset = Car.objects.all()
    permission_classes = [OwnerOrStuff]

class CarDestroyView(generics.DestroyAPIView):
    queryset = Car.objects.all()

class CarCreateAPIView(generics.CreateAPIView):
    serializer_class = CarCreateSerializers

class MilageCreateAPIView(generics.CreateAPIView):
    serializer_class = MilageSerializer

    def perform_create(self, serializer):
        self.object = serializer.save()
        milage_check.delay(self.object.pk)

class MilageMotoListAPIView(generics.ListAPIView):
    queryset = Milage.objects.filter(moto__isnull=False)
    serializer_class = MotoMilageSerializer

class MotoMilageCreateAPIView(generics.CreateAPIView):
    serializer_class = MotoCreateMilageSerializer

    def perform_create(self, serializer):
        self.object = serializer.save()
        milage_check.delay(self.object.pk)

class CarMilageCreateAPIView(generics.CreateAPIView):
    serializer_class = CarMilageSerializer

"""Реализовать эндпоинт для получения пробегов и добавить фильтрацию:
выводить список только пробегов для машин,
выводить список только пробегов для мотоциклов,
изменять последовательность сортировки по году пробега.
Шаги решения
Установить пакет django-filter.
Описать класс фильтр для фильтрации данных.
Описать атрибуты для контроллера для изменения порядка сортировки.
Вспомогательный материал: https://www.django-rest-framework.org/api-guide/filtering/#api-guide"""

class MilageListAPIView(generics.ListAPIView):

    queryset = Milage.objects.all()
    serializer_class = MilageSerializer
    filter_backends = [DjangoFilterBackend, OrderingFilter]
    filterset_fields = ['car', 'moto']
    ordering_fields = ['year']

class TotalAPIView(APIView):
    """Задача Подключить drf-yasg. Настроить документацию для проекта. Создать эндпоинт на базе APIView для вывода

    общей информации по количеству машин, количеству мотоциклов, а также суммарному пробегу по машинам и мотоциклам.
    Описать для этого эндпоинта документацию вручную."""

    @swagger_auto_schema(responses={200: TotalDataSerializer})
    def get(self, *args, **kwargs):
        cars_milage = Milage.objects.filter(car__isnull=False).values_list('milage', flat=True)
        moto_milage = Milage.objects.filter(moto__isnull=False).values_list('milage', flat=True)
        response = {
            'total_cars': Car.objects.all().count(),
            'total_moto': Motorcycle.objects.all().count(),
            'total_cars_milage': sum(list(cars_milage)),
            'total_moto_milage': sum(list(moto_milage))
        }
        return Response(response)

class SetLikeToCar(APIView):

    def post(self, request):
        user = self.request.user
        car = get_object_or_404(Car, pk=request.data.get("car"))
        if car.likes.filter(id=user.id).exists():
            return Response({"result": f"У {car} уже есть лайк от {user}"})
        send_message_about_like.delay()
        car.likes.add(user)
        return Response({"result": f"Лайк добавлен для {car}, от {user}"})


#!/usr/bin/env python
# coding: utf-8

# In[1]:

import numpy as np
x = np.arange(10, 20)
x

# In[2]:

y = np.array([2, 1, 4, 5, 8, 12, 18, 25, 96, 48])
y

# In[3]:

r = np.corrcoef(x, y)
r

# In[4]:

print(r[0, 1])
print(r[1, 0])

# In[5]:

import scipy.stats

# In[7]:

print(x)
print(y)

# In[8]:

scipy.stats.pearsonr(x, y)

# In[9]:

scipy.stats.spearmanr(x, y)

# In[10]:

scipy.stats.kendalltau(x, y)

# In[15]:

print(scipy.stats.pearsonr(x, y)[0])

# In[12]:

print(scipy.stats.spearmanr(x, y)[0])

# In[13]:

print(scipy.stats.kendalltau(x, y)[0])

# In[16]:

import pandas as pd

x = pd.Series(range(10, 20))
x

# In[17]:

y = pd.Series([2, 1, 4, 5, 8, 12, 18, 25, 96, 48])
y

# In[19]:

print(x)
print(y)

# In[20]:

x.corr(y)

# In[21]:

y.corr(x)

# In[22]:

x.corr(y, method='spearman')

# In[23]:

x.corr(y, method='kendall')

# In[24]:

import numpy as np
import scipy.stats

x = np.arange(10, 20)
y = np.array([2, 1, 4, 5, 8, 12, 18, 25, 96, 48])

# In[25]:

print(x)
print(y)

# In[26]:

result = scipy.stats.linregress(x, y)

# In[27]:

result

# In[28]:

result.slope

# In[29]:

result.intercept

# In[32]:

xy=np.array([[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
[2,  1,  4,  5,  8, 12, 18, 25, 96,  48]])

# In[33]:

scipy.stats.linregress(xy)

# In[34]:

xy.T

# In[35]:

scipy.stats.linregress(xy.T)

# In[36]:

scipy.stats.linregress(np.arange(3), np.array([2, np.nan, 5]))

# In[37]:

r, p = scipy.stats.pearsonr(x, y)

# In[38]:

print(r)
print(p)

# In[39]:

np.corrcoef(x, y)

# In[40]:

np.corrcoef(xy)

# In[41]:

xyz = np.array([[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
                [2, 1, 4, 5, 8, 12, 18, 25, 96, 48],
                [5, 3, 2, 1, 0, -2, -8, -11, -15, -16]])

# In[42]:

np.corrcoef(xyz)

# In[43]:

"""
         x        y        z

x     1.00     0.76    -0.97
y     0.76     1.00    -0.83
z    -0.97    -0.83     1.00
"""

# In[44]:

arr_with_nan = np.array([[0, 1, 2, 3],
                         [2, 4, 1, 8],
                         [2, 5, np.nan, 2]])

# In[45]:

np.corrcoef(arr_with_nan)

# In[46]:

xyz.T

# In[47]:

np.corrcoef(xyz.T, rowvar=False)

# In[50]:

import pandas as pd

# In[49]:

x = pd.Series(range(10, 20))

# In[51]:

y = pd.Series([2, 1, 4, 5, 8, 12, 18, 25, 96, 48])

# In[52]:

z = pd.Series([5, 3, 2, 1, 0, -2, -8, -11, -15, -16])

# In[54]:

xy = pd.DataFrame({'x-values': x, 'y-values': y})

# In[55]:

xyz = pd.DataFrame({'x-values': x, 'y-values': y, 'z-values': z})

# In[57]:

print(x)
print(y)
print(z)
print(xy)
print(xyz)

# In[60]:

x.corr(y)

# In[61]:

xy.corr()

# In[62]:

xyz.corr()

# In[66]:

u, u_with_nan = pd.Series([1, 2, 3]), pd.Series([1, 2, np.nan, 3])
v, w = pd.Series([1, 4, 8]), pd.Series([1, 4, 154, 8])

# In[67]:

u.corr(v)

# In[68]:

u_with_nan.corr(w)

# In[69]:

corr_matrix = xy.corr()

# In[70]:

corr_matrix

# In[71]:

corr_matrix.at['x-values', 'y-values']

# In[72]:

corr_matrix.iat[0, 1]

# In[73]:

xyz.corr()

# In[74]:

xy.corrwith(z)

# In[75]:

# Rank Correlation

# In[76]:

# Scipy

# In[77]:

x = np.arange(10, 20)
y = np.array([2, 1, 4, 5, 8, 12, 18, 25, 96, 48])
z = np.array([5, 3, 2, 1, 0, -2, -8, -11, -15, -16])

# In[78]:

scipy.stats.rankdata(x)

# In[79]:

scipy.stats.rankdata(y)

# In[80]:

scipy.stats.rankdata(z)

# In[81]:

scipy.stats.rankdata([8, 2, 0, 2])

# In[82]:

scipy.stats.rankdata([8, np.nan, 0, 2])

# In[83]:

np.argsort(y) + 1

# In[89]:

result = scipy.stats.spearmanr(x, y)

# In[90]:

result.correlation

# In[91]:

rho, p = scipy.stats.spearmanr(x, y)

# In[93]:

rho

# In[86]:

xy = np.array([[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
               [2, 1, 4, 5, 8, 12, 18, 25, 96, 48]])

# In[94]:

rho, p = scipy.stats.spearmanr(xy, axis=1)

# In[95]:

rho

# In[98]:

xyz = np.array([[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
                [2, 1, 4, 5, 8, 12, 18, 25, 96, 48],
                [5, 3, 2, 1, 0, -2, -8, -11, -15, -16]])

# In[99]:

corr_matrix, p_matrix = scipy.stats.spearmanr(xyz, axis=1)

# In[100]:

corr_matrix

# In[101]:

result = scipy.stats.kendalltau(x, y)

# In[102]:

result.correlation

# In[103]:

tau, p = scipy.stats.kendalltau(x, y)

# In[104]:

tau

# In[105]:

# Pandas

# In[106]:

x, y, z = pd.Series(x), pd.Series(y), pd.Series(z)
xy = pd.DataFrame({'x-values': x, 'y-values': y})
xyz = pd.DataFrame({'x-values': x, 'y-values': y, 'z-values': z})

# In[107]:

x.corr(y, method='spearman')

# In[108]:

xy.corr(method='spearman')

# In[109]:

xyz.corr(method='spearman')

# In[110]:

xy.corrwith(z, method='spearman')

# In[111]:

x.corr(y, method='kendall')

# In[112]:

xy.corr(method='kendall')

# In[118]:

xyz.corr(method='kendall')

# In[119]:

xy.corrwith(z, method='kendall')

# In[120]:

# Visualization of correlation

# In[121]:

import matplotlib.pyplot as plt
plt.style.use('ggplot')

# In[122]:

import numpy as np
import scipy.stats
x = np.arange(10, 20)
y = np.array([2, 1, 4, 5, 8, 12, 18, 25, 96, 48])
z = np.array([5, 3, 2, 1, 0, -2, -8, -11, -15, -16])
xyz = np.array([[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
                [2, 1, 4, 5, 8, 12, 18, 25, 96, 48],
                [5, 3, 2, 1, 0, -2, -8, -11, -15, -16]])

# In[123]:

slope, intercept, r, p, stderr = scipy.stats.linregress(x, y)

# In[124]:

line = f'Regression line: y={intercept:.2f}+{slope:.2f}x, r={r:.2f}'
line

# In[125]:

fig, ax = plt.subplots()
ax.plot(x, y, linewidth=0, marker='s', label='Data points')
ax.plot(x, intercept + slope * x, label=line)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.legend(facecolor='white')
plt.show()

# In[126]:

corr_matrix = np.corrcoef(xyz).round(decimals=2)

# In[127]:

corr_matrix

# In[128]:

fig, ax = plt.subplots()
im = ax.imshow(corr_matrix)
im.set_clim(-1, 1)
ax.grid(False)
ax.xaxis.set(ticks=(0, 1, 2), ticklabels=('x', 'y', 'z'))
ax.yaxis.set(ticks=(0, 1, 2), ticklabels=('x', 'y', 'z'))
ax.set_ylim(2.5, -0.5)
for i in range(3):
    for j in range(3):
        ax.text(j, i, corr_matrix[i, j], ha='center', va='center',
                color='r')
cbar = ax.figure.colorbar(im, ax=ax, format='% .2f')
plt.show()

# In[4]:

fig, ax = plt.subplots()
ax.boxplot((x, y, z),
          vert=False,
          showmeans=True,
          meanline=True,
          labels=('x', 'y', 'z'),
          medianprops={'linewidth': 2, 'color': 'purple'},
          meanprops={'linewidth': 2, 'color': 'red'}
          )

# In[5]:

# Histogram

# In[7]:

hist, bin_edges = np.histogram(a, bins=10)

# In[8]:

hist

# In[9]:

bin_edges

# In[10]:

# pie chart

# In[11]:

x, y, z = 128, 256, 1024

# In[13]:

fig, ax = plt.subplots()
ax.pie((x, y, z), labels=('x', 'y', 'z'), autopct='%.1.1%%')

plt.show()

# In[ ]:


from django.urls import path
from .views import *
from rest_framework_simplejwt import views as jwt_views

urlpatterns = [
    path('create_country',CountryCreateApi.as_view()),
    path('events_list',EventsApi.as_view()),
    path('update_athlete/<int:pk>',AthleteUpdateApi.as_view()),
    path('delete_comment/<int:pk>',CommentDeleteApi.as_view()),
    path('api/token/',
         jwt_views.TokenObtainPairView.as_view(),
         name ='token_obtain_pair'),
    path('api/token/refresh/',
         jwt_views.TokenRefreshView.as_view(),
         name ='token_refresh'),

]


from typing import Text
from nltk.util import pr
from pyspark.context import SparkContext
from pyspark.sql.context import SQLContext
import pyspark.sql.functions as func
import os
import sys
from pyspark.sql import SparkSession
import pyspark
from textblob import TextBlob
import pandas as pd
from textblob.en import polarity

def umwandeln(text):
    daten = None
    pol = None
    sub = None
    try:
        daten = TextBlob(text)
    except:
        print("Fehler bei Textumwandlung: TextBlob")

    try:
        pol = daten.polarity
    except:
        print("Fehler bei Polarity Zuweisung")

    return pol

# environment
os.environ['PYSPARK_PYTHON'] = sys.executable
os.environ['PYSPARK_DRIVER_PYTHON'] = sys.executable

#sc = pyspark.SparkContext
sc = SparkContext.getOrCreate()
spark = SparkSession(sc)

#path
df = pd.read_json("C:/Users/ArtzT/Documents/WordPad Dokumente/Universität/INHALT STUDIENGANG INFORMATIK/6 Semester/SOES/Übung/uebung07/input/sample_2014-06-12-19-51-21.725+0200.json", lines=True)

pol = df["text"].apply(umwandeln)

posCounter = 0
negCounter = 0
for i in range(len(pol)):
    if posCounter >= 10 and negCounter >= 10:
        break
    if pol[i] > 0.9:
        try:
            posCounter += 1
            print("Positiver Text: " + str(df["text"][i]) + "\n" + str(pol[i]))
        except:
            print("Fehler")

    if pol[i] < 0.1:
        try:
            negCounter += 1
            print("Negativer Text: " + str(df["text"][i]) + "\n" + str(pol[i]))

        except:
            print("Fehler")

print("\n")
print("Positive Tweets: " + str(posCounter))
print("Negative Tweets: " + str(negCounter))
print("\n")

"""
df = "\U0001f648"
value = TextBlob(df).polarity
print(value)

gibt uns für den Affen eine 0.0 als Polarity
"""


from data_proc import load_housing_data, split_train_test
from sklearn.model_selection import  train_test_split
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.linear_model import LinearRegression
import numpy as np

rooms_ix, bedrooms_ix, population_ix, households_ix = 3, 4, 5, 6

class CombinedAttributesAdder(BaseEstimator, TransformerMixin):
	def __init__(self, add_bedrooms_per_room=True):
		self.add_bedrooms_per_room = add_bedrooms_per_room

	def fit(self, X, y=None):
		return self

	def transform(self, X, y=None):
		rooms_per_household = X[:, rooms_ix] / X[:, households_ix]
		population_per_household = X[:, population_ix] / X[:, households_ix]

		if self.add_bedrooms_per_room:
			bedrooms_per_room = X[:, bedrooms_ix] / X[:, rooms_ix]
			return np.c_[X, rooms_per_household, population_per_household, bedrooms_per_room]
		else:
			return np.c_[X, rooms_per_household, population_per_household]

class DataFrameSelector(BaseEstimator, TransformerMixin):
	def __init__(self, attribute_names):
		self.attribute_names = attribute_names

	def fit(self, X, y=None):
		return self

	def transform(self, X):
		return X[self.attribute_names].values

housing = load_housing_data()
housing_with_id = housing.reset_index()

train, test = train_test_split(housing_with_id, test_size=0.2, random_state=42)

housing_copy = train.drop('median_house_value', axis=1)
housing_labels = train['median_house_value'].copy()

housing_num = housing_copy.drop('ocean_proximity', axis=1)

num_pipeline = Pipeline([
	('Dataframe_Selector', DataFrameSelector(list(housing_num))),
	('imputer', SimpleImputer(strategy='median')),
	('attribs_adder', CombinedAttributesAdder()),
	('std_scaler', StandardScaler()),
])

cat_pipeline = Pipeline([
	('selector', DataFrameSelector(['ocean_proximity'])),
	('cat_encoder', OneHotEncoder(sparse=False)),
])

full_pipeline = FeatureUnion(transformer_list=[
	('num_pipeline', num_pipeline),
	('cat_pipeline', cat_pipeline),
])

housing_prep = full_pipeline.fit_transform(housing_copy)

lin_reg = LinearRegression()
lin_reg.fit(housing_prep, housing_labels)

print(housing_prep)


# flake8: noqa
from behave import then, when

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

@when(u'I access the URL "{url}"')
def step_impl(context, url):
    context.driver.get(context.base_url + url)

@then(u'The browser URL should be "{url}"')
def step_impl(context, url):
    assert context.driver.current_url.endswith(url)

@when(u'I click in "{link}"')
def step_impl(context, link):
    context.driver.find_element_by_link_text(link).click()

@when(u'I click in "{link}" in modal')
def step_impl(context, link):
    WebDriverWait(context.driver, 10).until( \
        EC.visibility_of_element_located((By.LINK_TEXT, link)) \
    ).click()

@when(u'I click in "{button_id}" button')
def step_impl(context, button_id):
    context.driver.find_element_by_id(button_id).click()

@when(u'I click in "{button_id}" button in modal')
def step_impl(context, button_id):
    WebDriverWait(context.driver, 10).until( \
        EC.visibility_of_element_located((By.ID, button_id)) \
    ).click()

@when(u'I fill "{text}" in "{field_name}" field in modal')
def step_impl(context, text, field_name):
    field = WebDriverWait(context.driver, 10).until( \
        EC.visibility_of_element_located((By.NAME, field_name)) \
    )
    field.clear()
    field.send_keys(text)

@then(u'The field "{field_id}" should have an error')
def step_impl(context, field_id):
    field = context.driver.find_element_by_id(field_id)
    container = field.find_element_by_xpath('..')
    classes = container.get_attribute('class')
    assert 'has-error' in classes

@then(u'I should see "{content}" in "{element_id}"')
def step_impl(context, content, element_id):
    element = context.driver.find_element_by_id(element_id)
    assert (content in element.text) or \
           (content in element.get_attribute("value"))

@then(u'I should see "{content}" in page')
def step_impl(context, content):
    import re
    src = context.driver.page_source
    content_found = re.search(r'%s' % content, src)
    assert content_found is not None


from hub.dataload.nde import NDESourceUploader
from utils.csv_helper import get_source_data
from utils.funding_helper import standardize_funding
from utils.pmid_helper import load_pmid_ctfd
from utils.utils import nde_upload_wrapper

# Example __metadata__ dictionary:
# <SOURCE_NAME> = https://api.data.niaid.nih.gov/v1/metadata
# __metadata__ = {
# "src_meta": {
# 'description': 'A short description of what the source offers, usually found on the source's about page',
# 'name': 'The full source name, Ex. Mendeley Data (not mendeley)',
# 'identifier':'includedInDataCatalog.name value',
# 'schema': 'A dict where the key is the source's metadata variable and the value is our transformation. Ex: {"summary":"description"},
# 'url': 'The source's URL homepage',
# }
# }

class VDJ_Uploader(NDESourceUploader):
    name = "vdj"
    __metadata__ = {
        "src_meta": {
            "sourceInfo": {
                "description": "VDJServer is a free, scalable resource for performing immune repertoire analysis and sharing data. VDJServer Community Data Portal is part of the AIRR Data Commons. Funded by a National Institute of Allergy and Infectious Diseases research grant (#1R01A1097403), the VDJServer project is led by The University of Texas Southwestern (UTSW) Medical Center in collaboration with the J. Craig Venter Institute and Yale University. The Texas Advanced Computing Center (TACC) at The University of Texas at Austin leads the cyberinfrastructure implementation, including the high performance computing (HPC) systems, storage, and software solutions.",
                "identifier": "VDJServer",
                "name": "VDJServer",
                "schema": get_source_data(name),
                "url": "https://vdj-staging.tacc.utexas.edu/community/",
            }
        }
    }

    @nde_upload_wrapper
    def load_data(self, data_folder):
        docs = load_pmid_ctfd(data_folder)
        docs = standardize_funding(docs)
        for doc in docs:
            yield doc


from django.urls import path

from user import views

urlpatterns = [
    path('register/',views.register,name = 'register'),
    path('login/',views.login,name = 'login'),
    path('logout/',views.logout,name = 'logout'),
    # 收货地址
    path('user_site/',views.user_site,name = 'user_site'),
    # 订单详情
    path('user_list/',views.user_list,name = 'user_list'),
    #  用户中心
    path('user_center/',views.user_center,name = 'user_center'),

]


from aiohttp import ClientError, ClientSession, web

from .utils import HN_HTTPS, HOST, PORT, trademarkify_page_html

async def handle(request):
    session = request.app["PERSISTENT_SESSION"]
    try:
        async with session.get(f"{HN_HTTPS}{request.path_qs}") as r:
            if (r.status != 200) or (r.content_type != "text/html"):
                return web.Response(
                    body=await r.read(),
                    content_type=r.headers["content-type"],
                    status=r.status,
                )

            html = await r.text()
            trademarkified_html = trademarkify_page_html(html)
            return web.Response(text=trademarkified_html, content_type="text/html")

    except ClientError as e:
        return web.Response(
            text=f"Request error
{e}",
            content_type="text/html",
            status=500,
        )

async def persistent_session(web_app):
    web_app["PERSISTENT_SESSION"] = session = ClientSession()
    yield
    await session.close()

app = web.Application()
app.add_routes([web.get(r"/{path:.*}", handle)])
app.cleanup_ctx.append(persistent_session)

if __name__ == "__main__":
    web.run_app(app, host=HOST, port=PORT)


import sys
sys.path.append('./')
from utils.utils import calc_AUC
from copy import deepcopy
import matplotlib.pyplot as plt
import numpy as np
import utils.hsdmdl2_nml as hsdmdl2_nml
import utils.hsdmdl1_nml as hsdmdl1_nml
import utils.sdmdl_nml as sdmdl_nml
import tsmdl.aw2s_mdl as aw2s_mdl
import tsmdl.fw2s_mdl as fw2s_mdl
import dmdl.hsdmdl2 as hsdmdl2
import dmdl.hsdmdl1 as hsdmdl1
import dmdl.sdmdl as sdmdl
from functools import partial
import pandas as pd
import optuna
import changefinder
import bocpd
import datetime as dt
from multiprocessing import Pool
import multiprocessing as multi
import boto3
from settings import AWS_S3_BUCKET_NAME
import os

print(os.cpu_count())

df = pd.read_csv('./data/factory_sensor.csv')

X = np.zeros((8, 26450))
for i in range(8):
    # X[i]=np.array(df.iloc[:,i])
    for j in range(1, 26450):
        X[i, j] = df.iloc[j, i] - df.iloc[j - 1, i]
    X[i] -= np.mean(X[i, 0:250])
    X[i] /= np.std(X[i, 0:250])
changepoints = np.where(np.array(df.iloc[:, 8] == 1))[0]
changepoints = [667,  2633,  9662, 13229, 17371, 17831, 20130, 25440]
print("Starting Points of Changes: ", changepoints)

# parameters
tolerance_delay = 500
n_trials = 200
both = True

# BOCPD

def _objective_BOCPD(trial, train, changepoints, tolerance_delay):
    lam = trial.suggest_int('lam', 100, 1000)
    alpha = trial.suggest_uniform('alpha', 1e-8, 10)
    beta = trial.suggest_uniform('beta', 1e-8, 0.01)
    kappa = trial.suggest_uniform('kappa', 1e-8, 0.01)
    mu = 0
    #mu = trial.suggest_uniform('mu', -1, 1)

    h = partial(bocpd.constant_hazard, lam)
    lik = bocpd.StudentT(alpha, beta, kappa, mu)

    retrospective = bocpd.Retrospective(hazard_func=h, likelihood_func=lik)

    scores = np.zeros((8, 26450))

    for i in range(8):
        scores[i] = retrospective.calc_scores(train[i])

    scores = np.nanmax(scores, axis=0)

    AUC = calc_AUC(scores, changepoints, tolerance_delay, both=both)

    return -AUC

# hyperparameter tuning
objective_BOCPD = partial(_objective_BOCPD, train=X,
                          changepoints=changepoints, tolerance_delay=tolerance_delay)
study = optuna.create_study()
study.optimize(objective_BOCPD, n_trials=n_trials, n_jobs=-1)

# calculate scores
opt_lam = study.best_params['lam']
opt_alpha = study.best_params['alpha']
opt_beta = study.best_params['beta']
opt_kappa = study.best_params['kappa']
#opt_mu = study.best_params['mu']
opt_mu = 0

h = partial(bocpd.constant_hazard, opt_lam)
lik = bocpd.StudentT(opt_alpha, opt_beta, opt_kappa, opt_mu)
retrospective = bocpd.Retrospective(hazard_func=h, likelihood_func=lik)

bocpd_scores = np.zeros((8, 26450))

for i in range(8):
    bocpd_scores[i] = retrospective.calc_scores(X[i])

bocpd_scores = np.nanmax(bocpd_scores, axis=0)

# CF

def _objective_CF(trial, train, changepoints, tolerance_delay):
    # hyperparameters
    r = trial.suggest_uniform('r', 0.01, 0.99)
    order = trial.suggest_int('order', 1, 20)
    smooth = trial.suggest_int('smooth', 3, 20)

    retrospective = changefinder.Retrospective(r=r, order=order, smooth=smooth)

    scores = np.zeros((8, 26450))

    for i in range(8):
        scores[i] = retrospective.calc_scores(train[i])

    scores = np.nanmax(scores, axis=0)

    AUC = calc_AUC(
        scores, changepoints, tolerance_delay, both=both)
    return -AUC

# hyperparameter tuning
objective_CF = partial(_objective_CF, train=X,
                       changepoints=changepoints, tolerance_delay=tolerance_delay)
study = optuna.create_study()
study.optimize(objective_CF, n_trials=n_trials, n_jobs=-1)
opt_r = study.best_params['r']
opt_order = study.best_params['order']
opt_smooth = study.best_params['smooth']

retrospective = changefinder.Retrospective(
    r=opt_r, order=opt_order, smooth=opt_smooth)

cf_scores = np.zeros((8, 26450))

for i in range(8):
    cf_scores[i] = retrospective.calc_scores(X[i])

cf_scores = np.nanmax(cf_scores, axis=0)

# SDMDL 0th

def _objective_SDMDL(trial, train, changepoints, tolerance_delay, params):

    nml_multgaussian = partial(sdmdl_nml.nml_multgaussian, R=params[
                               "R"], lambda_min=params["lambda_min"])
    complexity_multgaussian = partial(sdmdl_nml.complexity_multgaussian, m=8, R=params[
                                      "R"], lambda_min=params["lambda_min"])

    window_size = trial.suggest_int('window_size', 100, 300)
    retrospective = sdmdl.Retrospective(h=window_size, encoding_func=nml_multgaussian,
                                        complexity_func=complexity_multgaussian, order=params["order"])

    scores = retrospective.calc_scores(train)
    n = len(scores)
    scores[2 * window_size - 1: n] = scores[window_size - 1: n - window_size]
    scores[0:2 * window_size] = np.nan

    AUC = calc_AUC(scores, changepoints,  tolerance_delay, both=both)
    return -AUC

R = 60
lambda_min = 1e-5

params = {"R": R, "lambda_min": lambda_min, "order": 0}

# 0th D-MDL
# hyperparameter tuning
objective_SDMDL = partial(_objective_SDMDL, train=X.T,
                          changepoints=changepoints, tolerance_delay=tolerance_delay, params=params)
study = optuna.create_study()
study.optimize(objective_SDMDL, n_trials=n_trials, n_jobs=-1)
opt_window_size = study.best_params['window_size']

nml_multgaussian = partial(sdmdl_nml.nml_multgaussian, R=params[
                           "R"], lambda_min=params["lambda_min"])
complexity_multgaussian = partial(sdmdl_nml.complexity_multgaussian, m=8, R=params[
                                  "R"], lambda_min=params["lambda_min"])

retrospective = sdmdl.Retrospective(h=opt_window_size, encoding_func=nml_multgaussian,
                                    complexity_func=complexity_multgaussian, order=params["order"])

sdmdl_0_scores = retrospective.calc_scores(X.T)
n = len(sdmdl_0_scores)
sdmdl_0_scores[2 * opt_window_size -
               1: n] = sdmdl_0_scores[opt_window_size - 1: n - opt_window_size]
sdmdl_0_scores[0:2 * opt_window_size] = np.nan

# 1st D-MDL
params = {"R": R, "lambda_min": lambda_min, "order": 1}

# hyperparameter tuning
objective_SDMDL = partial(_objective_SDMDL, train=X.T,
                          changepoints=changepoints, tolerance_delay=tolerance_delay, params=params)
study = optuna.create_study()
study.optimize(objective_SDMDL, n_trials=n_trials, n_jobs=-1)
opt_window_size = study.best_params['window_size']

retrospective = sdmdl.Retrospective(h=opt_window_size, encoding_func=nml_multgaussian,
                                    complexity_func=complexity_multgaussian, order=params["order"])

sdmdl_1_scores = retrospective.calc_scores(X.T)
n = len(sdmdl_1_scores)
sdmdl_1_scores[2 * opt_window_size -
               1: n] = sdmdl_1_scores[opt_window_size - 1: n - opt_window_size]
sdmdl_1_scores[0:2 * opt_window_size] = np.nan

# 2nd D-MDL
params = {"R": R, "lambda_min": lambda_min, "order": 2}

# hyperparameter tuning
objective_SDMDL = partial(_objective_SDMDL, train=X.T,
                          changepoints=changepoints, tolerance_delay=tolerance_delay, params=params)
study = optuna.create_study()
study.optimize(objective_SDMDL, n_trials=n_trials, n_jobs=-1)
opt_window_size = study.best_params['window_size']

retrospective = sdmdl.Retrospective(h=opt_window_size, encoding_func=nml_multgaussian,
                                    complexity_func=complexity_multgaussian, order=params["order"])

sdmdl_2_scores = retrospective.calc_scores(X.T)
n = len(sdmdl_2_scores)
sdmdl_2_scores[2 * opt_window_size -
               1: n] = sdmdl_2_scores[opt_window_size - 1: n - opt_window_size]
sdmdl_2_scores[0:2 * opt_window_size] = np.nan

# FW2S_MDL

def _objective_FW2S_MDL(trial, train, changepoints, tolerance_delay, params):
    nml_multgaussian = partial(sdmdl_nml.nml_multgaussian, R=params[
                               "R"], lambda_min=params["lambda_min"])
    complexity_multgaussian = partial(sdmdl_nml.complexity_multgaussian, m=8, R=params[
                                      "R"], lambda_min=params["lambda_min"])

    nml_gaussian = partial(sdmdl_nml.nml_gaussian, mu_max=params[
                           "mu_max"], div_min=params["div_min"], div_max=params["div_max"])
    complexity_gaussian = partial(sdmdl_nml.complexity_gaussian, mu_max=params[
                                  "mu_max"], div_min=params["div_min"], div_max=params["div_max"])
    delta_0 = trial.suggest_uniform('delta_0', 0.001, 0.499)
    window_size_1 = trial.suggest_int('window_size_1', 100, 300)
    window_size_2 = trial.suggest_int('window_size_2', 100, 300)

    retrospective_first = sdmdl.Retrospective(h=window_size_1, encoding_func=nml_multgaussian,
                                              complexity_func=complexity_multgaussian, delta_0=delta_0, order=0)
    retrospective_second = sdmdl.Retrospective(h=window_size_2, encoding_func=nml_gaussian,
                                               complexity_func=complexity_gaussian, order=0)
    retrospective = fw2s_mdl.Retrospective(
        retrospective_first, retrospective_second)
    scores = retrospective.calc_scores(train)

    n = len(scores)
    scores[2 * (window_size_1 + window_size_2): n] = scores[window_size_1 +
                                                            window_size_2: n - (window_size_1 + window_size_2)]
    scores[0:2 * (window_size_1 + window_size_2)] = np.nan

    AUC = calc_AUC(scores, changepoints,  tolerance_delay, both=both)
    return -AUC

R = 60
lambda_min = 1e-5
mu_max = 10
div_min = 1e-2
div_max = 1e2

params = {"R": R, "lambda_min": 1e-5, "mu_max": mu_max,
          "div_min": div_min, "div_max": div_max}

# hyperparameter tuning
objective_FW2S_MDL = partial(_objective_FW2S_MDL, train=X.T,
                             changepoints=changepoints, tolerance_delay=tolerance_delay, params=params)
study = optuna.create_study()
study.optimize(objective_FW2S_MDL, n_trials=n_trials, n_jobs=-1)
opt_delta_0 = study.best_params['delta_0']
opt_window_size_1 = study.best_params['window_size_1']
opt_window_size_2 = study.best_params['window_size_2']

nml_multgaussian = partial(sdmdl_nml.nml_multgaussian, R=params[
                           "R"], lambda_min=params["lambda_min"])
complexity_multgaussian = partial(sdmdl_nml.complexity_multgaussian, m=8, R=params[
                                  "R"], lambda_min=params["lambda_min"])
nml_gaussian = partial(sdmdl_nml.nml_gaussian, mu_max=params[
                       "mu_max"], div_min=params["div_min"], div_max=params["div_max"])
complexity_gaussian = partial(sdmdl_nml.complexity_gaussian, mu_max=params[
                              "mu_max"], div_min=params["div_min"], div_max=params["div_max"])

retrospective_first = sdmdl.Retrospective(h=opt_window_size_1, encoding_func=nml_multgaussian,
                                          complexity_func=complexity_multgaussian, delta_0=opt_delta_0, order=0)
retrospective_second = sdmdl.Retrospective(h=opt_window_size_2, encoding_func=nml_gaussian,
                                           complexity_func=complexity_gaussian, order=0)
retrospective = fw2s_mdl.Retrospective(
    retrospective_first, retrospective_second)

fw2s_mdl_scores = retrospective.calc_scores(X.T)
n = len(fw2s_mdl_scores)
fw2s_mdl_scores[2 * (opt_window_size_1 + opt_window_size_2): n] = fw2s_mdl_scores[opt_window_size_1 +
                                                                                opt_window_size_2: n - (opt_window_size_1 + opt_window_size_2)]
fw2s_mdl_scores[0:2 * (opt_window_size_1 + opt_window_size_2)] = np.nan

sdmdl_0_scores[np.isnan(sdmdl_0_scores)] = np.nanmin(sdmdl_0_scores)
sdmdl_1_scores[np.isnan(sdmdl_1_scores)] = np.nanmin(sdmdl_1_scores)
sdmdl_2_scores[np.isnan(sdmdl_2_scores)] = np.nanmin(sdmdl_2_scores)
fw2s_mdl_scores[np.isnan(fw2s_mdl_scores)] = np.nanmin(fw2s_mdl_scores)

print("SDMDL 0th: ", calc_AUC(sdmdl_0_scores,
                              changepoints,  tolerance_delay, both=both))
print("SDMDL 1st: ", calc_AUC(sdmdl_1_scores,
                              changepoints,  tolerance_delay, both=both))
print("SDMDL 2nd: ", calc_AUC(sdmdl_2_scores,
                              changepoints,  tolerance_delay, both=both))
print("FW2S-MDL: ", calc_AUC(fw2s_mdl_scores,
                             changepoints,  tolerance_delay, both=both))
print("ChangeFinder: ", calc_AUC(
    cf_scores, changepoints,  tolerance_delay, both=both))
print("BOCPD: ", calc_AUC(bocpd_scores, changepoints,  tolerance_delay, both=both))

df_result = pd.DataFrame()
row = pd.DataFrame({"method: ": ["SDMDL 0th"], "AUC: ": calc_AUC(
    sdmdl_0_scores, changepoints,  tolerance_delay, both=both)})
df_result = pd.concat([df_result, row], axis=0)
row = pd.DataFrame({"method: ": ["SDMDL 1st"], "AUC: ": calc_AUC(
    sdmdl_1_scores, changepoints,  tolerance_delay, both=both)})
df_result = pd.concat([df_result, row], axis=0)
row = pd.DataFrame({"method: ": ["SDMDL 2nd"], "AUC: ": calc_AUC(
    sdmdl_2_scores, changepoints,  tolerance_delay, both=both)})
df_result = pd.concat([df_result, row], axis=0)
row = pd.DataFrame({"method: ": ["FW2S-MDL"], "AUC: ": calc_AUC(
    fw2s_mdl_scores, changepoints,  tolerance_delay, both=both)})
df_result = pd.concat([df_result, row], axis=0)
row = pd.DataFrame({"method: ": ["ChangeFinder"], "AUC: ": calc_AUC(
    cf_scores, changepoints,  tolerance_delay, both=both)})
df_result = pd.concat([df_result, row], axis=0)
row = pd.DataFrame({"method: ": ["BOCPD"], "AUC: ": calc_AUC(
    bocpd_scores, changepoints,  tolerance_delay, both=both)})
df_result = pd.concat([df_result, row], axis=0)

df_result.to_csv("production_condition.csv", index=False)

plt.clf()
fig, axes = plt.subplots(nrows=7, ncols=1, figsize=(20, 20))

fontsize = 18

axes[0].plot(X[0], label='Raw Data')
axes[0].set_ylabel('Return', fontsize=fontsize)
axes[0].vlines(changepoints, np.min(X[0]), np.max(X[0]), color="black")
axes[0].set_ylim(np.min(X[0]), np.max(X[0]))
axes[0].legend(bbox_to_anchor=(1, 1), loc='upper right',
               borderaxespad=0, fontsize=fontsize)
axes[0].grid(True)

axes[1].plot(sdmdl_0_scores, label='SD-MDL 0th')
axes[1].set_ylabel('Description Length', fontsize=fontsize)
axes[1].vlines(changepoints, np.nanmin(sdmdl_0_scores) - 1,
               np.nanmax(sdmdl_0_scores) + 1, color="black")
axes[1].set_ylim(np.nanmin(sdmdl_0_scores) - 1, np.nanmax(sdmdl_0_scores) + 1)
axes[1].legend(bbox_to_anchor=(1, 1), loc='upper right',
               borderaxespad=0, fontsize=fontsize)
axes[1].grid(True)

axes[2].plot(sdmdl_1_scores, label='SD-MDL 1st')
axes[2].set_ylabel('Description Length', fontsize=fontsize)
axes[2].vlines(changepoints, 0, np.nanmax(sdmdl_1_scores), color="black")
axes[2].set_ylim(0, np.nanmax(sdmdl_1_scores))
axes[2].legend(bbox_to_anchor=(1, 1), loc='upper right',
               borderaxespad=0, fontsize=fontsize)
axes[2].grid(True)

axes[3].plot(sdmdl_2_scores, label='SD-MDL 2nd')
axes[3].set_ylabel('Description Length', fontsize=fontsize)
axes[3].vlines(changepoints, 0, np.nanmax(sdmdl_1_scores), color="black")
axes[3].set_ylim(0, np.nanmax(sdmdl_1_scores))
axes[3].legend(bbox_to_anchor=(1, 1), loc='upper right',
               borderaxespad=0, fontsize=fontsize)
axes[3].grid(True)

axes[4].plot(fw2s_mdl_scores, label='FW2S-MDL')
axes[4].set_ylabel('Description Length', fontsize=fontsize)
axes[4].vlines(changepoints, np.nanmin(fw2s_mdl_scores) - 1,
               np.nanmax(fw2s_mdl_scores) + 1, color="black")
axes[4].set_ylim(np.nanmin(fw2s_mdl_scores) - 1,
                 np.nanmax(fw2s_mdl_scores) + 1)
axes[4].legend(bbox_to_anchor=(1, 1), loc='upper right',
               borderaxespad=0, fontsize=fontsize)
axes[4].grid(True)

axes[5].plot(cf_scores, label='ChangeFinder')
axes[5].set_ylabel('Change Score', fontsize=fontsize)
axes[5].vlines(changepoints, np.nanmin(cf_scores) - 1,
               np.nanmax(cf_scores) + 1, color="black")
axes[5].set_ylim(np.nanmin(cf_scores) - 1, np.nanmax(cf_scores) + 1)
axes[5].legend(bbox_to_anchor=(1, 1), loc='upper right',
               borderaxespad=0, fontsize=fontsize)
axes[5].grid(True)

axes[6].plot(bocpd_scores, label='BOCPD')
axes[6].set_ylabel('Change Score', fontsize=fontsize)
axes[6].vlines(changepoints, np.nanmin(bocpd_scores),
               np.nanmax(bocpd_scores), color="black")
axes[6].set_ylim(np.nanmin(bocpd_scores), np.nanmax(bocpd_scores))
axes[6].legend(bbox_to_anchor=(1, 1), loc='upper right',
               borderaxespad=0, fontsize=fontsize)
axes[6].grid(True)

fig.savefig("production_condition.png")

# upload to s3
s3 = boto3.resource('s3')
bucket = s3.Bucket(AWS_S3_BUCKET_NAME)

bucket.upload_file("production_condition.png",
                   "production_condition/" + "production_condition.png")
bucket.upload_file("production_condition.csv",
                   "production_condition/" + "production_condition.csv")


import sys
sys.path.append("..")

import paddle
import paddle.nn as nn
import paddle.nn.functional as F
from ..misc import ModuleWrapper

from metrics import calculate_kl as KL_DIV

class BBBLinear(ModuleWrapper):
    def __init__(self, in_features, out_features, bias=True, priors=None):
        super(BBBLinear, self).__init__()
        self.in_features = in_features
        self.out_features = out_features
        self.use_bias = bias

        if priors is None:
            priors = {
                'prior_mu': 0,
                'prior_sigma': 0.1,
                'posterior_mu_initial': (0, 0.1),
                'posterior_rho_initial': (-3, 0.1),
            }
        self.prior_mu = priors['prior_mu']
        self.prior_sigma = priors['prior_sigma']
        self.posterior_mu_initial = priors['posterior_mu_initial']
        self.posterior_rho_initial = priors['posterior_rho_initial']

        x = paddle.empty([in_features,out_features])
        self.W_mu = paddle.create_parameter(shape=x.shape,
                        dtype=str(x.numpy().dtype),
                        default_initializer=paddle.nn.initializer.Normal(*self.posterior_mu_initial))

        self.W_rho = paddle.create_parameter(shape=x.shape,
                        dtype=str(x.numpy().dtype),
                        default_initializer=paddle.nn.initializer.Normal(*self.posterior_rho_initial))

        if self.use_bias:
            y = paddle.empty([out_features])
            self.bias_mu = paddle.create_parameter(shape=y.shape,
                        dtype=str(y.numpy().dtype),
                        default_initializer=paddle.nn.initializer.Normal(*self.posterior_mu_initial))
            self.bias_rho = paddle.create_parameter(shape=y.shape,
                        dtype=str(y.numpy().dtype),
                        default_initializer=paddle.nn.initializer.Normal(*self.posterior_rho_initial))

    def forward(self, input, sample=True):
        if self.training or sample:
            W_eps = paddle.normal(mean = 0.0,std = 1.,shape=self.W_mu.shape)
            self.W_sigma = paddle.log1p(paddle.exp(self.W_rho))

            weight = self.W_mu + W_eps * self.W_sigma

            if self.use_bias:
                bias_eps = paddle.normal(mean = 0.0,std = 1.,shape=self.bias_mu.shape)
                self.bias_sigma = paddle.log1p(paddle.exp(self.bias_rho))

                bias = self.bias_mu + bias_eps * self.bias_sigma
            else:
                bias = None
        else:
            weight = self.W_mu
            bias = self.bias_mu if self.use_bias else None

        return F.linear(input, weight, bias)

    def kl_loss(self):
        kl = KL_DIV(self.prior_mu, self.prior_sigma, self.W_mu, self.W_sigma)
        if self.use_bias:
            kl += KL_DIV(self.prior_mu, self.prior_sigma, self.bias_mu, self.bias_sigma)
        return kl