from __future__ import annotations

from typing import Tuple

import distrax
import jax
import jax.numpy as jnp
import jax.tree_util as jtu
import optax
from flax import linen as nn
from flax import struct
from flax.core.scope import VariableDict as Params
from jax import Array
from jax.random import KeyArray
from optax import GradientTransformation
import rlax

from helx.base.modules import Lambda, Parallel, Split, Temperature
from helx.base.mdp import Timestep, TERMINATION
from helx.base.memory import ReplayBuffer
from helx.base.spaces import Continuous
from helx.base import losses

from .agent import Agent, AgentState, HParams, Log

class SACHParams(HParams):
    # network
    action_space: Continuous
    tau: float = 0.005
    # rl
    replay_start: int = 1000
    replay_memory_size: int = 1000
    update_frequency: int = 1
    target_network_update_frequency: int = 10000
    discount: float = 0.99
    n_steps: int = 1
    entropy_rewards: bool = False
    # sgd
    batch_size: int = 32
    learning_rate: float = 3e-4

class SACLog(Log):
    buffer_size: Array = jnp.asarray(0)
    critic_loss: Array = jnp.asarray(float("inf"))
    actor_loss: Array = jnp.asarray(float("inf"))
    temperature_loss: Array = jnp.asarray(float("inf"))
    total_loss: Array = jnp.asarray(float("inf"))
    policy_entropy: Array = jnp.asarray(float("inf"))
    alpha: Array = jnp.asarray(float("inf"))

class SACState(AgentState):
    params: Tuple[Params, Params, Params, Params] = struct.field(pytree_node=True)
    buffer: ReplayBuffer = struct.field(pytree_node=True)
    log: SACLog = struct.field(pytree_node=True)

class SAC(Agent):
    """Implements Soft Actor-Critic with gaussian policy for continuous action spaces.
    Haarnoja, Tuomas, et al. "Soft actor-critic: Off-policy maximum entropy deep
        reinforcement learning with a stochastic actor."
        International conference on machine learning. PMLR, 2018.
        https://arxiv.org/abs/1801.01290 for the base SAC.
    Haarnoja, Tuomas, et al. "Soft actor-critic algorithms and applications."
        arXiv preprint arXiv:1812.05905 (2018).
        https://arxiv.org/abs/1812.05905 for the tunable entropy temperature
    Haonanm Yu, et al. "Do you need reward entropy (in practice)?".
        arXiv preprint arXiv:2201.12434. 2022 Jan 28.
        https://arxiv.org/abs/2201.12434

    Args:
        network (AgentNetwork): the network to use for the agent.
            the `actor_net` is usually a `GaussianPolicy` for continuous action spaces.
            the `critic_net` is double Q network.
            the `extra_net` is usually a `Temperature` layer to automatically
            tune the entropy pull.
        optimiser (GradientTransformation): an optax optimiser to perform gradient descent.
        hparams (SACHparams): the hyperparameters for the agent.
        seed (int): the seed to use for the agent.
            Using the same seed will result in reproducible agent results.
    """

    hparams: SACHParams = struct.field(pytree_node=False)
    optimiser: GradientTransformation = struct.field(pytree_node=False)
    actor: nn.Module = struct.field(pytree_node=False)
    critic: nn.Module = struct.field(pytree_node=False)
    critic_target: nn.Module = struct.field(pytree_node=False)
    temperature: nn.Module = struct.field(pytree_node=False)

    @classmethod
    def create(
        cls,
        hparams: SACHParams,
        optimiser: optax.GradientTransformation,
        actor_backbone: nn.Module,
        critic_backbone: nn.Module,
    ) -> SAC:
        action_size = hparams.action_space.size
        reshape = Lambda(lambda x: x.reshape(hparams.action_space.shape))
        actor = nn.Sequential(
            [
                actor_backbone,
                Split(2),
                Parallel((nn.Dense(action_size), nn.Dense(action_size))),
                Parallel((reshape, jtu.tree_map(lambda x: x, reshape))),
            ]
        )
        critic = nn.Sequential([critic_backbone, nn.Dense(1)])
        critic_target = nn.Sequential([critic_backbone, nn.Dense(1)])
        temperature = Temperature()
        return SAC(
            hparams=hparams,
            optimiser=optimiser,
            actor=actor,
            critic=critic,
            critic_target=critic_target,
            temperature=temperature,
        )

    def init(self, timestep: Timestep, *, key: KeyArray) -> SACState:
        """Initialises the agent state.

        Args:
            key (KeyArray): a JAX PRNG key.

        Returns:
            SACState: the initial agent state.
        """
        key, k1, k2, k3 = jax.random.split(key, num=4)
        obs = self.hparams.obs_space.sample(key=key)
        params = (
            self.actor.init(k1, obs),
            self.critic.init(k2, obs),
            self.critic_target.init(k2, obs),
            self.temperature.init(k3),
        )
        opt_state = self.optimiser.init(params)
        buffer = ReplayBuffer.create(
            timestep, self.hparams.replay_memory_size, self.hparams.n_steps
        )
        return SACState(
            iteration=jnp.asarray(0),
            opt_state=opt_state,
            log=SACLog(),
            params=params,
            buffer=buffer,
        )

    def sample_action(
        self, train_state: SACState, obs: Array, *, key: KeyArray, eval: bool = False
    ) -> Array:
        params_actor = train_state.params[0]
        mu, logvar = jtu.tree_map(jnp.asarray, self.actor.apply(params_actor, obs))
        # SAC uses a tanh squashing function
        # see https://arxiv.org/pdf/1801.01290.pdf, Appendix C.
        # and https://github.com/openai/spinningup/blob/master/spinup/algos/pytorch/sac/core.py#L29
        policy = distrax.Transformed(
            distrax.Normal(mu, jnp.exp(logvar)), distrax.Tanh()
        )
        action = policy.sample(seed=key)
        return action

    def loss(
        self,
        params: Tuple[Params, Params, Params, Params],
        timesteps: Timestep,
        *,
        key: KeyArray,
    ) -> Tuple[Array, Tuple[Array, Array, Array, Array, Array]]:
        s_tm1 = timesteps.observation[:-1]
        s_t = timesteps.observation[1:]
        r_t = timesteps.reward[:-1][0]  # [0] because scalar
        terminal_tm1 = timesteps.step_type[:-1] != TERMINATION
        k1, k2 = jax.random.split(key, num=2)

        # params
        params_actor, params_critic, params_critic_target, params_temperature = params

        # autotuning temp
        temperature = jnp.asarray(self.temperature.apply(params_temperature))
        alpha = jax.lax.stop_gradient(temperature)

        # actor
        mu_tm1, logvar_tm1 = jtu.tree_map(
            jnp.asarray, self.actor.apply(params_actor, s_tm1)
        )
        policy_tm1 = distrax.Transformed(
            distrax.Normal(mu_tm1, jnp.exp(logvar_tm1)), distrax.Tanh()
        )
        a_tm1, logprobs_a_tm1 = policy_tm1.sample_and_log_prob(seed=k1)

        mu_t, logvar_t = jtu.tree_map(jnp.asarray, self.actor.apply(params_actor, s_t))
        policy_t = distrax.Transformed(
            distrax.Normal(mu_t, jnp.exp(logvar_t)), distrax.Tanh()
        )
        a_t, logprobs_a_t = policy_t.sample_and_log_prob(seed=k1)

        # critic
        q_tm1 = self.critic.apply(params_critic, s_tm1)
        qA_t, qB_t = jtu.tree_map(jnp.asarray, self.critic.apply(params_critic, s_t))
        q_target = jnp.min(jnp.asarray([qA_t, qB_t]), axis=0)
        critic_loss = losses.double_dqn_loss(
            timesteps,
            self.critic,
            params_critic,
            params_critic_target,
            self.hparams.discount,
        )

        # augment reward with policy entropy
        policy_entropy = -jnp.sum(probs_a_tm1 * logprobs_a_tm1, axis=-1)

        # critic loss
        qA_tm1, qB_tm1 = self.critic.apply(params_critic, s_tm1)
        qA_t, qB_t = self.critic.apply(params_critic, s_t)
        q_target = jnp.min(jnp.asarray([qA_t, qB_t]), axis=0)
        v_t = q_target - alpha * logprobs_a_t
        rlax.double_q_learning(
            q_tm1,
            a_tm1,
            r_t,
            discount_t,
            q_target,
        )

        qA_tm1, qB_tm1 = jnp.asarray(qA_tm1), jnp.asarray(qB_tm1)
        qA_t, qB_t = jnp.asarray(qA_t), jnp.asarray(qB_t)
        q_t = jnp.min(jnp.stack([qA_t, qB_t], axis=0), axis=0)
        v_t = q_t - alpha * logprobs_a_t
        q_target = jax.lax.stop_gradient(
            r_t + terminal_tm1 * self.hparams.discount * v_t
        )
        critic_loss = jnp.asarray(
            optax.l2_loss(qA_tm1, q_target) + optax.l2_loss(qB_tm1, q_target)
        )

        # actor loss
        q_tm1 = jax.lax.stop_gradient(
            jnp.min(jnp.stack([qA_tm1, qB_tm1], axis=0), axis=0)
        )
        rlax.policy_gradient_loss()
        actor_loss = jnp.asarray(alpha * logprobs_a_tm1 - q_tm1)

        # temperature loss
        target_entropy = -self.hparams.action_space.ndim
        logprobs_a_tm1 = jax.lax.stop_gradient(logprobs_a_tm1)
        temperature_loss = jnp.asarray(
            -(temperature * (logprobs_a_tm1 + target_entropy))
        )

        loss = actor_loss + critic_loss + temperature_loss
        aux = (actor_loss, critic_loss, temperature_loss, policy_entropy, alpha)
        return loss, aux

    def update(
        self,
        train_state: SACState,
        transition: Timestep,
        *,
        key: KeyArray,
    ) -> SACState:
        # update iteration
        iteration = jnp.asarray(train_state.iteration + 1, dtype=jnp.int32)

        # update memory
        buffer = train_state.buffer.add(transition)

        # update actor, critic and temperature
        def _sgd_step(params, opt_state):
            def _loss_fn(params, transition):
                loss, aux = jax.vmap(self.loss, in_axes=(None, 0))(params, transition)
                return jnp.mean(loss), aux

            transitions = buffer.sample(key, self.hparams.batch_size)
            (loss, aux), grads = jax.value_and_grad(_loss_fn, has_aux=True)(
                params, transitions
            )
            updates, opt_state = self.optimiser.update(grads, opt_state)
            params = optax.apply_updates(params, updates)
            return params, opt_state, loss, aux

        cond = buffer.size() < self.hparams.replay_memory_size
        cond = jnp.logical_or(cond, iteration % self.hparams.update_frequency != 0)
        params, opt_state, loss, aux = jax.lax.cond(
            cond,
            lambda p, o: _sgd_step(p, o),
            lambda p, o: (p, o, jnp.asarray(float("inf"))),
            train_state.params,
            train_state.opt_state,
        )

        # update log
        log = SACLog(
            iteration=iteration,
            actor_loss=aux[0],
            critic_loss=aux[1],
            temperature_loss=aux[2],
            total_loss=loss,
            policy_entropy=aux[3],
            alpha=aux[4],
            step_type=transition.step_type[-1],
            returns=train_state.log.returns
            + jnp.sum(
                self.hparams.discount ** transition.t[:-1] * transition.reward[:-1]
            ),
            buffer_size=buffer.size(),
        )

        # update train_state
        train_state = train_state.replace(
            iteration=iteration,
            opt_state=opt_state,
            params=params,
            buffer=buffer,
            log=log,
        )
        return train_state


"""Logic of game: prime check"""

import random

START_MSG = 'Answer "yes" if given number is prime. Otherwise answer "no".'

def is_prime(num):
    if num <= 1:
        return False
    div = 2
    while div <= num / 2:
        if num % div == 0:
            return False
        div += 1
    return True

def generate_qa():
    question = random.randint(-100, 100)
    answer = ('yes' if is_prime(question) is True else 'no')
    return (question, answer)


from ni_engine.tools import Item
from ..abstract_sensor import AbstractSensor
import random
from ni_engine.storage import DataContainer,data
import ni_engine.config as config
class GaussianSensor(AbstractSensor):
    """
    Abstract sensor that who's measurement simply
    pulls a value from a gaussian distribution.
    """
    code = "GAUSSSENSOR"
    def __init__(self,ID,mu=1,sigma=1,max_measurements=-1,name="",description=""):
        self._mu =mu
        self._sigma = sigma
        self._code = GaussianSensor.code
        self._name = name
        self._description = description
        self._id = ID
        self._max_measurements = max_measurements
    def connect(self):
        """
        Connects sensor
        """
        raise NotImplementedError('Abstract method has not been implemented')

    def disconnect(self):
        """
        Disconnects sensor
        """
        raise NotImplementedError('Abstract method has not been implemented')

    def delete(self):
        """
        Deletes sensor
        """
        del self

    def measure(self):
        """
        Called to measure sensor
        Returns
        -------
        DataContainer
        """
        val = random.gauss(self._mu,self._sigma)
        measurement = data(self.id,self.code,self.name,val)
        container = DataContainer(self._id,self._max_measurements)
        container["gaussian"]=measurement
        return container

    # abstract method to handle sensor creation based on configuration
    @classmethod
    def create(cls,configuration,data_handler,hardware):
        """
        Abstract method that when implemented is the intializer method for the sensor.

        Parameters
        ----------
        config : configuration
        data_handler : data_handler
        hardware : HardwareManager

        Returns
        -------
        GaussianSensor
        """
        mu = configuration.get("mu",1)
        sigma = configuration.get("sigma",1)
        ID = configuration.get(config.ID)
        name = configuration.get(config.NAME,"gaussian sensor")
        description = configuration.get(config.DESCRIPTION,"pulls from gaussian distribution")
        max_measurements = configuration.get(config.MAX_DATA,-1)
        return GaussianSensor(ID,mu,sigma,max_measurements,name,description)


# In the future I should probably switch all my view classes to FormView

from django.conf import settings
from django.shortcuts import redirect, reverse
from django.urls import reverse_lazy, resolve
from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils.decorators import method_decorator
from django.forms.models import model_to_dict
from django.contrib import messages
from django.utils.translation import gettext as _
from ratelimit.decorators import ratelimit
from ratelimit.core import is_ratelimited

import common.utils as utils
from common.views import CHANGELOGS, logger, TimewebGenericView
from timewebapp.views import ExampleAccountView
from .forms import SettingsForm
from .models import SettingsModel

from api.integrations import (
    disable_gc_integration,
    generate_gc_authorization_url,
    disable_canvas_integration,
    generate_canvas_authorization_url,
)
from contact_form.views import ContactFormView

import asyncio
from requests import get as requests_get
from copy import deepcopy

EXCLUDE_FROM_DEFAULT_SETTINGS_FIELDS = (
    # cannot be json serialized
    "background_image",
    # self explanatory
    "id",
    # handled by the frontend, is a hidden input
    "assignment_sorting",
)
# NOTE: this does not take into account SettingsForm.Meta.exlude, so don't worry if
# you see fields like gc_courses_cache here
DONT_EXCLUDE_FROM_DEFAULT_SETTINGS_FIELDS = (
    'immediately_delete_completely_finished_assignments', 'def_min_work_time',
    'def_break_days', 'def_skew_ratio', 'one_graph_at_a_time', 'close_graph_after_work_input', 'show_priority', 'highest_priority_color',
    'lowest_priority_color', 'default_dropdown_tags', 'horizontal_tag_position', 'vertical_tag_position', 'appearance', 'animation_speed',
    'enable_tutorial', 'sorting_animation_threshold', 'gc_token', 'added_gc_assignment_ids', 'seen_latest_changelog',
    'nudge_calendar', 'nudge_notifications', 'user', 'gc_courses_cache', 'device_uuid', 'device_uuid_api_timestamp',
    'display_working_days_left', 'background_image_text_shadow_width', 'gc_assignments_always_midnight', 'loosely_enforce_minimum_work_times',
    'priority_color_borders', 'font', 'should_alert_due_date_incremented', 'example_account', "gc_token",
    'added_canvas_assignment_ids', 'canvas_courses_cache', 'canvas_instance_domain',
)

assert len(EXCLUDE_FROM_DEFAULT_SETTINGS_FIELDS) + len(DONT_EXCLUDE_FROM_DEFAULT_SETTINGS_FIELDS) == len(SettingsModel._meta.fields), "update this list"
@method_decorator(ratelimit(key=utils.get_client_ip, rate='1/s', method="POST", block=True), name='post')
@method_decorator(ratelimit(key=utils.get_client_ip, rate='20/m', method="POST", block=True), name='post')
@method_decorator(ratelimit(key=utils.get_client_ip, rate='100/h', method="POST", block=True), name='post')
class SettingsView(LoginRequiredMixin, TimewebGenericView):
    template_name = "navbar/settings.html"

    def get(self, request):
        if self.user is None:
            self.user = request.user
        if "form" not in self.context:
            initial = {
                'gc_integration': 'token' in self.user.settingsmodel.gc_token,
                'canvas_integration': 'token' in self.user.settingsmodel.canvas_token,
                'canvas_instance_domain': self.user.settingsmodel.canvas_instance_domain,
            }
            self.context['form'] = SettingsForm(initial=initial, instance=self.user.settingsmodel)
        self.context['default_settings'] = model_to_dict(SettingsForm().save(commit=False),
                            exclude=[*SettingsForm.Meta.exclude, # SettingsForm already excludes these fields but saving the field to a model adds them back
                            *EXCLUDE_FROM_DEFAULT_SETTINGS_FIELDS])

        logger.info(f'User \"{self.user}\" is now viewing the settings page')
        return TimewebGenericView.get(self, request)

    def post(self, request):
        if self.user is None:
            self.user = request.user
        self.old_settings = deepcopy(self.user.settingsmodel)
        self.form = SettingsForm(data=request.POST, files=request.FILES, instance=self.user.settingsmodel)
        if request.path == reverse("example_settings"):
            # don't run this after is_valid because is_valid updates self.user.settingsmodel which then is later
            # saved into the db by later .save calls in other views
            if self.form.data.get("view_deleted_assignments"):
                return redirect("example_deleted_assignments")
            else:
                return redirect("example")
        if self.form.is_valid():
            return self.valid_form(request)
        else:
            return self.invalid_form(request)

    def valid_form(self, request):
        enabled_gc_integration = self.form.cleaned_data.get("gc_integration") and not 'token' in self.user.settingsmodel.gc_token
        disabled_gc_integration = not self.form.cleaned_data.get("gc_integration") and 'token' in self.user.settingsmodel.gc_token
        enabled_canvas_integration = self.form.cleaned_data.get("canvas_integration") and not 'token' in self.user.settingsmodel.canvas_token
        disabled_canvas_integration = not self.form.cleaned_data.get("canvas_integration") and 'token' in self.user.settingsmodel.canvas_token
        if (
            self.form.cleaned_data.get("canvas_instance_domain") != self.old_settings.canvas_instance_domain
            and self.form.cleaned_data.get("canvas_integration")
            and 'token' in self.user.settingsmodel.canvas_token
        ):
            disabled_canvas_integration = True
            enabled_canvas_integration = True
        async def disable_integrations():
            loop = asyncio.get_event_loop()
            disable_integration_tasks = []
            if disabled_gc_integration:
                disable_integration_tasks.append(loop.run_in_executor(None, lambda: disable_gc_integration(request, save=False)))
            if disabled_canvas_integration:
                disable_integration_tasks.append(loop.run_in_executor(None, lambda: disable_canvas_integration(request, save=False)))
            await asyncio.gather(*disable_integration_tasks)
        asyncio.run(disable_integrations())

        self.form.save()
        logger.info(f'User \"{self.user}\" updated the settings page')

        integration_authorization_urls = []
        if enabled_gc_integration:
            integration_authorization_urls.append(
                lambda next_url: generate_gc_authorization_url(request, next_url=next_url, current_url="settings")
            )
        if enabled_canvas_integration:
            integration_authorization_urls.append(
                lambda next_url: generate_canvas_authorization_url(request, next_url=next_url, current_url="settings")
            )
        prev_url = None
        for current_url in reversed(integration_authorization_urls):
            if prev_url is None:
                prev_url = current_url("home")
            else:
                prev_url = current_url(prev_url)
        if prev_url is not None:
            return redirect(prev_url)

        if self.form.cleaned_data.get("view_deleted_assignments"):
            return redirect("deleted_assignments")
        else:
            return redirect("home")

    def invalid_form(self, request):
        self.context['form'] = self.form
        logger.info(self.form.errors)
        # It's ok to return a 2xx from invalid form, because there is no danger of the user resubmitting because its invalid
        return self.get(request)

# the class order matters so settingsview can override exampleaccountview
class ExampleAccountSettingsView(SettingsView, ExampleAccountView):
    pass

class SecuredFormView(ContactFormView):
    success_url = reverse_lazy("secured_contact_form")

    def post(self, request):
        if is_ratelimited(request, group=resolve(request.path)._func_path, key=utils.get_client_ip, rate='1/m', method="POST", increment=True):
            messages.error(request, "You must wait for one minute before submitting another contact form.")
            return super().get(request)
        recaptcha_token = request.POST.get('g-recaptcha-response')
        auth = requests_get(f"https://www.google.com/recaptcha/api/siteverify?secret={settings.RECAPTCHA_SECRET_KEY}&response={recaptcha_token}")
        if auth.json()['success']:
            # should 3xx: ProcessFormView.post -> ContactFormView.form_valid -> FormMixin.form_valid -> redirect
            return super().post(request)
        else:
            messages.error(request, "Your submission was not authentic. Please try again.")
            return super().get(request)

class BlogView(TimewebGenericView):
    template_name = "navbar/blog.html"

class UserguideView(TimewebGenericView):
    template_name = "navbar/user_guide.html"

    def get(self, request):
        self.context['default_settings'] = model_to_dict(SettingsForm().save(commit=False),
                            exclude=[*SettingsForm.Meta.exclude, # SettingsForm already excludes these fields but saving the field to a model adds them back
                            *EXCLUDE_FROM_DEFAULT_SETTINGS_FIELDS])
        self.context['add_faq'] = True
        return super().get(request)

class ChangelogView(TimewebGenericView):
    template_name = "navbar/changelog.html"

    def get(self, request):
        self.context['changelogs'] = CHANGELOGS
        return super().get(request)


"""
Parts for Optical Field Writable Arrays (OFWA)
"""

import numpy as np

from gdshelpers.parts import Port
from gdshelpers.parts.waveguide import Waveguide
from gdshelpers.parts.marker import DLWMarker

from gdshelpers.geometry import geometric_union
from gdshelpers.helpers import normalize_phase

class MultiPortSwitch:
    def __init__(self, origin, angle, in_ports, out_ports, port_spacing, taper_length, taper_function, radius,
                 wg_bend_radius, displacement=0., minimal_final_spacing=None):
        self._origin = origin
        self._angle = angle
        self._in_ports = in_ports
        self._out_ports = out_ports
        self._port_spacing = port_spacing
        self._taper_length = taper_length
        self._taper_function = taper_function
        self._taper_options = {}
        self._radius = radius
        self._wg_bend_radius = wg_bend_radius
        self._displacement = displacement
        self._minimal_final_spacing = minimal_final_spacing

        self._in_wgs = None
        self._out_wgs = None

    @classmethod
    def make_at_in_port(cls, port, in_port_idx, **kwargs):
        tmp_mps = cls([0, 0], port.angle, **kwargs)
        return cls(-tmp_mps.get_in_port(in_port_idx).origin + port.origin, port.angle, **kwargs)

    @classmethod
    def make_at_out_port(cls, port, out_port_idx, **kwargs):
        tmp_mps = cls([0, 0], port.inverted_direction.angle, **kwargs)
        return cls(-tmp_mps.get_out_port(out_port_idx).origin + port.origin, port.inverted_direction.angle, **kwargs)

    @property
    def origin(self):
        return np.array(self._origin)

    @property
    def angle(self):
        return self._angle

    @property
    def _angular_spacing(self):
        return self._port_spacing / self._radius

    def _calculate(self, do_in_wgs=True, do_out_wgs=True):
        angular_spacing = self._angular_spacing
        assert angular_spacing * self._out_ports < np.pi, 'Not enough space for output ports'
        assert angular_spacing * self._in_ports < np.pi, 'Not enough space for input ports'

        if do_out_wgs:
            # Do the output side
            out_origin_port = Port(self._origin, self._angle, 1.).longitudinal_offset(-self._displacement / 2)
            out_fanout_wgs = [Waveguide.make_at_port(out_origin_port.rotated(angle).longitudinal_offset(self._radius))
                              for angle in (np.arange(self._out_ports) - (self._out_ports - 1) / 2.) * angular_spacing]

            for wg in out_fanout_wgs:
                wg.add_parameterized_path(path=lambda t: [t * self._taper_length, np.zeros_like(t)],
                                          path_derivative=lambda t: [np.ones_like(t) * self._taper_length,
                                                                     np.zeros_like(t)],
                                          path_function_supports_numpy=True,
                                          width=self._taper_function, **self._taper_options)

            if self._minimal_final_spacing is None:
                for wg in out_fanout_wgs:
                    wg.add_bend(normalize_phase(-wg.angle + self._angle), self._wg_bend_radius)

            else:
                offsets = (np.arange(self._out_ports) - (self._out_ports - 1) / 2.) * self._minimal_final_spacing
                final_port_heights = [out_origin_port.parallel_offset(offset) for offset in offsets]

                for wg, final_port_height, offset in zip(out_fanout_wgs, final_port_heights, offsets):
                    if np.isclose(offset, 0):
                        continue

                    try:
                        wg.add_route_single_circle_to_port(final_port_height.inverted_direction, on_line_only=True)
                    except AssertionError:
                        # No curve possible, use normal bend
                        wg.add_bend(normalize_phase(-wg.angle + self._angle), self._wg_bend_radius)

            final_ports = [wg.current_port for wg in out_fanout_wgs]
            for wg in out_fanout_wgs:
                wg.add_straight_segment_until_level_of_port(final_ports)
            self._out_wgs = out_fanout_wgs

        if do_in_wgs:
            # Do the input side
            in_origin_port = Port(self._origin, self._angle + np.pi, 1.).longitudinal_offset(-self._displacement / 2)
            in_fanout_wgs = [Waveguide.make_at_port(in_origin_port.rotated(angle).longitudinal_offset(self._radius))
                             for angle in (np.arange(self._in_ports) - (self._in_ports - 1) / 2.) * angular_spacing]

            for wg in in_fanout_wgs:
                wg.add_parameterized_path(path=lambda t: [t * self._taper_length, np.zeros_like(t)],
                                          path_derivative=lambda t: [np.ones_like(t) * self._taper_length,
                                                                     np.zeros_like(t)],
                                          path_function_supports_numpy=True,
                                          width=self._taper_function, **self._taper_options)

            if self._minimal_final_spacing is None:
                for wg in in_fanout_wgs:
                    wg.add_bend(normalize_phase(-wg.angle + self._angle - np.pi), self._wg_bend_radius)

            else:
                offsets = (np.arange(self._in_ports) - (self._in_ports - 1) / 2.) * self._minimal_final_spacing
                final_port_heights = [in_origin_port.parallel_offset(offset) for offset in offsets]

                for wg, final_port_height, offset in zip(in_fanout_wgs, final_port_heights, offsets):
                    if np.isclose(offset, 0):
                        continue

                    # wg.add_route_single_circle_to_port(final_port_height.inverted_direction, on_line_only=True)

                    try:
                        wg.add_route_single_circle_to_port(final_port_height.inverted_direction, on_line_only=True)
                    except AssertionError:
                        # No curve possible, use normal bend
                        wg.add_bend(normalize_phase(-wg.angle + self._angle - np.pi), self._wg_bend_radius)

            final_ports = [wg.current_port for wg in in_fanout_wgs]
            for wg in in_fanout_wgs:
                wg.add_straight_segment_until_level_of_port(final_ports)

            self._in_wgs = in_fanout_wgs

    def get_in_port(self, idx):
        if not self._in_wgs:
            self._calculate(do_in_wgs=True, do_out_wgs=False)

        assert 0 <= idx <= self._in_ports, 'Invalid input port number'
        return self._in_wgs[idx].current_port

    def get_out_port(self, idx):
        if not self._out_wgs:
            self._calculate(do_in_wgs=False, do_out_wgs=True)

        assert 0 <= idx <= self._out_ports, 'Invalid input port number'
        return self._out_wgs[idx].current_port

    def get_dlw_in_port(self, idx):
        if not self._in_wgs:
            self._calculate(do_in_wgs=True, do_out_wgs=False)

        assert 0 <= idx <= self._in_ports, 'Invalid input port number'
        return self._in_wgs[idx].in_port

    def get_dlw_out_port(self, idx):
        if not self._out_wgs:
            self._calculate(do_in_wgs=False, do_out_wgs=True)

        assert 0 <= idx <= self._out_ports, 'Invalid input port number'
        return self._out_wgs[idx].in_port

    @property
    def in_ports(self):
        return list((self.get_in_port(idx) for idx in range(self._in_ports)))

    @property
    def out_ports(self):
        return list((self.get_out_port(idx) for idx in range(self._out_ports)))

    @property
    def dlw_in_ports(self):
        return list((self.get_dlw_in_port(idx) for idx in range(self._in_ports)))

    @property
    def dlw_out_ports(self):
        return list((self.get_dlw_out_port(idx) for idx in range(self._out_ports)))

    @property
    def marker_positions(self):
        center_port = Port(self._origin, self._angle, 1.)

        angle = max((2 + max(self._in_ports, self._out_ports)) / 2. * self._angular_spacing, np.pi / 4)
        radius = max(self._radius, 40)
        return [center_port.rotated(angle).longitudinal_offset(radius).origin,
                center_port.rotated(angle).longitudinal_offset(-radius).origin,
                center_port.rotated(-angle).longitudinal_offset(radius).origin,
                center_port.rotated(-angle).longitudinal_offset(-radius).origin]

    def get_shapely_object(self):
        if not self._in_wgs or not self._out_wgs:
            self._calculate(do_in_wgs=True, do_out_wgs=True)

        markers = [DLWMarker(pos) for pos in self.marker_positions]

        return geometric_union(self._out_wgs + self._in_wgs + markers)

def _example():
    import gdsCAD.core
    from gdshelpers.geometry import convert_to_gdscad
    from gdshelpers.parts.waveguide import Waveguide

    mpsv2 = MultiPortSwitch(origin=[0, 0],
                            angle=np.deg2rad(0.),
                            in_ports=4, out_ports=7,
                            port_spacing=10,
                            taper_length=40, taper_function=lambda t: t * (1.0 - 0.05) + 0.05,
                            radius=50., displacement=0.,
                            wg_bend_radius=40., minimal_final_spacing=20)

    wg = Waveguide([100, 100], np.pi / 4, 1)
    wg.add_straight_segment(100)

    # mpsv2_2 = MultiPortSwitch.make_at_out_port(wg.current_port, 3,
    #                                            in_ports=2, out_ports=7,
    #                                            port_spacing=10,
    #                                            taper_length=10, taper_function=lambda t: t * (1.0 - 0.05) + 0.05,
    #                                            radius=50., displacement=00.,
    #                                            wg_bend_radius=40., )

    cell = gdsCAD.core.Cell('TEST')
    cell.add(convert_to_gdscad([mpsv2, wg, ]))
    cell.show()

if __name__ == '__main__':
    _example()


unique_element = set()  # to create empty set need to do set() if you do empty {} type gonna be dic

unique_element.add(10)
unique_element.add(10)
unique_element.add(10)
unique_element.add(20)
unique_element.add(20)
# set avoid duplicate => so the result is going to be 2 element
print(type(unique_element))
print(unique_element)

# print(unique_element[1]) set does not have index number

# print( unique_element[1:] ) because no index number you can not slice it too

unique_element.remove(10)

print(unique_element)

unique_element.update((1, 2, 3, 4, 5, 1, 2, 3, 4, 5))  # ONLY uniq one will add at the same time too

# print( help(set.update) )

print(unique_element)

n = unique_element.pop()  # pop remove the first element

print(unique_element)

print(n)

# print( help( str.istitle ) )

print('-------------difference-----------------------')

# difference(): compares two sets and returns a new set which contains the items that only exist in first set
s1 = {'Java', 'Python', 'C#'}
s2 = {'Ruby', 'Java', 'C++', 'Swift'}

s3 = s1.difference(s2)

print(s3)

print('----------------------intersection-------------------')

# intersection(): compares two sets and returns a new set which contains the common elements of two sets
set1 = {'Java', 'Python', 'C#', 'Cydeo'}
set2 = {'C++', 'Ruby', 'Swift', 'Java', 'Python'}

set3 = set1.intersection(set2)

print(set3)

print('------------------different_update-------------------')

# different_update(): removes the elements of the first Set that exist in the second Set
a1 = {'Book', 'Pen', 'Apple', 'Cherry', 'Coffee'}
a2 = {'Book', 'Apple', 'Banana', 'Grape', 'TV'}

a1.difference_update(a2)
print(a1)

print('---------------intersection_update----------------------')

# intersection_update(): removes the uncommon elements of first & second sets
b1 = {'Cydeo', 'Python', 'Java', 'C#', 'Wooden Spoon', 'Ruby', 'Swift'}
b2 = {'Wooden Spoon', 'Python', 'Cydeo'}

b1.intersection_update(b2)

print(b1)

print('------------------symmetric_update-------------------')

# symmetric_difference(): Compares two sets and returns a new set which contains all elements except the common once
e1 = {'Apple', 'Banana', 'Cherry'}
e2 = {'Grape', 'Strawberry', 'Banana', 'Mango', 'Lemon', 'Apple'}

e3 = e1.symmetric_difference(e2)

print(e3)


#!/usr/bin/python3
''' Say my name '''

def say_my_name(first_name, last_name=""):
    ''' Function that concatenate two strings. '''
    '''
    print(first_name + last_name)
    print(type(first_name))
    print(not isinstance(first_name, str))
    print(not isinstance(last_name, str))
    '''

    if not isinstance(first_name, str):
        raise TypeError('first_name must be a string')
    if not isinstance(last_name, str):
        raise TypeError('last_name must be a string')
    space = ' '
    print('My name is {}{}{}'.format(first_name, space, last_name))


# Implement binary search.

def binary_search(lists, num):
    begin, end = 0, len(lists)
    while begin <= end:
        mid = (begin + end) // 2
        if lists[mid] == num:
            return mid
        elif lists[mid] > num:
            end = mid - 1
        elif lists[mid] < num:
            begin = mid + 1
    return 'N/A'

# test
li = [1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
n = 21
print('The number is present at index: ', binary_search(li, n))


from abilities import *
from map import *
from races import *

def fight(player1, player2):
    player1.calcAbilities(player2)
    player2.calcAbilities(player1)
    player1.attack(player2)
    player2.attack(player1)
    player1.takeDmg()
    player2.takeDmg()

    if player2.isDead == True:
        player1.xp(player2.lvl)

    if player1.isDead == True:
        player2.xp(player1.lvl)

def checkWiz(playerList):
    for i in range(len(playerList)):
        if playerList[i].char == "W":
            for k in range(len(playerList)):
                if k != i:
                    playerList[k].calcAbilities(playerList[i])

def checkDebuff(playerList):
    for p in range(len(playerList)):
        playerList[p].stunCount -= 1

        if playerList[p].DoTCount != 0:
            playerList[p].dotted()

        if playerList[p].stunCount == 0:
            playerList[p].isStun = False

tiles.generate()

p2 = pyromancer(2, 0)
p1 = wizard(2, 2)
p3 = knight(3, 0)
p4 = rogue(3, 0)

r = 1

players = [p1, p2, p3, p4]

while r != 0:

    checkDebuff(players)

    checkWiz(players)

    for i in range(len(players)):
        for j in range(i + 1, len(players)):
            if players[i].playerPosition() == players[j].playerPosition():
                if players[i].isDead == False and players[j].isDead == False:
                    fight(players[i], players[j])

    r -= 1

p1.showStats()
p2.showStats()
p3.showStats()
p4.showStats()


n = input()
line = list(map(int,input().split()))

order = [1]

for i in range(int(n)-1):
    line[i] = (line[i], i+2)

line.sort()

for i in range(int(n)-1):
    order.append(line[i][1])

for i in order:
    print(i, end = ' ')


def main():
    N, M, K = map(int, input().split())
    seats = [input() for _ in range(N)]
    cnt = 0
    for seat in seats:
        for i in range(M-K+1):
            if seat[i:i+K] == '0' * K:
                cnt += 1
    print(cnt)

if __name__ == "__main__":
    main()

BOJ_Contest/제3회 숙명여자대학교 프로그래밍 경진대회 (SMUPC) Open Contest/B-우당탕탕 영화예매.py

B-우당탕탕 영화예매.py


import copy
from collections import defaultdict

day_num = 19

file_load = open("input/day19.txt", "r")
file_prep = file_load.read()
file_load.close()

file_in = [defaultdict(list), []]
file_prep = [temp_itr.strip('\n') for temp_itr in file_prep.split("\n\n")]
for temp_rule in file_prep[0].replace("\"", "").split("\n"):
	rule_num, rule_parts = temp_rule.split(": ")
	for temp_part in rule_parts.split(" | "):
		if temp_part in ["a", "b"]:
			file_in[0][int(rule_num)] = temp_part
		else:
			file_in[0][int(rule_num)].append(list(eval(temp_itr) for temp_itr in temp_part.split()))
file_in[1] = file_prep[1].split("\n")

def run():

	def itr(input_in, input_rul, input_str):
		if not input_rul:
			return len(input_str) == 0
		rule_check = input_in[0][input_rul.pop(0)]
		if rule_check in ["a", "b"]:
			return input_str.startswith(rule_check) and itr(input_in, input_rul, input_str[1:])
		else:
			return any(itr(input_in, temp_rule + input_rul, input_str) for temp_rule in rule_check)

	def rule(input_in, input_adjust):
		if input_adjust:
			input_in[0][8] = [[42], [42, 8]]
			input_in[0][11] = [[42, 31], [42, 11, 31]]
		return sum(itr(input_in, [0], temp_line) for temp_line in input_in[1])

	return rule(file_in, False), rule(file_in, True)

if __name__ == "__main__":
	print(run())


"""Sample PyTorch Inference script
"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import os
import time
import argparse
import numpy as np
import torch

from models import create_model, apply_test_time_pool
from data import Dataset, create_loader, resolve_data_config
from utils import AverageMeter

torch.backends.cudnn.benchmark = True

parser = argparse.ArgumentParser(description='PyTorch ImageNet Inference')
parser.add_argument('data', metavar='DIR',
                    help='path to dataset')
parser.add_argument('--output_dir', metavar='DIR', default='./',
                    help='path to output files')
parser.add_argument('--model', '-m', metavar='MODEL', default='dpn92',
                    help='model architecture (default: dpn92)')
parser.add_argument('-j', '--workers', default=2, type=int, metavar='N',
                    help='number of data loading workers (default: 2)')
parser.add_argument('-b', '--batch-size', default=256, type=int,
                    metavar='N', help='mini-batch size (default: 256)')
parser.add_argument('--img-size', default=224, type=int,
                    metavar='N', help='Input image dimension')
parser.add_argument('--mean', type=float, nargs='+', default=None, metavar='MEAN',
                    help='Override mean pixel value of dataset')
parser.add_argument('--std', type=float, nargs='+', default=None, metavar='STD',
                    help='Override std deviation of of dataset')
parser.add_argument('--interpolation', default='', type=str, metavar='NAME',
                    help='Image resize interpolation type (overrides model)')
parser.add_argument('--num-classes', type=int, default=1000,
                    help='Number classes in dataset')
parser.add_argument('--print-freq', '-p', default=10, type=int,
                    metavar='N', help='print frequency (default: 10)')
parser.add_argument('--checkpoint', default='', type=str, metavar='PATH',
                    help='path to latest checkpoint (default: none)')
parser.add_argument('--pretrained', dest='pretrained', action='store_true',
                    help='use pre-trained model')
parser.add_argument('--num-gpu', type=int, default=1,
                    help='Number of GPUS to use')
parser.add_argument('--no-test-pool', dest='no_test_pool', action='store_true',
                    help='disable test time pool')

def main():
    args = parser.parse_args()

    # create model
    model = create_model(
        args.model,
        num_classes=args.num_classes,
        in_chans=3,
        pretrained=args.pretrained,
        checkpoint_path=args.checkpoint)

    print('Model %s created, param count: %d' %
          (args.model, sum([m.numel() for m in model.parameters()])))

    config = resolve_data_config(model, args)
    model, test_time_pool = apply_test_time_pool(model, config, args)

    if args.num_gpu > 1:
        model = torch.nn.DataParallel(model, device_ids=list(range(args.num_gpu))).cuda()
    else:
        model = model.cuda()

    loader = create_loader(
        Dataset(args.data),
        input_size=config['input_size'],
        batch_size=args.batch_size,
        use_prefetcher=False,
        interpolation=config['interpolation'],
        mean=config['mean'],
        std=config['std'],
        num_workers=args.workers,
        crop_pct=1.0 if test_time_pool else config['crop_pct'])

    model.eval()

    batch_time = AverageMeter()
    end = time.time()
    top5_ids = []
    with torch.no_grad():
        for batch_idx, (input, _) in enumerate(loader):
            input = input.cuda()
            labels = model(input)

            top5 = labels
            # top5 = labels.topk(5)[1]
            # top5 = top5+1

            top5_ids.append(top5.cpu().numpy())

            # measure elapsed time
            batch_time.update(time.time() - end)
            end = time.time()

            if batch_idx % args.print_freq == 0:
                print('Predict: [{0}/{1}]\t'
                      'Time {batch_time.val:.3f} ({batch_time.avg:.3f})'.format(
                    batch_idx, len(loader), batch_time=batch_time))

    top5_ids = np.concatenate(top5_ids, axis=0).squeeze()

    with open(os.path.join(args.output_dir, './p10.csv'), 'w') as out_file:
        # out_file.write('image,category\n')
        out_file.write('image,l1,l2,l3,l4,l5\n')
        filenames = loader.dataset.filenames()
        for filename, label in zip(filenames, top5_ids):
            filename = os.path.basename(filename)
            out_file.write('{0},{1},{2},{3},{4},{5}\n'.format(
                filename, label[0],label[1],label[2],label[3],label[4]))
            # out_file.write('{0},{1}\n'.format(
            #     filename, label[0]))

if __name__ == '__main__':
    main()


#!/bin/env python
#-*- encoding=utf8 -*-

class GlobalConfig(object):

    """ 商店业务的全局配置
    """
    THUMB_PIC_SWITCH = 0          # 缩略图开关
    UPDATE_CHECK_RATE = 60 * 6    # 应用升级检测频率

class BsConst(object):

    """ 业务相关的常量
    """
    CACHE_SPLITE = "$$"                                     # 缓存版本分隔符
    CACHE_VER_LENGTH = 14                                   # 缓存版本长度:20140101101010

    APPLIST_LENGTH = 500                                    # 列表的长度

class CacheInfo(object):

    """ 缓存名定义
    """
    __api_cache_prefix = "apps_api:"
    __api_private_cache_prefix = "apps_api_private:"
    __bg_cache_prefix = "apps:"

    SERI_PREFIX = __api_cache_prefix + "seri:"                      # 序列化后的缓存前缀
    API_SRC_PREFIX = __api_cache_prefix + "src:"                    # 接口生成的源缓存前缀
    API_PRIVATE_SRC_PREFIX = __api_private_cache_prefix + "src:"    # 接口生成的私有源缓存前缀
    BG_SRC_PREFIX = __bg_cache_prefix + ""                          # 后台生成的源缓存前缀

class ElemTypeEnum(object):

    """ 元素类型
    """
    APP = 1             # 应用
    LINK = 2            # 链接
    JUMP2CALSS = 3      # 跳转到分类
    JUMP2GAME = 4       # 跳转到网游单机
    JUMP2SUBJECT = 5    # 跳转到专题
    SEARCH_WORD = 6      # 搜索词
    FLASH_PIC = 7           # 闪屏图

class GroupClassEnum(object):

    """ 分组类别
    """
    APP_GAME = 10
    APP = 11
    GAME = 12
    OLGAME_SINGLEGAME = 21
    SUBJECT = 31
    GAME_SUBJECT = 32
    RECOMM = 41
    DISTRIBUTE = 51

    # 只能后台配置的数据
    ONLY_FOR_CONFIG = (SUBJECT, GAME_SUBJECT, RECOMM, DISTRIBUTE)
    # 可自动，又可后台配置控制的数据
    CONTROLLABLE = (APP_GAME, APP, GAME, OLGAME_SINGLEGAME)

class GroupTypeEnum(object):

    """ 分组类别
    """
    ALL_APP_GAME = 1000
    RISE_FASTER_APP_GAME = 1001

    ALL_APP = 1100

    ALL_GAME = 1200

    OL_GAME = 2101
    SINGLE_GAME = 2102

    DEFAULT_SUBJECT = 3100
    ESSENTIAL_GAME_SUBJECT = 3101       # 必备游戏
    ESSENTAIL_SUBJECT = 3102            # 必备应用游戏

    START_RECOMM = 4101
    FIRST_PAGE_RECOMM_4_GAME =4102
    RECOMM_GAME_4_SEARCH = 4103
    RECOMM_SEARCH_WORD = 4104
    FLASH_RECOMM = 4105
    FIRST_PAGE_RECOMM_4_APPGAME = 4106
    QUALITY_APP_RECOMM = 4107
    QUALITY_GAME_RECOMM = 4108
    AVOID_FLOW_RECOMM_APPGAME = 4109

    LAUNCHER_DISTRI = 5101

class DBIsNetGameEnum(object):

    """ 是否网游
    """
    NET_GAME = 1
    SINGLE_GAME =2

class DBOrderTypeEnum(object):

    """ 排序类型
    """
    AUTO = 0
    UPDATE_TIME = 2

class ApiSeriCacheName(object):

    """ 接口生成的序列化后的缓存
    """
    SERI_APPS_CONFIG = CacheInfo.SERI_PREFIX + "appsconfig:%s"                  # 序列化后的全局配置缓存,参数:schemeid
    SERI_GROUP_ELEMS = CacheInfo.SERI_PREFIX + "groupelems:%s_%s_%s"            # 序列化后的分组元素缓存,参数:groupid_pagesize_pageindex
    SERI_APP_INFO = CacheInfo.SERI_PREFIX + "appinfo:%s"                        # 序列化后的应用信息缓存,参数:appid

    # 支持渠道分发应用后，新的缓存结构,(2015.12.23修改，增加架构支持)
    SERI_CHNNO_GROUP_ELEMS = CacheInfo.SERI_PREFIX + "groupelems:%s:%s:%s_%s_%s"   # 序列化后的分组元素缓存,参数:architecture:chnno:groupid_pagesize_pageindex

class BGSrcCacheName(object):

    """ 后台生成的缓存源
    """
    GROUP_SCHEME = CacheInfo.BG_SRC_PREFIX + "sGroupScheme:%s"          # 分组方案,参数:schemeid
    GROUP_INFO = CacheInfo.BG_SRC_PREFIX + "hGroupInfo:%s"              # 分组信息,参数:groupid
    GROUP_ELEM_KEY = CacheInfo.BG_SRC_PREFIX + "ssGroupElemKey:%s"      # 分组元素Key,参数:groupid,返回Val:[groupelemid]_[elemtype]_[elemid]_[posid]
    GROUP_ELEM = CacheInfo.BG_SRC_PREFIX + "hGroupElems:%s_%s"          # 分组元素,参数:groupid_groupelemid_elemtype_elemid
    LINK_INFO = CacheInfo.BG_SRC_PREFIX + "hLinkInfo:%s"                # 外链信息，参数:linkid
    NEWEST_APP = CacheInfo.BG_SRC_PREFIX + "hNewestAppVer:%s_%s"        # 最新应用信息:参数:packname_md5(signcode)
    CHNNOLIST = CacheInfo.BG_SRC_PREFIX + "lChnnoList"                  # 上线应用配置的分发渠道汇总列表。

    class GroupInfoField(object):

        """ 分组信息字段
        """
        group_id = 'gid'
        group_class = 'gclass'
        group_type = 'gtype'
        order_type = 'odtype'
        order_no = 'odno'
        group_tips = 'gtips'
        group_name = 'gname'
        group_desc = 'gdesc'
        group_pic_url = 'gpic'
        start_time = 'stime'
        end_time = 'etime'
        type_pic_url = 'tpic'
        # create_time = 'ctime'
        # update_time = 'utime'

    class GroupElemField(object):

        """ 分组元素字段
        """
        group_elem_id = "geid"
        group_id = "gid"
        pos_id = "posid"
        elem_type = "etype"
        elem_id = "eid"
        show_type = "stype"
        group_type = "gtype"
        order_type = "otype"
        order_no = "ono"
        recomm_val = "rval"
        recomm_title = "rtitle"
        recomm_word = "rword"
        recomm_pic_url = "rpic"
        recomm_tag = "rmtag" # 推荐角标(recommFlag)
        remarks = "rmks"
        start_time = "stime"
        end_time = "etime"
        create_time = "etime"
        update_time = "utime"

    class LinkInfoField(object):

        """外链字段
        """
        link_id = 'lid'
        cp_id = 'cpid'
        dev_name = 'dname'
        link_name = 'lname'
        show_name = 'sname'
        link_url = 'lurl'
        icon_url = 'iurl'
        coop_type = 'ctype'
        link_tag = 'ltag'
        link_desc = 'ldesc'
        remarks = 'rmks'
        create_time = 'ctime'
        update_time = 'utime'

    class NewestAppVerField(object):
        """ 最新应用版本字段
        """
        appid = 'appid'
        packid = 'packid'
        version_name = 'vname'
        version_code = 'vcode'
        app_class = 'aclass'
        pack_name = 'pname'

class APISrcCacheName(object):

    """ 接口生成的缓存源
    """
    APP_INFO = CacheInfo.API_SRC_PREFIX + "hAppInfo:%s"                     # 应用信息,参数:appid
    APP_DOWN_COUNT = CacheInfo.API_PRIVATE_SRC_PREFIX + "hAppDowntimes:%s"  # 应用下载成功次数,参数:appid
    MATCH_GROUPID = CacheInfo.API_SRC_PREFIX + "matchGroupID:%s_%s_%s_%s"   # 匹配分组id,参数:schemeid_groupclass_grouptype_ordertype

    class AppInfoField(object):

        """ 应用信息字段
        """
        appid = 'appid'
        packid = 'packid'
        show_name = 'soname'
        pack_name = 'pkname'
        sign_code = 'sgcode'
        dev_name = 'devname'
        app_class = 'aclass'
        app_type = 'atype'
        down_times = 'dwtimes'
        comment_times = 'cmtimes'
        comment_score = 'cmscore'
        app_tag_flag = 'apptag'
        recomm_level = 'rmlevel'
        recomm_flag = 'rmflag'
        recomm_word = 'rmword'
        thumb_url = 'tmurl'
        icon_url = 'icurl'
        app_pic_url = 'picurl'
        pack_url = 'pkurl'
        pack_url2 = 'pkurl2'
        pack_md5 = 'pkmd5'
        part_md5 = 'ptmd5'
        pack_size = 'pksize'
        ver_code = 'vcode'
        ver_name = 'vname'
        comp_desc = 'cmdesc'
        lan_desc = 'landesc'
        app_desc = 'appdesc'
        update_desc = 'upddesc'
        publish_time = 'pbltime'
        search_keys = 'shkeys'
        app_type_name = 'atname'
        issue_type = 'issuetype'
        channelnos = 'chnnos'
        channel_adaptation = 'chnadapt'
        permission = 'permission'
        architecture = 'archit'

class APISrcCommentCacheName(object):

    """ 评论及评分的接口生成的缓存源
    """
    # 新增时间: 2015-09-07
    APP_WAITAUDIT_CACHE = CacheInfo.API_SRC_PREFIX+'comments:waitaudit:hash' # 待审核的评论缓存
    APP_PASSED_CACHE = CacheInfo.API_SRC_PREFIX+'comments:passed:%s'         # Hash 审核通过的评论缓存 %appId
    APP_SCORE_CACHE = CacheInfo.API_SRC_PREFIX+'comments:score:%s'           # 应用的评分缓存
    APP_COMMENT_ID = CacheInfo.API_SRC_PREFIX+'comment:id'                   # 保存评论ID的缓存

class ApiSeriRecommCacheName(object):

    """ 应用推荐接口生成的序列化后的缓存
    """

    # 新增 2015-09-07
    SERI_RECOMMEND_INFO = CacheInfo.SERI_PREFIX + "recommend:%s:%s:%s"      # 序列化后的应用推荐信息缓存,参数 architecture:chnno:appid

class APISrcInformCacheName(object):

    """ 应用举报次数的缓存
    """

    # 新增 2015-09-07
    APP_INFORM_COUNT_CACHE = CacheInfo.API_SRC_PREFIX + "appinform"                        # 序列化后的应用推荐信息缓存,参数:appid


"""
Profiling calculation
=====================

.. start-body
"""

import chemfiles

import rascaline
from rascaline import SoapPowerSpectrum

def compute_soap(path):
    """Compute SOAP power spectrum.

    This is the same code as the 'compute-soap' example
    """
    with chemfiles.Trajectory(path) as trajectory:
        frames = [f for f in trajectory]

    HYPER_PARAMETERS = {
        "cutoff": 5.0,
        "max_radial": 6,
        "max_angular": 4,
        "atomic_gaussian_width": 0.3,
        "center_atom_weight": 1.0,
        "radial_basis": {
            "Gto": {},
        },
        "cutoff_function": {
            "ShiftedCosine": {"width": 0.5},
        },
    }

    calculator = SoapPowerSpectrum(**HYPER_PARAMETERS)
    descriptor = calculator.compute(frames, gradients=["positions"])
    descriptor = descriptor.keys_to_samples("species_center")
    descriptor = descriptor.keys_to_properties(
        ["species_neighbor_1", "species_neighbor_2"]
    )

    return descriptor

# %%
#
# Run the calculation with profiling enabled.

with rascaline.Profiler() as profiler:
    descriptor = compute_soap("dataset.xyz")
# %%
#
# Display the recorded profiling data as table.

print(profiler.as_short_table())

# %%
#
# You can also save this data as json for future usage
print(profiler.as_json())

# %%
#
# .. end-body


from typing import Callable

from authelio_sdk.client import Client
from authelio_sdk.models.group import Group

def test_FUNC_client_group_filter_WITH_new_group_EXPECT_new_group_found(
        sdk_client: Client,
        group_function: Callable[..., Group]
) -> None:
    """
    Test whether filter function works as expected.

    :param sdk_client: Authelio SDK client.
    :param group_function: Function, that creates group entity.

    :return: No return.
    """
    # Create some groups for filtering.
    group_ids = [group_function().group_id for _ in range(5)]

    filtered_groups, next_page_id = sdk_client.group.filter()

    filtered_group_ids = list(filtered_groups.keys())

    assert all(group_id in filtered_group_ids for group_id in group_ids)


# -*- coding: utf-8 -*-
"""
Created on Fri Dec 20 19:30:11 2019

@author: Ken
"""

import pandas as pd
import matplotlib.pyplot as plt
df_noref = pd.read_csv('data_final_no_refs.csv')
df_ref = pd.read_csv('data_final_refs.csv')
df_ref['constant'] =1

df_ref['line_movement'] = df_ref.line_close - df_ref.line_open
df_ref['OU_movement'] = df_ref.OU_close - df_ref.OU_open
df_ref.dropna(inplace=True)
for i in df_ref.columns:
    print("'"+i+"'"+',')

#simple linear regression for year
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, mean_absolute_error
import math

#multiple linear regression
from statsmodels.stats.outliers_influence import variance_inflation_factor
import statsmodels.api as sm

#actual regression
X3 = pd.get_dummies(df_ref[['constant',
                                'b2b_home',
                                'threein4_home',
                                'fourin5_home',
                                'rest2_home',
                                'rest3_plus_home',
                                'b2b_away',
                                'threein4_away',
                                'fourin5_away',
                                'rest2_away',
                                'rest3_plus_away',
                                'away_traveled',
                                'time_diff',
                                'home_ML',
                                'home_2H',
                                'away_ML',
                                'away_2H',
                                'OU_open',
                                'OU_close',
                                'line_open',
                                'line_close',
                                'OU_2H',
                                'line_2H',
                                'line_movement',
                                'OU_movement']])

y3 = df_ref.actual_score.values

X_train3, X_test3, y_train3, y_test3 = train_test_split(X3, y3, test_size=0.3, random_state=0)

reg_sm3 = sm.OLS(y_train3, X_train3).fit()
reg_sm3.summary()

y_hat3 = reg_sm3.predict(X_test3)

rmse3 = math.sqrt(mean_squared_error(y_hat3,y_test3))

plt.scatter(y_hat3,y_test3)

from statsmodels.stats.outliers_influence import variance_inflation_factor

# get refs
X3 = df_ref[['constant',
                                'b2b_home',
                                'threein4_home',
                                'fourin5_home',
                                'rest2_home',
                                'rest3_plus_home',
                                'b2b_away',
                                'threein4_away',
                                'fourin5_away',
                                'rest2_away',
                                'rest3_plus_away',
                                'away_traveled',
                                'time_diff',
                                'home_ML',
                                #'home_2H',
                                'away_ML',
                                #'away_2H',
                                'OU_open',
                                #'OU_close',
                                'line_open',
                                #'line_close',
                                'OU_2H',
                                'line_2H',
                                'line_movement',
                                'OU_movement']]

y3 = df_ref.actual_score.values

X_train3, X_test3, y_train3, y_test3 = train_test_split(X3, y3, test_size=0.3, random_state=0)

reg_sm3 = sm.OLS(y_train3, X_train3).fit()
reg_sm3.summary()

y_hat3 = reg_sm3.predict(X_test3)

rmse3 = math.sqrt(mean_squared_error(y_hat3,y_test3))

plt.scatter(y_hat3,y_test3)

pd.Series([variance_inflation_factor(X3.values,i) for i in range(X3.shape[1])],index=X3.columns)

from sklearn.ensemble import RandomForestRegressor

rf = RandomForestRegressor(n_estimators = 300)
rf.fit(X_train3,y_train3)
ypred_rf = rf.predict(X_test3)
rf.score(X_test3,y_test3)

#withrefs
X = df_ref.drop(['Unnamed: 0','date','away_team','home_team','actual_score','line_2H',
                'OU_2H','line_open','line_close','OU_close','away_ML','away_2H','home_2H','home_ML','away_Final','home_Final'], axis=1)

Y = df_ref.actual_score.values
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.3, random_state=0)

reg_sm3 = sm.OLS(y_train, X_train).fit()
reg_sm3.summary()

#cross validation 5 fold
from sklearn.model_selection import cross_val_score
import numpy as np
reg4 = LinearRegression().fit(X_train3, y_train3)
reg4.score(X_test3,y_test3)

reg4 = LinearRegression()
scores = cross_val_score(reg4,X3,y3, cv=5, scoring = 'neg_mean_squared_error')
np.sqrt(np.abs(scores))


import os
import json

BASE_DIR = os.path.expanduser('~/.suicarecorder')

FILE_PATH = os.path.join(BASE_DIR, 'config.json')

DEFAULTS = {
    'output_dir': BASE_DIR
}

class Config(dict):
    def __init__(self, file_path=FILE_PATH):
        self.file_path = file_path
        self._dict = None

    @property
    def dict(self):
        if not self._dict:
            if os.path.isfile(self.file_path):
                with open(self.file_path, 'r') as f:
                    self._dict = json.load(f, 'utf-8')
            else:
                self._dict = {}
        return self._dict

    def normalize_value(self, key, value):
        if key == 'output_dir':
            return os.path.expanduser(value)
        else:
            return value

    def load(self):
        for k, v in self.dict.items():
            _v = self.normalize_value(k, v)
            self.__setitem__(k, _v)

        return self

    def get(self, key):
        return dict.get(self, key, DEFAULTS.get(key))

_CONFIGS = {}

def get(key, config_file_path=None):
    file_path = config_file_path or FILE_PATH
    if not _CONFIGS.get(file_path):
        _CONFIGS[file_path] = Config(file_path).load()
    return _CONFIGS[file_path].get(key)


from django.urls import path
from .import views as app_views
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('',app_views.index,name='index'),
    path('add_todo',app_views.add_todo,name='add_todo'),
    path('update_todo/<int:todo_id>', app_views.update_todo,name='update_todo'),
    path('delete_todo/<int:todo_id>', app_views.delete_todo,name='delete_todo'),
    path('todo_details/<int:todo_id>',app_views.todo_details,name='todo_details'),
    path('search',app_views.search,name='search'),

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


#URLify

def URLify(testString, length):
    return testString.strip().replace(" ", "%20")
print(URLify("Mr John Smith ", 13))

#
def URLify2(testString, length):
    space = " "
    replacement = "%20"
    replaceString = []
    lastChar = 0
    numSpace = 0
    #Trim last few spaces
    for x in range(len(testString)-1, 0, -1):
        if testString[x] != space:
            lastChar = x
            break
    #lastChar is last character without space
    for x in range(0, lastChar):
        if testString[x] == space:
            numSpace+=1
    replaceString = [""]*(length + 2*numSpace)
    index = len(replaceString)-1
    while lastChar >= 0:
        if testString[lastChar] != space:
            replaceString[index] = testString[lastChar]
            index-=1
            lastChar-=1
            continue
        replaceString[index] = "0"
        replaceString[index-1] = "2"
        replaceString[index-2] = "%"
        index-=3
        lastChar-=1
    return "".join(replaceString)
print(URLify2("Mr John Smith ", 13))

Python practice/CrackingCodePractice/String and Array/Q3.py


# Works on gyrus (ANNarchy 4.6.2)

from ANNarchy import *
import pylab as plt
import numpy as np
import random
from timeit import default_timer as timer
import sys
import scipy.optimize as sciopt
import scipy.stats as st

from fit_arky_params import read_arky_data, read_arky_data_Bogacz2016

def mean_response_rate(poprate, tot_trials, simsteps, dt):
    mean_response = plt.zeros(tot_trials)
    for trial in range(tot_trials):
        ti_last_in_trial = int( min(simsteps, (trial+1) / float(tot_trials) * simsteps - 1) )
        ti_last100ms_firstind = int( ti_last_in_trial - 100.0 / dt + 1 )
        mean_response[trial] = poprate[ti_last100ms_firstind : ti_last_in_trial].mean()
    return mean_response

def raster_rate_plot(mon, spdata, popname, subplot_idx, rate_color, Tsmooth_ms, maxrate, fs):
    mon_te, mon_ne = mon.raster_plot(spdata)
    fr_mon = mon.population_rate(spdata, smooth=Tsmooth_ms)
    ax_wrapper = []
    ax_wrapper.append(plt.subplot(subplot_idx))
    plt.plot(mon_te, mon_ne, 'k.')
    plt.ylabel(popname + ' neuron index', fontsize=fsize)
    plt.xlabel('t [ms]', fontsize=fsize)
    ax3 = plt.gca()
    for label in ax3.get_xticklabels() + ax3.get_yticklabels():
        label.set_fontsize(fs)
    ax_wrapper.append(ax_wrapper[0].twinx())
    plt.plot(timesteps, fr_mon, lw=2, color=rate_color)
    plt.ylabel(popname + ' firing rate [spk/s]', color=rate_color, fontsize=fsize)
    ax_twin = plt.gca()
    for label in ax_twin.get_yticklabels():
        label.set_color(rate_color)
        label.set_fontsize(fs)
    ax_twin.axis([ax_twin.axis()[0], ax_twin.axis()[1], ax_twin.axis()[2], maxrate])
    plt.title(popname + ' responses to step currents', fontsize=1.2*fsize)

def plot_vm_traces(gpe_vdata, arky_vdata, length_ms, dt, fs, i_gpe_fig, i_arky_fig, I_arky=[], i_trial_arky=0):
    fs=fs+2
    #plt.subplot(i_gpe_fig)
    ax_wrapper = []
    ax_wrapper.append(plt.subplot(i_gpe_fig))
    end = int(length_ms / dt)
    #plt.plot(timesteps[i_trial * end : (i_trial+1) * end], gpe_vdata[i_trial * end : (i_trial+1) * end, 0], 'b', lw=0.5)
    #plt.plot(timesteps[0:end], gpe_vdata[0:end, 0], 'b', lw=0.5)
    t_init = timesteps[i_trial_arky * end]
    plt.plot(timesteps[i_trial_arky * end : (i_trial_arky+1) * end] - t_init, gpe_vdata[i_trial_arky * end : (i_trial_arky+1) * end, 0], color=np.array([3,67,223])/255., lw=0.5)
    print('Proto vm min = ', min(gpe_vdata[i_trial_arky * end : (i_trial_arky+1) * end, 0]))
    print('Arky vm min = ', min(arky_vdata[i_trial_arky * end : (i_trial_arky+1) * end, 0]))
    ax5 = plt.gca()
    plt.xlabel('t [ms]', fontsize=fs)
    plt.ylabel('v [mV]', fontsize=fs)
    plt.title('GPe-Proto voltage traces', fontsize=1.2*fs)
    ax5.axis([ax5.axis()[0], ax5.axis()[1], -100, 40]) #  -80
    ax5.set_yticks(range(-100, 45, 20)) # -80
    #ax5.set_yticklabels(['-80', '', '-60', '', '-40', '', '-20', '', '0', '', '20', '', '40'])

    if len(I_arky) > 0:
        ax_wrapper.append(ax_wrapper[0].twinx())
        plt.plot(timesteps[0:end], I_arky, lw=2, color='0.5')
        ax_twin = plt.gca()
        plt.ylabel('Injected current', color='0.5')
        ax_twin.axis([ax_twin.axis()[0], ax_twin.axis()[1], ax_twin.axis()[2], 1.0])
        for label in ax_twin.get_yticklabels():
            label.set_color('0.5')

    ax_wrapper = []
    ax_wrapper.append(plt.subplot(i_arky_fig))
    #plt.subplot(i_arky_fig)
    #plt.plot(timesteps[0:end], arky_vdata[0:end, 0], 'r', lw=0.5)
    t_init = timesteps[i_trial_arky * end]
    plt.plot(timesteps[i_trial_arky * end : (i_trial_arky+1) * end] - t_init, arky_vdata[i_trial_arky * end : (i_trial_arky+1) * end, 0], color=np.array([0,255,255])/255., lw=0.5)
    ax6 = plt.gca()
    plt.xlabel('t [ms]', fontsize=fs)
    plt.ylabel('v [mV]', fontsize=fs)
    vmin = min(ax5.axis()[2], ax6.axis()[2])
    vmax = max(ax5.axis()[3], ax6.axis()[3])
    #ax5.axis([ax5.axis()[0], ax5.axis()[1], vmin, vmax])
    #ax6.axis([ax6.axis()[0], ax6.axis()[1], vmin, vmax])
    ax6.axis([ax5.axis()[0], ax5.axis()[1], -100, 40])
    ax6.set_yticks(range(-100, 45, 20)) # , 10

    plt.title('GPe-Arky voltage traces', fontsize=1.2*fs)
    if len(I_arky) > 0:
        ax_wrapper.append(ax_wrapper[0].twinx())
        #plt.plot(timesteps[0:end], I_arky, lw=2, color='0.5')
        plt.plot(timesteps[i_trial_arky * end : (i_trial_arky+1) * end], I_arky, lw=2, color='0.5')
        ax_twin = plt.gca()
        plt.ylabel('Injected current', color='0.5')
        ax_twin.axis([ax_twin.axis()[0], ax_twin.axis()[1], ax_twin.axis()[2], 1.0])
        for label in ax_twin.get_yticklabels():
            label.set_color('0.5')

#def calc_arky_response(arky_params, GPe_arky, full_output=False):
#def calc_arky_response(arky_params, input_args):
def calc_arky_response(arky_proto_params, input_args):

    GPe_arky = input_args[0]
    arky_params = arky_proto_params[0:7]
    GPe_arky.a = arky_params[0] # 0.005
    GPe_arky.b = arky_params[1] # 0.3
    GPe_arky.c = arky_params[2] # -65
    GPe_arky.d = arky_params[3] # 8
    GPe_arky.n0 = arky_params[4]
    GPe_arky.n1 = arky_params[5]
    GPe_arky.n2 = arky_params[6]

    full_output = input_args[1]

    print("arky_params = ", arky_params)

    for trial in range(n_trials):
        start = timer()
        if trial >= 7:
            GPe_Proto.I = (trial-7) * 0.025 # 0.01 # Allow for negative currents to be injected
        else:
            GPe_Proto.I = (trial-7) * 0.01
        GPe_arky.I = GPe_Proto.I
        injected_current_simul_nA[trial] = GPe_Proto.I
        simulate(trial_length_ms)

    #T_smoothing_ms = 250.0

    gpe_spdata = m_GPe_Proto.get('spike')
    gpe_vdata = m_GPe_Proto.get('v')
    gpe_gAMPAdata = m_GPe_Proto.get('g_ampa')
    gpe_Idata = m_GPe_Proto.get('I')
    fr_gpe = m_GPe_Proto.population_rate(gpe_spdata, smooth=T_smoothing_ms) # 100.0

    arky_spdata = m_arky.get('spike')
    arky_vdata = m_arky.get('v')
    arky_gAMPAdata = m_arky.get('g_ampa')
    arky_Idata = m_arky.get('I')
    fr_arky = m_arky.population_rate(arky_spdata, smooth=T_smoothing_ms) # 100.0

    reset(populations=True)

    # Calculate firing rate for the last 100 ms of each stimulation period:
    mean_response_Proto_simul_Hz = mean_response_rate(fr_gpe, n_trials, sim_steps, dt_step_ms)
    mean_response_arky_simul_Hz = mean_response_rate(fr_arky, n_trials, sim_steps, dt_step_ms)

    # Calculate a fitting error relative to the Abdi et al. data
    #inj_current_Arky_expdata_pA, rate_Arky_expdata_Hz = read_arky_data()
    inj_current_Arky_expdata_pA, rate_Arky_expdata_Hz, sem_Arky_Hz, rate_Proto_expdata_Hz, sem_Proto_Hz = read_arky_data_Bogacz2016()

    i_trial_autonomous = 7
    vm_min = min(arky_vdata[i_trial_autonomous * int(trial_length_ms / dt_step_ms) : (i_trial_autonomous+1) * int(trial_length_ms / dt_step_ms), 0])  # dt_step_ms # 0.1
    print('Arky vm min = ', vm_min)

    #rmse_arky = np.sqrt( np.sum( (np.array(mean_response_arky_simul_Hz) - np.array(rate_Arky_expdata_Hz))**2 ) )
    rmse_arky = np.sqrt( np.sum( (np.array(mean_response_arky_simul_Hz) - np.array(rate_Arky_expdata_Hz))**2 ) + 10*(vm_min - (-71))**2) # Adding vm constraint

    print('rmse_arky = ', rmse_arky)

    #print('arky_spdata[0][0] = ', arky_spdata[0][0])
    #print('GPe_arky.a, GPe_arky.b, GPe_arky.c, GPe_arky.d = ', GPe_arky.a, GPe_arky.b, GPe_arky.c, GPe_arky.d)

    if full_output == False:
        return rmse_arky
    else:
        return rmse_arky, mean_response_arky_simul_Hz,arky_spdata, arky_vdata

def calc_proto_response(proto_params, input_args):
    GPe_Proto = input_args[0]
    GPe_Proto.a = proto_params[0]
    GPe_Proto.b = proto_params[1]
    GPe_Proto.c = proto_params[2]
    GPe_Proto.d = proto_params[3]
    GPe_Proto.n0 = proto_params[4]
    GPe_Proto.n1 = proto_params[5]
    GPe_Proto.n2 = proto_params[6]

    full_output = input_args[1]

    print("proto_params = ", proto_params)

    for trial in range(n_trials):
        start = timer()
        if trial >= 7:
            GPe_Proto.I = (trial-7) * 0.025 # 0.01 # Allow for negative currents to be injected
        else:
            GPe_Proto.I = (trial-7) * 0.01
        GPe_arky.I = GPe_Proto.I
        injected_current_simul_nA[trial] = GPe_Proto.I
        simulate(trial_length_ms)

    #T_smoothing_ms = 250.0

    gpe_spdata = m_GPe_Proto.get('spike')
    gpe_vdata = m_GPe_Proto.get('v')
    gpe_gAMPAdata = m_GPe_Proto.get('g_ampa')
    gpe_Idata = m_GPe_Proto.get('I')
    fr_gpe = m_GPe_Proto.population_rate(gpe_spdata, smooth=T_smoothing_ms) # 100.0

    arky_spdata = m_arky.get('spike')
    arky_vdata = m_arky.get('v')
    arky_gAMPAdata = m_arky.get('g_ampa')
    arky_Idata = m_arky.get('I')
    fr_arky = m_arky.population_rate(arky_spdata, smooth=T_smoothing_ms) # 100.0

    reset(populations=True)

    # Calculate firing rate for the last 100 ms of each stimulation period:
    mean_response_Proto_simul_Hz = mean_response_rate(fr_gpe, n_trials, sim_steps, dt_step_ms)
    mean_response_arky_simul_Hz = mean_response_rate(fr_arky, n_trials, sim_steps, dt_step_ms)

    # Calculate a fitting error relative to the Abdi et al. data
    #inj_current_Arky_expdata_pA, rate_Arky_expdata_Hz = read_arky_data()
    inj_current_Arky_expdata_pA, rate_Arky_expdata_Hz, sem_Arky_Hz, rate_Proto_expdata_Hz, sem_Proto_Hz = read_arky_data_Bogacz2016()

    i_trial_autonomous = 7
    vm_min = min(gpe_vdata[i_trial_autonomous * int(trial_length_ms / dt_step_ms) : (i_trial_autonomous+1) * int(trial_length_ms / dt_step_ms), 0])  # dt_step_ms # 0.1
    print('Proto vm min = ', vm_min)

    #rmse_proto = np.sqrt( np.sum( (np.array(mean_response_Proto_simul_Hz[0:14]) - np.array(rate_Proto_expdata_Hz[0:14]))**2 ) )
    rmse_proto = np.sqrt( np.sum( (np.array(mean_response_Proto_simul_Hz[0:14]) - np.array(rate_Proto_expdata_Hz[0:14]))**2 ) + 10*(vm_min - (-66))**2) # Adding vm constraint

    print('rmse_proto = ', rmse_proto)

    if full_output == False:
        return rmse_proto
    else:
        return rmse_proto, mean_response_Proto_simul_Hz, gpe_spdata, gpe_vdata

setup(dt=0.1)
#setup(dt=0.01)
#setup(dt=1)
#setup(num_threads=4 )

random.seed()
np.random.seed()

#General parameters
population_size = 10 # 100

#Neuron models

Hybrid_neuron_inp_res = Neuron(
parameters="""

    a = 0.0   : population
    b = 0.0   : population
    c = 0.0   : population
    d = 0.0   : population
    n0 = 140. : population
    n1 = 5.0  : population
    n2 = 0.04 : population
    I = 0.0   : population
    tau_ampa = 80 : population
    tau_gaba = 80 : population
    E_ampa = 0.0 : population
    E_gaba = -90.0 : population
    R_input_megOhm = 10.0 : population
""",

equations="""
    dg_ampa/dt = -g_ampa/tau_ampa : init = 0
    dg_gaba/dt = -g_gaba/tau_gaba : init = 0
    dv/dt = n2*v*v+n1*v+n0 - u  + R_input_megOhm * I - g_ampa*(v-E_ampa) - g_gaba*(v-E_gaba): init = -70.
    du/dt = a*(b*(v)-u) : init = -18.55
""", # megOhm * nanoAmp = millivolt

spike = """v>=30""",
reset = """v = c
           u = u+d""",
refractory = 5.0
) # 5.0

#Layers
GPe_Proto      = Population(population_size, Hybrid_neuron_inp_res)
GPe_arky = Population(population_size, Hybrid_neuron_inp_res)

#GPe parameters
GPe_Proto.a = 0.005
GPe_Proto.b = 0.585
GPe_Proto.c = -65
GPe_Proto.d = 4
GPe_Proto.I = 0
GPe_Proto.R_input_megOhm = 450.0 # See Abdi, Magill et al. 2015, Table 1

#GPe Arky parameters

GPe_arky.a = 0.005 # 0.004 #
GPe_arky.b = 0.1 # 0.585 #
GPe_arky.c = -65
GPe_arky.d = 4
GPe_arky.I = 0
GPe_arky.R_input_megOhm = 560.0 # 560.0  # See Abdi, Magill et al. 2015, Table 1

# Individual params n0, n1, n2 varied:
'''#
GPe_arky.n0, GPe_arky.n1, GPe_arky.n2 = GPe_Proto.n0 * 2, GPe_Proto.n1, GPe_Proto.n2          # Very high rates
GPe_arky.n0, GPe_arky.n1, GPe_arky.n2 = GPe_Proto.n0 * 0.9, GPe_Proto.n1, GPe_Proto.n2        # Somewhat lower rates, similar f-I slope

GPe_arky.n0, GPe_arky.n1, GPe_arky.n2 = GPe_Proto.n0, GPe_Proto.n1 * 1.05, GPe_Proto.n2       # Somewhat lower rates, similar f-I slope
GPe_arky.n0, GPe_arky.n1, GPe_arky.n2 = GPe_Proto.n0, GPe_Proto.n1 * 0.9, GPe_Proto.n2        # higher rates

GPe_arky.n0, GPe_arky.n1, GPe_arky.n2 = GPe_Proto.n0, GPe_Proto.n1, GPe_Proto.n2 * 1.05       # higher rates
GPe_arky.n0, GPe_arky.n1, GPe_arky.n2 = GPe_Proto.n0, GPe_Proto.n1, GPe_Proto.n2 * 0.9        # lower rates

GPe_arky.n0, GPe_arky.n1, GPe_arky.n2 = GPe_Proto.n0 * 0.95, GPe_Proto.n1 * 1.02, GPe_Proto.n2 # somewhat lower rates
'''

#GPe_arky.d, GPe_arky.a, paramset = GPe_Proto.d * 2.0, GPe_Proto.a * 0.5, 1      # Strongly reduced rates - good! A bit too strong when considering input resistance.
#GPe_arky.d, GPe_arky.a, paramset = GPe_Proto.d * 2.0, GPe_Proto.a * 0.25, 2     # Rates too low
GPe_arky.d, GPe_arky.a, paramset = GPe_Proto.d * 2.0, GPe_Proto.a * 0.8, 3       # My version: a=0.004, b=0.585
GPe_arky.d, GPe_arky.a, paramset = GPe_Proto.d * 2.0, 0.005, 4       # Ilianas version: a=0.005, b=0.1
GPe_arky.d, GPe_arky.a, paramset = GPe_Proto.d * 2.0, 0.005, 5       # New version: a=0.005, b=0.3

# Result (use these values):
GPe_arky.a = 0.005 # 0.004
GPe_arky.b = 0.3 # 0.1 # 0.585
GPe_arky.c = -65
GPe_arky.d = 8
GPe_arky.I = 0

arky_params = [GPe_arky.a, GPe_arky.b, GPe_arky.c, GPe_arky.d, GPe_arky.n0, GPe_arky.n1, GPe_arky.n2]
proto_params = [GPe_Proto.a, GPe_Proto.b, GPe_Proto.c, GPe_Proto.d, GPe_Proto.n0, GPe_Proto.n1, GPe_Proto.n2]

#main loop
compile('Annarchy99')

m_GPe_Proto  = Monitor(GPe_Proto,['spike','v','g_ampa', 'I'])
m_arky  = Monitor(GPe_arky,['spike','v','g_ampa', 'I'])

dt_step_ms          = dt() # 0.1
trial_length_ms     = 1500.0
T_smoothing_ms = 250.0

n_trials            = 17 # 12 # 9 # 10 # 1
simlength_ms        = n_trials * trial_length_ms
sim_steps           = simlength_ms / dt_step_ms
timesteps           = plt.arange(0, simlength_ms, dt_step_ms)

injected_current_simul_nA    = np.nan *np.ones(n_trials)

#arky_params =  [ 5.04768174e-03,  3.27611185e-01, -7.17911993e+01,  8.68578568e+00,  1.17574208e+02,  4.41107716e+00,  3.76000533e-02] # 5ms refractory period - great! rmse_arky = 2.41027 (manual Abdi data)
#arky_params =  [ 5.02471952e-03,  3.27597679e-01, -7.30001054e+01,  8.96429028e+00,  1.17881446e+02,  4.42449605e+00,  3.74269283e-02] # Bogacz et al. data. rmse_arky =  2.102311282480598
#arky_params =  [ 5.38612347e-03,  3.36811868e-01, -71,  9.81279870e+00,  1.12989223e+02,  4.47315863e+00,  3.98586667e-02] # -71
arky_params =  [ 0.0054,          0.34,           -71,  9.81,            113,             4.47,            0.04] # rounded

#proto_params =  [5.40489759e-03, 5.84110289e-01, -6.87516180e+01,  3.53245611e+00, 1.36701406e+02,  5.20660168e+00,  4.16693675e-02] #  good enough (5ms refr.), rmse_proto = 3.5426
#proto_params =  [ 5.75941038e-03,  5.58540551e-01, -6.58954513e+01,  3.79816288e+00,  1.17164834e+02,  4.85649725e+00,  4.25927423e-02] # Proto vm min =  -65.89, rmse_proto =  3.50
#proto_params =  [ 5.75941038e-03,  5.58540551e-01, -65,  3.79816288e+00,  1.17164834e+02,  4.85649725e+00,  4.25927423e-02] # -64
proto_params =  [ 0.0058,          0.56,           -65,  3.8,             117,             4.86,            0.043] # rounded

GPe_arky.a, GPe_arky.b, GPe_arky.c, GPe_arky.d, GPe_arky.n0, GPe_arky.n1, GPe_arky.n2 = arky_params
GPe_Proto.a, GPe_Proto.b, GPe_Proto.c, GPe_Proto.d, GPe_Proto.n0, GPe_Proto.n1, GPe_Proto.n2 = proto_params

param_bounds = ((0, np.inf), (0, np.inf), (-80, -40), (0, np.inf), (0, np.inf), (0, np.inf), (0, np.inf)) # a,b,c,d,n0,n1,n2

'''#
res = sciopt.minimize(calc_arky_response, arky_params, [GPe_arky, False], bounds=param_bounds, method='Nelder-Mead') # Fit only Arky
res = sciopt.minimize(calc_proto_response, proto_params, [GPe_Proto, False], bounds=param_bounds, method='Nelder-Mead')  # Fit only Proto

rmse_arky, mean_response_arky_simul_Hz, arky_spdata, arky_vdata = calc_arky_response(res.x, [GPe_arky, GPe_Proto, True]) # After fitting#
rmse_proto, mean_response_Proto_simul_Hz, gpe_spdata, gpe_vdata = calc_proto_response(res.x, [GPe_Proto, True]) # After fitting#
'''

rmse_arky, mean_response_arky_simul_Hz, arky_spdata, arky_vdata = calc_arky_response(arky_params, [GPe_arky, True]) # Without fitting
rmse_proto, mean_response_Proto_simul_Hz, gpe_spdata, gpe_vdata = calc_proto_response(proto_params, [GPe_Proto, True]) # Without fitting

GPe_arky.a, GPe_arky.b, GPe_arky.c, GPe_arky.d, GPe_arky.n0, GPe_arky.n1, GPe_arky.n2 = arky_params
GPe_Proto.a, GPe_Proto.b, GPe_Proto.c, GPe_Proto.d, GPe_Proto.n0, GPe_Proto.n1, GPe_Proto.n2 = proto_params

plt.ion()
fsize = 9
plt.figure(figsize=(9,12)) # 15,12

rmax_gpe = m_GPe_Proto.population_rate(gpe_spdata, smooth=T_smoothing_ms).max()
rmax_arky = m_arky.population_rate(arky_spdata, smooth=T_smoothing_ms).max()
rmax = max(rmax_gpe, rmax_arky)

#raster_rate_plot(m_gpe, gpe_spdata, 'GPe proto', 321, 'b', T_smoothing_ms, rmax, fsize)
#raster_rate_plot(m_arky, arky_spdata, 'GPe Arky', 322, 'r', T_smoothing_ms, rmax, fsize)

#plt.subplot(324)
#ax4=plt.gca()
#plt.axis([ax4.axis()[0], ax4.axis()[1], 0, ax4.axis()[3]])

plot_vm_traces(gpe_vdata, arky_vdata, trial_length_ms, dt_step_ms, fsize, 321, 323, i_trial_arky=8)
#plot_vm_traces(gpe_vdata, arky_vdata, trial_length_ms, dt_step_ms, fsize, 321, 325)

# Additional simulations - driven firing:
GPe_Proto.u = 0.0
GPe_Proto.v = -70.0
GPe_Proto.I = 0.0

GPe_arky.u = 0.0
GPe_arky.v = -70.0
GPe_arky.I = 0.0
simulate(500.0)

GPe_Proto.I = 0.1
GPe_arky.I = GPe_Proto.I
simulate(2000.0)

GPe_Proto.I = 0.0
GPe_arky.I = 0.0
simulate(500.0)

# New - hyperpolarization:
GPe_Proto.I = -0.1
GPe_arky.I = GPe_Proto.I
simulate(500.0)
GPe_Proto.I = 0.0
GPe_arky.I = 0.0
simulate(500.0)
# - end new
GPe_Proto.I = -0.5
GPe_arky.I = GPe_Proto.I
simulate(500.0)
GPe_Proto.I = 0.0
GPe_arky.I = 0.0
simulate(500.0)

gpe_vdata = m_GPe_Proto.get('v')
arky_vdata = m_arky.get('v')
arky_Idata = m_arky.get('I')
#plot_vm_traces(gpe_vdata, arky_vdata, 3000.0, dt_step_ms, fsize, 322, 324, arky_Idata) # old - only depolarization
#plot_vm_traces(gpe_vdata, arky_vdata, 4000.0, dt_step_ms, fsize, 322, 324, arky_Idata) # new - add'l hyperpolarization
plot_vm_traces(gpe_vdata, arky_vdata, 5000.0, dt_step_ms, fsize, 322, 324, arky_Idata) # new - 2x hyperpolarization

plt.subplot(325)
inj_current_Arky_expdata_pA, rate_Arky_expdata_Hz, sem_Arky_Hz, rate_Proto_expdata_Hz, sem_Proto_Hz = read_arky_data_Bogacz2016()
plt.plot(inj_current_Arky_expdata_pA, rate_Arky_expdata_Hz, '.-', color=np.array([255,64,0])/255., ms=10, label='GPe-Arky (experimental data)')
plt.plot(1e3 * injected_current_simul_nA, mean_response_arky_simul_Hz, '.-', color=np.array([0,255,255])/255., ls='--', ms=10, label='GPe-Arky (simulated data)')
plt.plot(inj_current_Arky_expdata_pA[0:14], rate_Proto_expdata_Hz[0:14],'.-', color=np.array([223,98,3])/255., ms=10, label='GPe-Proto (experimental data)')
plt.plot(1e3 * injected_current_simul_nA[0:14], mean_response_Proto_simul_Hz[0:14],'.-', color=np.array([3,67,223])/255., ls='--', ms=10, label='GPe-Proto (simulated data)')
plt.legend()
plt.axis([plt.axis()[0], plt.axis()[1], -5, 100]) # 75
plt.xlabel('Injected current [pA]')
plt.ylabel('Firing rate [spk/sec]')
plt.title('Responses to step currents', fontsize=1.2*fsize)

# Add further simulations (hyperpolarization) here:

#plt.subplots_adjust(bottom=0.08, top=0.9, wspace=0.5, hspace=0.35, left=0.12)#, right=0.85 )
plt.subplots_adjust(bottom=0.08, top=0.9, wspace=0.3, hspace=0.35, left=0.12)#, right=0.85 )

#plt.savefig('plots/compare_proto_arky_paramset'+str(paramset)+'.png')#, dpi=300)
resultsDir='../results'
try:
    os.makedirs(resultsDir)
except:
    if os.path.isdir(resultsDir):
        print(resultsDir+' already exists')
    else:
        print('could not create '+resultsDir+' folder')
        quit()
plt.savefig(resultsDir+'/compare_proto_arky_fit_expdata_dt.svg', dpi=300)

plt.ioff()
plt.show()


class FilterModule(object):
  def filters(self):
    return {
      'service_ipv4_address': self.service_ipv4_address,
      'service_ipv6_address': self.service_ipv6_address,
    }

  def service_ipv4_address(self, instancePort, basePort, shortRange = False):
    if shortRange:
      bnet = int(basePort/100)
      cnet = int(basePort/10) - (int(basePort/100)*10)
      dnet = (instancePort % basePort)*16
      mask = 28
    else:
      bnet = int(basePort/100)
      cnet = instancePort % basePort
      dnet = 0
      mask = 24

    if bnet < 0 or bnet > 255:
      bnet = 0

    if cnet < 0 or cnet > 255:
      cnet = 0

    if dnet < 0 or dnet > 255:
      dnet = 0

    return '172.' + str(bnet) + '.' +str(cnet)+ '.' +str(dnet)+ '/' + str(mask)

  def service_ipv6_address(self, instancePort, basePort, shortRange = False):
    bnet = basePort
    cnet = format(instancePort % basePort, 'x')
    mask = 110

    return 'fc00:ac0b:0:0:' + str(bnet) + ':' + str(cnet) + '::/' + str(mask)


from collections import deque
min_time = 1000000

def bfs(x):
    global min_time
    q = deque([x])
    visited = [0] * (min_time+1)
    while q:
        c = q.popleft()
        if c == K:  # 종료조건
            return visited[c]

        for i in (c-1, c+1, 2*c):
            if 0 <= i <= min_time and not visited[i]:
                visited[i] = visited[c] + 1
                q.append(i)

N, K = map(int, input().split())
print(bfs(N))


""" Service functions for slot models of coupon app. """

import datetime
import logging

from django.db.models import Q

from coupon.models import Slot, SlotTimeFrame

LOG = logging.getLogger('ten.%s' % __name__)
LOG.setLevel(logging.ERROR)

def close_slot_open_time_frame(slot):
    """ Given a slot, close the open time frame of it. A slot has at most one
    open time frame.
    """
    now = datetime.datetime.now()
    slot_time_frames = SlotTimeFrame.objects.filter(
        Q(end_datetime__gt=now) | Q(end_datetime=None),
        start_datetime__lt=now, slot=slot)
    if slot_time_frames:
        slot_time_frames[0].close_this_frame_now()

def create_business_families_list(business_id):
    """ Create a list of dictionaries each holding a slot family for all
    current families this business owns. A parent has from 0 to 9 children.
    Example:
    [{'parent':<Slot: Slot 357 on Hudson Valley>,
      'children':[<Slot: Slot 358 on Hudson Valley>,
                <Slot: Slot 359 on Hudson Valley>,
                <Slot: Slot 360 on Hudson Valley>,
                <Slot: Slot 361 on Hudson Valley>,
                <Slot: Slot 362 on Hudson Valley>,
                <Slot: Slot 363 on Hudson Valley>,
                <Slot: Slot 364 on Hudson Valley>,
                <Slot: Slot 365 on Hudson Valley>,
                <Slot: Slot 366 on Hudson Valley>]},
     {'parent':<Slot: Slot 370 on Hudson Valley>,
      'children':[<Slot: Slot 375 on Hudson Valley>,
                <Slot: Slot 381 on Hudson Valley>,
                <Slot: Slot 398 on Hudson Valley>]},
     {'parent':<Slot: Slot 410 on Hudson Valley>,
      'children':[]}
    ]
    """
    all_families_list = []
    current_parent_slots, current_children_slots = \
            Slot.current_slots.get_current_family_slots(business_id=business_id)
    for parent_slot in current_parent_slots:
        children_list = []
        for child_slot in current_children_slots:
            if parent_slot == child_slot.parent_slot:
                children_list.append(child_slot)
        family_dict =  {'parent':parent_slot, 'children':children_list}
        all_families_list.append(family_dict)
    LOG.debug('all_families_list: %s' % all_families_list)
    return all_families_list

def check_available_family_slot(business_id):
    """ Check if any family slot member does not have a current time frame.
    If all parents and children have current time frames, check if a new child
    needs to get created for a parent who has less than 9 children in their
    family. If none of these are true, a new parent will have to get created.
    - A family can have a max of 10 members
    - 1 parent + (9 children max)/(0 children min)
    - 1 business can have multiple families
    We should always max out the number of children in the oldest family before
    we create/update another younger family.
    """
    publish_to_parent = False
    publish_to_child = False
    available_parent_slot = None
    available_child_slot = None
    for family in create_business_families_list(business_id=business_id):
        LOG.debug('family: %s' % family)
        if not family['parent'].has_active_time_frame():
            publish_to_parent = True
            available_parent_slot = family['parent']
            break
        for child in family['children']:
            if not child.has_active_time_frame():
                publish_to_child = True
                available_parent_slot = family['parent']
                available_child_slot = child
                break
        # Prefer early family children over later family parents.
        if publish_to_child:
            break
        if len(family['children']) < 9:
            available_parent_slot = family['parent']
            break
    family_availability_dict = {
        'available_parent_slot':available_parent_slot,
        'available_child_slot':available_child_slot,
        'publish_to_parent':publish_to_parent,
        'publish_to_child':publish_to_child}
    return family_availability_dict

def publish_business_coupon(family_availability_dict, coupon):
    """
    Do 1 of 3 things here.
    1.) Use existing parent_slot to put this coupon live.
    2.) Use existing child_slot to put this coupon live.
    3.) Create a new child_slot to put this coupon live because no other
        slot is empty/available for this business.
    We never should be calling this function if a new parent needs to
    be created.
    """
    available_parent_slot = family_availability_dict['available_parent_slot']
    available_child_slot = family_availability_dict['available_child_slot']
    publish_to_parent = family_availability_dict['publish_to_parent']
    publish_to_child = family_availability_dict['publish_to_child']
    if available_child_slot:
        # Unused child slot exists already for this business that has an
        #slot.end_date that hasn't closed yet.
        available_child_slot.site_id = available_parent_slot.site_id
        available_child_slot.end_date = available_parent_slot.end_date
        slot = available_child_slot
    if publish_to_parent:
        # Unused Parent slot exists already.
        slot = available_parent_slot
    if not publish_to_parent and not publish_to_child:
        # Create new child
        slot = Slot(site_id=available_parent_slot.site_id,
            business_id=available_parent_slot.business_id,
            renewal_rate=None,
            is_autorenew=False,
            parent_slot=available_parent_slot,
            end_date=available_parent_slot.end_date)
    slot.save()
    slot_time_frame = SlotTimeFrame(slot_id=slot.id,
        coupon_id=coupon.id)
    slot_time_frame.save()
    return slot


import os
from os import path

import pandas as pd
from sklearn.model_selection import train_test_split
from torch.utils.data import MapDataPipe

from modules import log
from modules.const import InputType, SEED

DATASET_NAME = 'archival'
NUM_CLASS = 2
INPUT = InputType.DUAL

# Root taken from tools/nli.
RAW_FILE = path.join(os.getcwd(), '.cache', 'archival_nli.json')

_EXTRACTED_FILES = {
	'train': 'train.json',
	'val': 'val.json',
	'test': 'test.json',
	'full': 'archival_nli.json'
}

_TEST_SPLIT = .15  # 15% of original dataset
_VAL_SPLIT = .15  # 15% of original dataset

def download_format_dataset(root: str, split: str, version: str):
	"""
	Download and reformat dataset
	Args:
		root (str): cache folder where to find the dataset.
		split (str): among train, val, test
		raw_path (int): parqueet file generated by notebook
	"""
	if path.basename(root) != DATASET_NAME:
		root = path.join(root, DATASET_NAME)
	root = path.join(root, version) # add version to the root
	os.makedirs(root, exist_ok=True)
	# make a subdata set for dev purpose
	json_path = path.join(root, _EXTRACTED_FILES[split])

	if not path.exists(json_path):

		json_path = path.join(root, _EXTRACTED_FILES['full'])
		full_data = pd.read_json(json_path, encoding='utf-8')

		# split into train-val-test equally for classes
		train_val, test = train_test_split(full_data, test_size=_TEST_SPLIT, stratify=full_data['label'],random_state=SEED)
		train, val = train_test_split(train_val, test_size=_VAL_SPLIT / (1 - _TEST_SPLIT), stratify=train_val['label'],random_state=SEED)

		for split_set, split in zip([train, val, test], ['train', 'val', 'test']):
			split_set.reset_index(drop=True, inplace=True)
			split_path = path.join(root, _EXTRACTED_FILES[split])
			with open(split_path, 'w', encoding='utf-8') as f:
				split_set.to_json(f, force_ascii=False)
				log.info(f'Save {split} set at: {split_path}')

	return json_path

class ArchivalNLI(MapDataPipe):
	NUM_CLASS = NUM_CLASS
	INPUT = INPUT

	def __init__(self, split: str = 'train', root: str = path.join(os.getcwd(), '.cache'), n_data: int = -1, version:str=None):

		if split not in _EXTRACTED_FILES.keys():
			self.json_path = split
			self.split = 'predict'
			# 	raise ArgumentError(f'split argument {split} doesnt exist for ArchivalNLI')

		else:
			root = self.root(root)
			self.split = split
			if version is None:
				version = self.get_version(root)

			# download and prepare csv file if not exist
			self.json_path = download_format_dataset(root, split, version=version)

		self.data = pd.read_json(self.json_path, encoding='utf-8')

		log.info(f'Load dataset from {self.json_path}')

		if n_data > 0:
			_unique_label = self.data['label'].unique()

			subset = [
				self.data[self.data['label'] == label]  # slice at each label
					.head(n_data // len(_unique_label))  # get the top n_data/3
				for label in _unique_label
			]
			self.data = pd.concat(subset).reset_index(drop=True)

	def __getitem__(self, index: int):
		"""

		Args:
			index ():

		Returns:

		"""

		# Load data and get label
		if index >= len(self): raise IndexError  # meet the end of dataset

		sample = self.data.loc[index].to_dict()

		return sample

	def __len__(self):
		"""
		Denotes the total number of samples
		Returns: int
		"""
		return len(self.data)

	@classmethod
	def root(cls, root):
		return path.join(root, DATASET_NAME)

	@classmethod
	def get_version(cls, root):
		"""
		Get the newest version created in the folder. Version folder name should be started by v

		Parameters
		----------
		root :

		Returns
		-------
		str
			name of the newest folder

		"""
		versions = [d for d in os.listdir(root) if path.isdir(path.join(root, d)) and d != '.DS_Store' and d[0] == 'v']
		versions.sort(key=lambda x: os.stat(os.path.join(root, x)).st_mtime)
		return versions[-1]

	@classmethod
	def download_format_dataset(cls, root, split='test', version=None):
		if version is None:
			version = cls.get_version(root)
		return download_format_dataset(root, split, version)

	@classmethod
	def clean_cache(cls, root):
		pass

	def __str__(self):
		description = {
			'name': DATASET_NAME,
			'split': self.split,
			'cache': self.json_path,
			'#data': len(self.data),
			'More': 'Use dataset.data.describe()'
		}
		return str(description)

	def describe(self):
		return self.data.describe()