import numpy as np
import renderapi
from renderapi.errors import RenderError

from .utils import (
    rescale_image
)

OVERLAP = 0.05  # assumed overlap between fields
BUFFER = 300    # amount of extra pixels to include in bbox

def get_bbox_from_relative_position(
    tilespec,
    relative_position=None,
    overlap=None,
    buffer=None
):
    """Determine bounding box from relative position.

    Parameters
    ----------
    tilespec : `renderapi.tilespec.TileSpec`
    relative_position : str
        relative position as determined by `renderapi.client.tilePairClient`
    overlap : scalar
        assumed overlap between fields
    buffer : scalar
        amount of extra pixels to include in bbox

    Returns
    -------
    bbox : 4-tuple
        (x_min, y_min, x_max, y_max)
    """
    if relative_position is None:
        return tilespec.bbox
    if overlap is None:
        overlap = OVERLAP
    if buffer is None:
        buffer = BUFFER

    # unpack bounding box
    x_min, y_min, x_max, y_max = tilespec.bbox

    # change the appropriate coordinate
    if relative_position.lower() == "left":
        x_min = x_max - overlap*tilespec.width - buffer
    elif relative_position.lower() == "right":
        x_max = x_min + overlap*tilespec.width + buffer
    elif relative_position.lower() == "top":
        y_min = y_max - overlap*tilespec.height - buffer
    elif relative_position.lower() == "bottom":
        y_max = y_min + overlap*tilespec.height + buffer

    else:
        msg = f"Unknown relative position, '{relative_position}'."
        raise ValueError(msg)

    bbox = (x_min, y_min, x_max, y_max)
    return bbox

def get_image_for_matching(
    stack,
    tileId,
    relative_position=None,
    overlap=None,
    buffer=None,
    **render_kwargs
):
    """Retrieve (part of) an image expected to overlap with its pair.

    Parameters
    ----------
    stack : str
    tileId : str
    relative_position : str (optional)
        relative position as determined by `renderapi.client.tilePairClient`
        defaults to None --> full image
    overlap : scalar
        assumed overlap between fields
    buffer : scalar
        amount of extra pixels to include in bbox

    Returns
    -------
    image : (M, N) ubyte array
    """
    # get tile specification to determine bbox
    spec = renderapi.tilespec.get_tile_spec(
        stack=stack,
        tile=tileId,
        **render_kwargs
    )
    if spec is None:
        msg = f"Tile specification, '{tileId}', does not exist in stack, '{stack}'."
        return RenderError(msg)

    # determine bbox from relative position and overlap
    bbox = get_bbox_from_relative_position(
        spec, relative_position, overlap, buffer
    )

    # get image as 16bit tiff
    # TODO: why `maxTileSpecsToRender` fails at low values?
    image = renderapi.image.get_bb_image(
        stack,
        z=spec.z,
        x=bbox[0],
        y=bbox[1],
        width=bbox[2] - bbox[0],
        height=bbox[3] - bbox[1],
        scale=1.0,
        maxTileSpecsToRender=32,
        img_format="tiff16",
        **render_kwargs
    )
    if isinstance(image, RenderError):
        return image

    return rescale_image(image, k=2, out_range=np.ubyte)

def get_image_pair_for_matching(
    stack,
    tilepair,
    overlap=None,
    buffer=None,
    **render_kwargs
):
    """Get pair of images from which to find features.

    Parameters
    ----------
    stack : str
    tilepair : dict
        output element from `renderapi.client.tilePairClient`
        {"p": {"groupId": ...,
               "id": ...,
               "relativePosition": ...},
         "q": {"groupId": ...,
               "id": ...,
               "relativePosition": ...}
        }
    overlap : scalar
        assumed overlap between fields
    buffer : scalar
        amount of extra pixels to include in bbox

    Returns
    -------
    image_p : (M, N) ubyte array
    image_q : (M, N) ubyte array
    """
    image_p = get_image_for_matching(
        stack=stack,
        tileId=tilepair["p"].get("id"),
        relative_position=tilepair["p"].get("relativePosition"),
        overlap=overlap,
        buffer=buffer,
        **render_kwargs
    )
    image_q = get_image_for_matching(
        stack=stack,
        tileId=tilepair["q"].get("id"),
        relative_position=tilepair["q"].get("relativePosition"),
        overlap=overlap,
        buffer=buffer,
        **render_kwargs
    )
    return image_p, image_q


#!/usr/bin/env python3

'''
Script to select the best configuration from a hyperparameter sweep.
'''

import argparse
import json
import numpy as np
import os
import os.path
import pandas
import yaml

from grid_search import grid_search

class Configuration:

    def __init__(self, params):
        self.params = params
        self.runs = []

def parse_args():
    parser = argparse.ArgumentParser("Identifies the best hyperparameters settings from a tuning sweep")

    parser.add_argument("path", type=str, help="path to directory containing training results")
    parser.add_argument("-l", "--loss", type=str, default="nash_conv",
        help="key of the metric to minimize (or maximize)")
    parser.add_argument("-a", "--accumulate", type=str, default="mean",
        help="method for condensing time series into a scalar ['mean','max','min']")
    parser.add_argument("-m", "--mode", type=str, default="min",
        help="whether to maximize or minimize the given key ['max','min']")

    return parser.parse_args()

def load_variations(path):
    with open(os.path.join(path, "config.json"), 'r') as config_file:
        config = json.load(config_file)

    return grid_search(config)

def load_runs(path, loss, accumulate):
    print(f"loading: {path}")
    runs = []

    if os.path.isdir(path):
        for obj in os.listdir(path):
            results_path = os.path.join(path, obj)

            if os.path.isdir(results_path):
                results_file = os.path.join(results_path, "results.csv")

                if os.path.isfile(results_file):
                    results = pandas.read_csv(results_file)

                    # Filter out empy data series
                    if results.shape[0] > 0:
                        result = results[loss]

                        if results.shape[0] > 0 and not np.any(np.isnan(result)):
                            if "max" == accumulate:
                                value = np.max(result)
                            elif "max" == accumulate:
                                value = np.min(result)
                            else:
                                value = np.mean(result)

                            runs.append(value)

    return runs

def main(args):
    print(f"Path: {args.path}")
    print("Loading runs...")

    # Load variations
    with open(os.path.join(args.path, "config.json"), 'r') as config_file:
        experiments = json.load(config_file)

    variations = {}

    for name, config in experiments.items():
        variations.update(grid_search(name, config))

    # Collect all runs for each config
    configs = dict()

    for name, config in variations.items():
        runs = load_runs(os.path.join(args.path, name), args.loss, args.accumulate)
        config_str = json.dumps({
            "alg": config["alg"],
            "alg_config": config["alg_config"]
        }, sort_keys=True)

        if config_str not in configs:
            configs[config_str] = Configuration(config["alg_config"])

        configs[config_str].runs.extend(runs)

    # Identify best configuration
    if "min" == args.mode:
        best_mean = np.Infinity
    else:
        best_mean = -np.Infinity

    best_configs = []

    for config in configs.values():
        if len(config.runs) > 0:
            mean = np.mean(config.runs)

            print("\n------------")
            print(f"Mean: {mean}")
            print("Config:")
            print(yaml.dump(config.params, default_flow_style=False))

            if mean == best_mean:
                best_configs.append(config.params)
            elif "min" == args.mode:
                if mean < best_mean:
                    best_mean = mean
                    best_configs = [config.params]
            else:
                if mean > best_mean:
                    best_mean = mean
                    best_configs = [config.params]

    # Return best config
    print(f"\nBest Value: {best_mean}")
    print("Best Configs:")

    for config in best_configs:
        print("\n----------\n")
        print(yaml.dump(config, default_flow_style=False))

if __name__ == "__main__":
    args = parse_args()
    main(args)


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('core', '0006_change_subscription_owner_to_payment_gateway'),
    ]

    operations = [
        migrations.CreateModel(
            name='BraintreePaymentMethod',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('created_at', models.DateTimeField(auto_now_add=True)),
                ('modified_at', models.DateTimeField(auto_now=True)),
                ('customer_id', models.CharField(max_length=255)),
                ('token', models.CharField(max_length=255)),
                ('succeed', models.BooleanField(default=False)),
            ],
            options={
                'db_table': 'sm_bt_payment_method',
            },
        ),
        migrations.CreateModel(
            name='DiscountCode',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('created_at', models.DateTimeField(auto_now_add=True)),
                ('modified_at', models.DateTimeField(auto_now=True)),
                ('name', models.CharField(unique=True, max_length=255)),
                ('code', models.CharField(unique=True, max_length=255)),
                ('amount', models.FloatField(default=0)),
                ('start_at', models.DateTimeField(auto_now_add=True)),
                ('end_at', models.DateTimeField(null=True, blank=True)),
            ],
            options={
                'db_table': 'sm_discount_code',
            },
        ),
        migrations.AddField(
            model_name='user',
            name='description',
            field=models.TextField(default=b''),
        ),
        migrations.AddField(
            model_name='user',
            name='mock',
            field=models.BooleanField(default=False),
        ),
        migrations.AlterField(
            model_name='order',
            name='status',
            field=models.CharField(default=b'OPEN', max_length=31, choices=[(b'APPROVED', 'Approved'), (b'CANCELLED', 'Cancelled'), (b'DELIVERED', 'Delivered'), (b'INVOICE_SENT', 'Invoice sent'), (b'OPEN', 'Open'), (b'PAID', 'Paid'), (b'RENEWING', b'Renewing')]),
        ),
    ]


import enum
from typing import Dict, List

from attr import define, field

from plox.cli import Plox
from plox.expressions import (
    Assign,
    Binary,
    Call,
    Expr,
    ExprVisitor,
    Get,
    Grouping,
    Literal,
    Logical,
    Set,
    Super,
    This,
    Unary,
    Variable,
)
from plox.interpreter import Interpreter
from plox.statements import (
    Block,
    Class,
    Expression,
    Function,
    If,
    Print,
    Return,
    Stmt,
    StmtVisitor,
    Var,
    While,
)
from plox.tokens import Token

class FunctionType(enum.Enum):
    NONE = enum.auto()
    FUNCTION = enum.auto()
    INITIALISER = enum.auto()
    METHOD = enum.auto()

class ClassType(enum.Enum):
    NONE = enum.auto()
    CLASS = enum.auto()
    SUBCLASS = enum.auto()

@define
class Resolver(ExprVisitor, StmtVisitor):
    interpreter: Interpreter
    scopes: List[Dict[str, bool]] = field(factory=list)
    current_function: FunctionType = FunctionType.NONE
    current_class: ClassType = ClassType.NONE

    def visit_block(self, stmt: Block) -> None:
        self.begin_scope()
        self.resolve(stmt.statements)
        self.end_scope()

    def visit_class(self, stmt: Class) -> None:
        enclosing_class = self.current_class
        self.current_class = ClassType.CLASS

        self.declare(stmt.name)
        self.define(stmt.name)

        if (
            stmt.superclass is not None
            and stmt.name.lexeme == stmt.superclass.name.lexeme
        ):
            Plox.error(
                stmt.superclass.name.line,
                "A class can't inherit from itself.",
                stmt.superclass.name,
            )

        if stmt.superclass is not None:
            self.current_class = ClassType.SUBCLASS
            self.resolve_expression(stmt.superclass)

        if stmt.superclass is not None:
            self.begin_scope()
            self.scopes[-1]["super"] = True

        self.begin_scope()
        self.scopes[-1]["this"] = True

        for method in stmt.methods:
            if method.name.lexeme == "init":
                self.resolve_function(method, FunctionType.INITIALISER)
            else:
                self.resolve_function(method, FunctionType.METHOD)

        self.end_scope()

        if stmt.superclass is not None:
            self.end_scope()

        self.current_class = enclosing_class

    def visit_expression(self, stmt: Expression) -> None:
        self.resolve_expression(stmt.expression)

    def visit_function(self, stmt: Function) -> None:
        self.declare(stmt.name)
        self.define(stmt.name)
        self.resolve_function(stmt, FunctionType.FUNCTION)

    def visit_if(self, stmt: If) -> None:
        self.resolve_expression(stmt.condition)
        self.resolve_statement(stmt.then_branch)
        if stmt.else_branch is not None:
            self.resolve_statement(stmt.else_branch)

    def visit_print(self, stmt: Print) -> None:
        self.resolve_expression(stmt.expression)

    def visit_return(self, stmt: Return) -> None:
        if self.current_function is FunctionType.NONE:
            Plox.error(
                stmt.keyword.line, "Can't return from top-level code.", stmt.keyword
            )
        if stmt.value is not None:
            if self.current_function is FunctionType.INITIALISER:
                Plox.error(
                    stmt.keyword.line,
                    "Can't return a value from an initializer.",
                    stmt.keyword,
                )
            self.resolve_expression(stmt.value)

    def visit_var(self, stmt: Var) -> None:
        self.declare(stmt.name)
        if stmt.initialiser is not None:
            self.resolve_expression(stmt.initialiser)
        self.define(stmt.name)

    def visit_while(self, stmt: While) -> None:
        self.resolve_expression(stmt.condition)
        self.resolve_statement(stmt.body)

    def visit_assign(self, expr: Assign) -> None:
        self.resolve_expression(expr.value)
        self.resolve_local(expr, expr.name)

    def visit_binary(self, expr: Binary) -> None:
        self.resolve_expression(expr.left)
        self.resolve_expression(expr.right)

    def visit_call(self, expr: Call) -> None:
        self.resolve_expression(expr.callee)
        for arg in expr.arguments:
            self.resolve_expression(arg)

    def visit_get(self, expr: Get) -> None:
        self.resolve_expression(expr.obj)

    def visit_grouping(self, expr: Grouping) -> None:
        self.resolve_expression(expr.expression)

    def visit_literal(self, expr: Literal) -> None:
        pass

    def visit_logical(self, expr: Logical) -> None:
        self.resolve_expression(expr.left)
        self.resolve_expression(expr.right)

    def visit_set(self, expr: Set) -> None:
        self.resolve_expression(expr.value)
        self.resolve_expression(expr.obj)

    def visit_super(self, expr: Super) -> None:
        if self.current_class is ClassType.NONE:
            Plox.error(
                expr.keyword.line, "Can't use 'super' outside of a class.", expr.keyword
            )
        elif self.current_class is not ClassType.SUBCLASS:
            Plox.error(
                expr.keyword.line,
                "Can't use 'super' in a class with no superclass.",
                expr.keyword,
            )

        self.resolve_local(expr, expr.keyword)

    def visit_this(self, expr: This) -> None:
        if self.current_class is ClassType.NONE:
            Plox.error(
                expr.keyword.line, "Can't use 'this' outside of a class.", expr.keyword
            )
            return
        self.resolve_local(expr, expr.keyword)

    def visit_unary(self, expr: Unary) -> None:
        self.resolve_expression(expr.right)

    def visit_variable(self, expr: Variable) -> None:
        if self.scopes and self.scopes[-1].get(expr.name.lexeme) is False:
            Plox.error(
                expr.name.line,
                "Can't read local variable in its own initializer.",
                expr.name,
            )
        self.resolve_local(expr, expr.name)

    def resolve(self, statements: List[Stmt]) -> None:
        for stmt in statements:
            self.resolve_statement(stmt)

    def resolve_statement(self, stmt: Stmt) -> None:
        stmt.accept(self)

    def resolve_expression(self, expr: Expr) -> None:
        expr.accept(self)

    def resolve_local(self, expr: Expr, name: Token) -> None:
        for depth, scope in enumerate(reversed(self.scopes)):
            if name.lexeme in scope:
                return self.interpreter.resolve(expr, depth)

    def resolve_function(self, stmt: Function, function_type: FunctionType) -> None:
        enclosing_function = self.current_function
        self.current_function = function_type
        self.begin_scope()

        for param in stmt.params:
            self.declare(param)
            self.define(param)
        self.resolve(stmt.body)

        self.end_scope()
        self.current_function = enclosing_function

    def begin_scope(self) -> None:
        self.scopes.append({})

    def end_scope(self) -> None:
        self.scopes.pop()

    def declare(self, name: Token) -> None:
        if self.scopes:
            current_scope = self.scopes[-1]
            if name.lexeme in current_scope:
                Plox.error(
                    name.line, "Already a variable with this name in this scope.", name
                )
            current_scope[name.lexeme] = False

    def define(self, name: Token) -> None:
        if self.scopes:
            self.scopes[-1][name.lexeme] = True


class Solution:
    def isPerfectSquare(self, num: int) -> bool:
        """
        :type num: int
        :rtype: bool
        """
        # set left and right boundary
        left, right = 0, num

        while left <= right:
            # get mid value
            mid = left + (right - left) // 2

            # check the square num and target num
            square_num = mid * mid
            if square_num > num:
                right = mid - 1
            elif square_num < num:
                left = mid + 1
            else:
                return True
        return False


"""
Persistence script for Core module.
This script provides methods to save and load dataframes to and from
 CSV and pickle files, respectively.
"""
import logging
from enum import Enum

import pandas as pd
from pandas import NaT
from pandas.io.parsers import TextFileReader

from core import logging_config
from core.config import settings

logging_config.setup_logging()
logger: logging.Logger = logging.getLogger(__name__)

class DataType(str, Enum):
    """
    Data Type class based on Enum
    """
    RAW: str = 'data/raw/'
    PROCESSED: str = 'data/processed/'
    FIGURES: str = 'reports/figures/'

class PersistenceManager:
    """
    Persistence Manager class.
    Defines the different data types that can be saved and loaded.
    """

    @staticmethod
    def save_to_csv(
            dataframe: pd.DataFrame, data_type: DataType = DataType.PROCESSED,
            filename: str = 'processed_data.csv') -> bool:
        """
        Save dataframe as csv file
        :param dataframe: DataFrame to save
        :type dataframe: pd.DataFrame
        :param data_type: Path where data will be saved
        :type data_type: DataType
        :param filename: name of the file
        :type filename: str
        :return: True if the csv file was created; otherwise false
        :rtype: bool
        """
        if len(dataframe) == 0:
            return False
        if not settings.ENCODING:
            raise AttributeError("Encoding is not set.")
        dataframe.to_csv(f'{data_type.value}{filename}', index=False,
                         encoding=settings.ENCODING)
        logger.info("Dataframe saved to csv")
        return True

    @staticmethod
    def load_from_csv(
            filename: str = 'raw_data.csv',
            data_type: DataType = DataType.RAW,
            chunk_size: int = settings.CHUNK_SIZE, dtypes: dict = None,
            parse_dates: list[str] = None, converters: dict = None
    ) -> pd.DataFrame:
        """
        Load dataframe from CSV using chunk scheme
        :param filename: name of the file including extension
        :type filename: str
        :param data_type: Path where data will be saved
        :type data_type: DataType
        :param chunk_size: Number of chunks to split dataset
        :type chunk_size: int
        :return: Dataframe retrieved from CSV after optimization with chunks
        :rtype: pd.DataFrame
        """
        filepath: str = f'{data_type.value}{filename}'
        if not settings.ENCODING:
            raise AttributeError("Encoding is not set.")
        text_file_reader: TextFileReader = pd.read_csv(
            filepath, sep=', ', header=0, chunksize=chunk_size,
            encoding=settings.ENCODING, parse_dates=parse_dates,
            converters=converters, na_values=[NaT, 'nan', '', ' '])
        dataframe: pd.DataFrame = pd.concat(text_file_reader,
                                            ignore_index=True)
        for key, value in dtypes.items():
            if value in [float, int]:
                try:
                    dataframe[key] = pd.to_numeric(dataframe[key],
                                                   errors='coerce')
                    dataframe[key] = dataframe[key].astype(value)
                except Exception as exc:
                    logger.error(exc)
            else:
                try:
                    dataframe[key] = dataframe[key].astype(value)
                except Exception as exc:
                    logger.error(exc)
        logger.info("Dataframe loaded from csv")
        return dataframe

    @staticmethod
    def save_to_pickle(
            dataframe: pd.DataFrame, data_type: DataType = DataType.PROCESSED,
            filename: str = 'optimized_df.pkl') -> None:
        """
        Save dataframe to pickle file
        :param dataframe: Dataframe to save
        :type dataframe: pd.DataFrame
        :param data_type: Path where data will be saved
        :type data_type: DataType
        :param filename: Name of the file
        :type filename: str
        :return: None
        :rtype: NoneType
        """
        dataframe.to_pickle(f'{data_type.value}{filename}')
        logger.info("Dataframe saved to pickle")

    @staticmethod
    def load_from_pickle(
            data_type: DataType, filename: str = 'optimized_df.pkl'
    ) -> pd.DataFrame:
        """
        Load dataframe from Pickle file
        :param filename: Name of the file to search and load
        :type filename: str
        :param data_type: Path where data will be saved from Data Type
        :type data_type: DataType
        :return: Dataframe read from pickle
        :rtype: pd.DataFrame
        """
        dataframe: pd.DataFrame = pd.read_pickle(
            f'data/{data_type.value}/{filename}')
        logger.info("Dataframe loaded from pickle")
        return dataframe


# https://github.com/recursecenter/interview-prep/blob/master/_questions/taxi-driver.md

def taxi_driver():
    n = int(input())
    mem = [[helper(i, j) for i in range(n)] for j in range(n)]
    for i in range(1, n):
        for j in range(1, n):
            mem[i][j] = mem[i-1][j] + mem[i][j-1]
    return mem[n-1][n-1]

def helper(i, j):
    if (i == 0 or j == 0):
        return 1
    else:
        return 0

print(taxi_driver())


# import pytest

from numpy.random import seed

from alf import ml_model
from alf import context_manager
from alf import d_manager
from alf import input_manager

SupervisedMLModel = ml_model.SupervisedMLModel
Committee = ml_model.CommitteeMLModel
ContextProvider = context_manager.ContextProvider
DbProvider = d_manager.DbProvider

d_0_path = "tests/test_files/test.csv"
wd = "/tmp/alf"

def test_input_manager_trapcap_folder():
    ContextProvider.create_context("file")
    ContextProvider.get_context().set_experiment_id("qqqq1")
    ContextProvider.get_context().set_working_dir(wd)
    ContextProvider.get_context().set_features(["bytes_rev", "bytes"])
    DbProvider.create_context("file", d_0_path=d_0_path)
    DbProvider.get_context().fetch(test_size=0.1)
    trapcap_folder_input_manager = input_manager.TrapcapFolderInputManager(
        "tests/example_trapcaps"
    )
    flows = trapcap_folder_input_manager.get()
    assert flows is not None
    assert len(list(flows)) > 0

def test_input_manager_trapcap_folder_load_all():
    all_tables = []
    ContextProvider.create_context("file")
    ContextProvider.get_context().set_experiment_id("qqqq1")
    ContextProvider.get_context().set_working_dir(wd)
    ContextProvider.get_context().set_features(["bytes_rev", "bytes"])
    DbProvider.create_context("file", d_0_path=d_0_path)
    DbProvider.get_context().fetch(test_size=0.1)
    trapcap_folder_input_manager = input_manager.TrapcapFolderInputManager(
        "tests/example_trapcaps"
    )
    for flows in trapcap_folder_input_manager.get():
        all_tables.append(flows)
    assert len(all_tables) == 9


import random
import math
import numpy

geracoes = []
novageracao = []

# Gera populacao inicial
def populationInitialization():
    nmrIndividuos = 10  # populacao
    minimo = -20  # menorValorX
    maximo = 20  # maiorValorX
    qtdBits = 16  # qtdCromossomos
    population = []

    for i in range(nmrIndividuos):
        cromossomos = ''

        for j in range(qtdBits):
            bit = random.randint(0, 1)
            if cromossomos == '':
                cromossomos = str(bit)
            else:
                cromossomos += str(bit)

        population.append([cromossomos, math.inf])

    # Calcula aptidao dos individuos
    population = fitnessFunction(minimo, maximo, qtdBits, population)

    return population

# Calcula aptidao
def fitnessFunction(minimo, maximo, bits, population):
    # Calculando cada individuo
    for i in range(len(population)):
        decimal = int(population[i][0], 2)

        # x ∈ [−20, +20]
        x = minimo + (((maximo - minimo) * decimal) / ((2 ** bits) - 1))

        # Cálculo de aptidão
        aptidao = round((math.cos(x) * x) + 2, 2)

        population[i][1] = aptidao

    # Ordenando, pois queremos o minimo
    population.sort(key=lambda fitness: fitness[1])

    return population

# Por torneio = 2 pais
def selection(population):
    pais = []

    for i in range(len(population)):
        individuo1 = population[random.randint(0, len(population) - 1)]
        individuo2 = population[random.randint(0, len(population) - 1)]

        if min(individuo1[1], individuo2[1]) == individuo1[1]:
            pai = individuo1
        else:
            pai = individuo2
        pais.append(pai)

    return pais

# r <= 0,6
def crossOver(pais, torneio):
    filhos = []

    for i in range(0, len(pais) - 1, torneio):
        r = round(random.uniform(0, 1), 1)
        if r <= 0.6:
            corte = random.randint(1, 16)

            pai1 = pais[i][0]
            pai2 = pais[i + 1][0]

            filho = [pai1[0:corte] + pai2[corte:len(pai2)], math.inf]
            filha = [pai2[0:corte] + pai1[corte:len(pai1)], math.inf]

        else:
            filho = pais[i]
            filha = pais[i + 1]

        filhos.append(filho)
        filhos.append(filha)

    return filhos

# r <= 0,01
def mutation(filhos):
    for i in range(len(filhos)):
        individuo = filhos[i][0]

        for j in range(len(individuo)):
            r = round(random.uniform(0, 1), 2)

            if r <= 0.01:
                if individuo[j] == "0":
                    individuo = individuo[:j] + "1" + individuo[j + 1:]
                else:
                    individuo = individuo[:j] + "0" + individuo[j + 1:]

    fitnessFunction(-20, 20, 16, filhos)

    return filhos

# Elitismo: guardando os melhores para a nova geracao
def elitismo(filhos, population):
    global novageracao
    global geracoes

    filhos.sort(key=lambda x: x[1])
    population.sort(key=lambda x: x[1])

    if filhos[-1] > population[0]:
        for i in range(len(filhos)):
            if filhos[i][1] == population[-1][1]:
                del filhos[i]
                break
        filhos.append(population[0])

    filhos.sort(key=lambda x: x[1])

    novageracao = filhos.copy()
    geracoes.append(novageracao)
    novageracao = []

def printaTabelas():
    global geracoes
    dic = {}
    contador = 1
    for geracao in geracoes:
        soma = 0
        print("######## GERACAO {} ########".format(contador))
        print("____________________________")
        print("    INDIVIDUOS     |  F(x)  ")
        dic["Geracao %d" % (contador)] = 0
        for individuo in geracao:
            print(individuo)
            soma += individuo[1]

        print("____________________________")
        print("MELHOR APTIDAO: {}".format(min(geracao, key=lambda x: x[1])[1]))
        print("MEDIA: {}\n\n".format(soma / len(geracao)))
        dic["Geracao %d" % (contador)] += soma / len(geracao)
        contador += 1
        print()
    print("GERAÇÃO \t MÉDIA")
    for ger in dic.keys():
        print("%s \t %.2f" % (ger, dic[ger]))
    print()

def main():
    global geracoes

    torneio = 2  # qtdPaisCrossOver
    qtdGeracoes = 10  # inicialmente
    totalGeracoes = 2  # 1 rodada com 10 e uma com 20 geracoes

    while totalGeracoes > 0:

        # Inicializa a populacao
        population = populationInitialization()

        solucao = True
        while solucao:

            # Seleciona individuos aleatorios para serem pais
            pais = selection(population)

            # Faz o crossover dos individuos
            filhos = crossOver(pais, torneio)

            # Aplica mutacao em todos menos no melhor individuo
            filhos = mutation(filhos)

            # Sobrevivencia
            elitismo(filhos, population)

            if len(geracoes) == qtdGeracoes:
                printaTabelas()
                print("############################ FIM\n\n")
                solucao = False

        totalGeracoes -= 1
        qtdGeracoes = 20

if __name__ == '__main__':
    main()


from collections import deque
n, m, k, x = map(int,input().split())
data=[[] for _ in range(n+1)]
for i in range(m):
    a,b=map(int, input().split())
    data[a].append(b)

distance=[-1]*(n+1)
distance[x]=0

q=deque()
q.append(x)

while q:
    now=q.popleft()
    for i in data[now]:
        if distance[i]==-1:
            q.append(i)
            distance[i]=distance[now]+1
flag=False
for i in range(1,n+1):
    if distance[i]==k:
        if flag==False:
            flag=True
        print(i)
if flag==False:
    print(-1)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Mar 10 15:14:18 2022

@author: joshua
"""

import sys, os
from astropy.io import fits
import matplotlib.pyplot as plt
import numpy as np
import plotstyle as ps

drpall = fits.getdata('/Volumes/ssd2t/final_clean/0.drpall/drpall_clean_weight.fits')
z = drpall['nsa_z']
mag = drpall['NSA_ELPETRO_absmag'][:,5] + 5*np.log10(0.7)
mngtarg1 = drpall['mngtarg1']

p = ((mngtarg1 & 2**10)!=0)
s = ((mngtarg1 & 2**11)!=0)
c = ((mngtarg1 & 2**12)!=0)

fontsize = 20
fig, ax = plt.subplots(1,1, figsize=(6,6))
ax.scatter(z[c], mag[c], c='goldenrod', label='Color-Enhanced', s=5)
ax.scatter(z[p], mag[p], c='deepskyblue', label='Primary', s=5)
ax.scatter(z[s], mag[s], c='crimson', label='Secondary', s=5)

ax.set_xlim(-0.01, 0.16)
ax.set_ylim(-17, -25)
ax.set_xlabel('Redshift', fontsize=fontsize)
ax.set_ylabel('i-band Absolute Magnitude', fontsize=fontsize)

ps.legend(ax, fontsize=fontsize)

ps.ticks(ax, xmajor=0.05, ymajor=2, xminor=0.01, yminor=0.5)
ps.style(ax, fontsize=fontsize)

plt.savefig('mag_z.png', bbox_inches='tight')


"""Snippets URL Configuration

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.index_page, name="Home"),
    path('snippets/add', views.add_snippet_page, name="Add"),
    path('snippets/list', views.snippets_page, name="List"),
    path('snippets/my', views.snippets_my, name="My"),
    path('snippets/edit/<int:id>', views.snippet_edit, name="Edit"),
    path('snippets/delete/<int:id>', views.snippet_delete, name="Delete"),
    path('snippets/page/<int:id>', views.snippet_page, name="Page"),
    path('auth/login', views.login, name="Login"),
    path('auth/logout', views.logout, name="Logout"),
    path('auth/register', views.register, name="Register"),
    path('comment/add', views.comment_add, name="Comment_Add"),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)+static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


import os
from multiprocessing import Pool as ThreadPool
from rich.progress import track

import osmnx as ox
import numpy as np
import pandas as pd

import flowmanage as fm
class ScenarioMaker:
    def __init__(self) -> None:

        # get the flight intention files to make scenarios
        self.intention_folder = fm.settings.intentions
        self.intention_files = os.listdir(fm.settings.intentions)

        if not self.intention_files:
            fm.con.print('[red bold]No intention files found!')
            fm.con.print("[red bold]Try:[/] [green]python FlowManage.py --intention")
            quit()
        # remove any hidden files
        self.intention_files = [file for file in self.intention_files if not file.startswith('.')]

        # read osmx graph from data
        self.G = ox.load_graphml(fm.settings.graph_path)

        # get nodes and edges
        self.nodes, self.edges = ox.graph_to_gdfs(self.G)

        # process the rest of settings
        self.intention_cols = fm.settings.intention_cols
        self.scen_cols = fm.settings.scen_cols
        self.default_values = fm.settings.default_values
        self.scenario_header = fm.settings.scenario_header
        self.scenario_folder = fm.settings.scenarios

    def process(self, multi: int | None = None) -> None:
        """Main scenario maker process.
        Args:
            multi (int | None, optional): Number of workers to use. Defaults to None.
        """

        fm.con.print('[magenta]Creating scenarios...')

        if multi:
                pool = ThreadPool(multi)
                pool.map(self.create_scen, self.intention_files)
                pool.close()
        else:
            # Loop through intention files
            for intention_file in track(self.intention_files, description="[magenta]Processing...",
                            console=fm.con):

                # create the scenario file
                self.create_scen(intention_file)

    def create_scen(self, intention_file: str) -> None:
        """Create the scenario file from the intention file."""

        # read the intention file
        file_path = os.path.join(self.intention_folder, intention_file)

        # create the dataframe
        scen_df = pd.read_csv(file_path, names=self.intention_cols)

        # see if any columns are missing from intention file
        missing_cols = list(set(self.scen_cols) - set(self.intention_cols))

        # add them to the dataframe
        if missing_cols:
            for col in missing_cols:
                    scen_df[col] = self.default_values[col]

        # create a column with spawn time + crecmd
        scen_df['crecmd'] = scen_df['spawn_time'] + '>' + scen_df['crecmd']

        # remove spawn time column
        scen_df.drop('spawn_time', axis=1, inplace=True)

        # save as df to csv
        scenario_file_name = intention_file.replace('csv','scn')

        scenario_path = os.path.join(self.scenario_folder, scenario_file_name)
        scen_df.to_csv(scenario_path, index=False, header=False, columns=self.scen_cols)

        # add the header to the file
        with open(scenario_path, 'r+') as f:
            content = f.read()
            f.seek(0, 0)
            f.write(''.join(self.scenario_header) + content)


import sys
import os
import time
from copy import deepcopy as dcp
import p3d.vector

class TransformationMatrix:
	def __init__(self,isv,itv):
		'''
		Returns a transformationmatrix object
		input has to be a set of 3 source vectors and 3 destination vectors
		'''
		assert len(isv) == 3, "Need three source vectors"
		assert len(itv) == 3, "Need three target vectors"
		self.a = 0
		self.b = 0
		self.c = 0
		self.d = 0
		self.e = 0
		self.f = 0
		self.g = 0
		self.h = 0
		self.i = 0
		sb1 = (isv[1]-isv[0])
		sb2 = (isv[2]-isv[0])
		su3 = (sb1.cross(sb2)).normalize()
		su2 = sb2.normalize()
		su1 = (su2.cross(su3)).normalize()

		tb1 = (itv[1]-itv[0])
		tb2 = (itv[2]-itv[0])
		tu3 = (tb1.cross(tb2)).normalize()
		tu2 = tb2.normalize()
		tu1 = (tu2.cross(tu3)).normalize()

		self.source = isv[0]
		self.target = itv[0]
		sourcevectors = [ su1, su2, su3 ]
		targetvectors = [ tu1, tu2, tu3 ]

		s1x = sourcevectors[0].x
		s2x = sourcevectors[1].x
		s3x = sourcevectors[2].x
		s1y = sourcevectors[0].y
		s2y = sourcevectors[1].y
		s3y = sourcevectors[2].y
		s1z = sourcevectors[0].z
		s2z = sourcevectors[1].z
		s3z = sourcevectors[2].z
		t1x = targetvectors[0].x
		t2x = targetvectors[1].x
		t3x = targetvectors[2].x
		t1y = targetvectors[0].y
		t2y = targetvectors[1].y
		t3y = targetvectors[2].y
		t1z = targetvectors[0].z
		t2z = targetvectors[1].z
		t3z = targetvectors[2].z
		self.a = -(s2z*s3y*t1x - s2y*s3z*t1x - s1z*s3y*t2x + s1y*s3z*t2x + s1z*s2y*t3x - s1y*s2z*t3x)/(-s1z*s2y*s3x + s1y*s2z*s3x + s1z*s2x*s3y - s1x*s2z*s3y - s1y*s2x*s3z + s1x*s2y*s3z)
		self.b = -(s2z*s3x*t1x - s2x*s3z*t1x - s1z*s3x*t2x + s1x*s3z*t2x + s1z*s2x*t3x - s1x*s2z*t3x)/(s1z*s2y*s3x - s1y*s2z*s3x - s1z*s2x*s3y + s1x*s2z*s3y + s1y*s2x*s3z - s1x*s2y*s3z)
		self.c = -(-s2y*s3x*t1x + s2x*s3y*t1x + s1y*s3x*t2x - s1x*s3y*t2x - s1y*s2x*t3x + s1x*s2y*t3x)/(s1z*s2y*s3x - s1y*s2z*s3x - s1z*s2x*s3y + s1x*s2z*s3y + s1y*s2x*s3z - s1x*s2y*s3z)
		self.d = -(s2z*s3y*t1y - s2y*s3z*t1y - s1z*s3y*t2y + s1y*s3z*t2y + s1z*s2y*t3y - s1y*s2z*t3y)/(-s1z*s2y*s3x + s1y*s2z*s3x + s1z*s2x*s3y - s1x*s2z*s3y - s1y*s2x*s3z + s1x*s2y*s3z)
		self.e = -(s2z*s3x*t1y - s2x*s3z*t1y - s1z*s3x*t2y + s1x*s3z*t2y + s1z*s2x*t3y - s1x*s2z*t3y)/(s1z*s2y*s3x - s1y*s2z*s3x - s1z*s2x*s3y + s1x*s2z*s3y + s1y*s2x*s3z - s1x*s2y*s3z)
		self.f = -(-s2y*s3x*t1y + s2x*s3y*t1y + s1y*s3x*t2y - s1x*s3y*t2y - s1y*s2x*t3y + s1x*s2y*t3y)/(s1z*s2y*s3x - s1y*s2z*s3x - s1z*s2x*s3y + s1x*s2z*s3y + s1y*s2x*s3z - s1x*s2y*s3z)
		self.g = -(s2z*s3y*t1z - s2y*s3z*t1z - s1z*s3y*t2z + s1y*s3z*t2z + s1z*s2y*t3z - s1y*s2z*t3z)/(-s1z*s2y*s3x + s1y*s2z*s3x + s1z*s2x*s3y - s1x*s2z*s3y - s1y*s2x*s3z + s1x*s2y*s3z)
		self.h = -(s2z*s3x*t1z - s2x*s3z*t1z - s1z*s3x*t2z + s1x*s3z*t2z + s1z*s2x*t3z - s1x*s2z*t3z)/(s1z*s2y*s3x - s1y*s2z*s3x - s1z*s2x*s3y + s1x*s2z*s3y + s1y*s2x*s3z - s1x*s2y*s3z)
		self.i = -(-s2y*s3x*t1z + s2x*s3y*t1z + s1y*s3x*t2z - s1x*s3y*t2z - s1y*s2x*t3z + s1x*s2y*t3z)/(s1z*s2y*s3x - s1y*s2z*s3x - s1z*s2x*s3y + s1x*s2z*s3y + s1y*s2x*s3z - s1x*s2y*s3z)
		return

	def __mul__(self,other):
		'''
		Returns new Vector with old properties, but transformed by transformation matrix
		'''
		protein = other.protein
		other.protein = None # must add to avoid deepcopy recursive ultra madness
		transformed_Vector = dcp(other)
		transformed_Vector.protein = protein
		transformed_Vector = transformed_Vector.translateBy(-self.source)
		new_x = (self.a*transformed_Vector.x + self.b*transformed_Vector.y + self.c*transformed_Vector.z)
		new_y = (self.d*transformed_Vector.x + self.e*transformed_Vector.y + self.f*transformed_Vector.z)
		new_z = (self.g*transformed_Vector.x + self.h*transformed_Vector.y + self.i*transformed_Vector.z)
		transformed_Vector.x = round(new_x,7)
		transformed_Vector.y = round(new_y,7)
		transformed_Vector.z = round(new_z,7)
		transformed_Vector = transformed_Vector.translateBy(self.target)
		transformed_Vector.desc += 'Transformed'
		return transformed_Vector

class Plane:
	def __init__(self,a,b,c):
		self.a = a
		self.b = b
		self.c = c
		tmp = (self.a-self.b).cross(self.a-self.c)
		#tmp = self.a.sub(self.b).cross(self.a.sub(self.c))
		self.n = tmp/(tmp.length())
		#self.n.uberID = ",".join([self.a.uberID,self.b.uberID,self.c.uberID])
	# Distance to origine
		self.d = self.a.dot(self.n)
	# Plane Basis Vector = Plane Normal times distance
		self.D = self.n*self.d
		return

	def projectionOfVector(self,vector):
		'''self is plane and vector vector tp project onto membrane '''
		projected = p3d.vector.Vector((self.n.y**2+self.n.z**2)*vector.x + (-self.n.x*self.n.y)*vector.y + (-self.n.x*self.n.z) * vector.z,
		                                        -self.n.y*self.n.x*vector.x + (self.n.x**2+self.n.z**2)*vector.y +(-self.n.y*self.n.z)*vector.z,
		                                        -self.n.z*self.n.x*vector.x+ (-self.n.z*self.n.y)*vector.y + (self.n.x**2+self.n.y**2) * vector.z)
		return projected+self.D
		'''
		Old style here self vector and zeother plane.n
		return Vector((zeother.y**2+zeother.z**2)*self.x + (-zeother.x*zeother.y)*self.y + (-zeother.x*zeother.z) * self.z,
		                                        -zeother.y*zeother.x*self.x + (zeother.x**2+zeother.z**2)*self.y +(-zeother.y*zeother.z)*self.z,
		                                        -zeother.z*zeother.x*self.x+ (-zeother.z*zeother.y)*self.y + (zeother.x**2+zeother.y**2) * self.z)
		'''

	def minDistance2Vector(self,vector):
		projected = self.projectionOfVector(vector)
		toZeroPlane = vector-projected
		return abs(toZeroPlane-self.D)

	def info(self):
		print('Vectors used to define plane:')
		for v in [self.a,self.b,self.c]:
			print(v.info(lvl='coordinates'))
		print('Plane normal vector:',self.n.info(lvl='coordinates'))
		print('Plane basis vector:',self.D.info(lvl='coordinates'))
		print('Distance to origine:',self.d)
		return

def bp(message=''):
	if message != '':
		print('<ERROR>',message)
		print('exiting ...')
		sys.exit(1)
	sys.exit(0)

def dihedral(a,b,c,d):
	#startT = time.time()
	p1n = Plane(a,b,c).n
	p2n = Plane(b,c,d).n
	angle = p1n.angleBetween(p2n)
	angle_sign = (c-b).dot(p1n.cross(p2n))
	#print('<--*-->',b.info(),time.time()-startT,'s')
	if angle_sign < 0:
		return -1*angle
	else:
		return angle

def strTr( text, dic ):
	pat = "(%s)" % "|".join( map(re.escape, dic.keys()) )
	return re.sub( pat, lambda m:dic[m.group()], text)

def test():
	a = p3d.vector.Vector(1,0,0)
	b = p3d.vector.Vector(0,1,0)
	c = p3d.vector.Vector(1,1,0)
	plane = p3d.geo.Plane(a,b,c)
	plane.info() # <<< should be like .info() in the other modules ....
	print(type(plane))
	k = p3d.vector.Vector(2,2,2)
	print('geo.plane: Projecting',k.info(lvl='coordinates'),'onto plane results into',plane.projectionOfVector(k).info(lvl='coordinates'))
	exit(0)

if __name__ == '__main__':
	print('yes!')


import pygame
import random

class Enemy(pygame.sprite.Sprite):

    def __init__(self, width, height):
        self.width = width
        self.height = height
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((10,10))
        self.image.fill((0,0,255))
        self.rect = self.image.get_rect()
        self.radius = 5
        pygame.draw.circle(self.image, (0,0,0), self.rect.center,self.radius)
        self.rect.center = (random.randint(0, self.width), 0)
        self.x_speed = 0
        self.y_speed = 5

    def update(self):
        self.rect.x += self.x_speed
        self.rect.y += self.y_speed

        if self.rect.top > self.height + 10:
            self.rect.x = random.randrange(0, self.width - self.rect.width)
            self.rect.y = random.randrange(2, 6)
            self.y_speed = 3

    def get_coordinates(self):
        return (self.rect.x, self.rect.y)

    def reset(self):
        self.rect.center = (random.randint(0, self.width), 0)

class Paddle(pygame.sprite.Sprite):

    def __init__(self, width, height):
        self.height = height
        self.width = width
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((75,20))
        self.image.fill((0,0,0))
        self.rect = self.image.get_rect()
        self.rect.center = (width/2, height-10)
        self.x_speed = 0
        self.y_speed = 0

    def update(self, action):
        self.x_speed = 0
        event = pygame.key.get_pressed()

        if event[pygame.K_LEFT] or action == 0:
            self.x_speed = -4
        elif event[pygame.K_RIGHT] or action == 1:
            self.x_speed = 4
        else:
            self.x_speed = 0

        self.rect.x +=self.x_speed

        if self.rect.right > self.height:
            self.rect.right = self.height
        if self.rect.left < 0:
            self.rect.left = 0

    def get_coordinates(self):
        return (self.rect.x, self.rect.y)

    def reset(self):
        self.rect.center = (self.width/2, self.height-10)

def main():
    pygame.init()
    screen = pygame.display.set_mode((360, 360))
    pygame.display.set_caption("Paddle")
    clock = pygame.time.Clock()

    enemy = Enemy(360,360)
    spritess = pygame.sprite.Group()
    spritess.add(enemy)

    running = True

    while running:
    #keep look running at right speed
        clock.tick(30)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
        screen.fill((255,255,255))

        spritess.update()
        spritess.draw(screen)

        #after drwing fill display
        pygame.display.flip()

    pygame.quit()


# from collections import deque

class Node:
    def __init__(self, data=None):
        self.data = data
        self.next = None
        self.prev = None

class DoublyLinkedList:
    def __init__(self):
        self.head = None
        self.tail = None

    def printlist(self):
        val = self.head
        while val is not None:
            print(val.data)
            val = val.next

    def insertBeginning(self, data):
        newNode = Node(data)
        self.head.prev = newNode
        newNode.next= self.head
        self.head = newNode

    # def insertEndWithoutTail(self, data):
    #     newNode = Node(data)
    #     if self.head is None:
    #         self.head = newNode
    #         return
    #     temp = self.head
    #     while temp.next:
    #         temp = temp.next
    #     temp.next = newNode

    def insertEnd(self, data):
        newNode = Node(data)
        if self.tail is None:
            self.head = newNode
            self.tail = newNode
            return
        self.tail.next = newNode
        newNode.prev = self.tail
        self.tail = newNode

    def insertInbetween(self, node, data):
        if node is None:
            print('invalid position')
            return
        newNode = Node(data)
        newNode.next = node.next
        newNode.prev = node
        node.next = newNode

    def remove(self, remove_data):
        if self.head is not None and self.head.data == remove_data:
            newHead = self.head.next
            self.head.next = None
            self.head = newHead
            self.head.prev = None
            return
        if self.tail is None and self.tail.data == remove_data:
            newTail = self.tail.prev
            self.tail.prev = None
            newTail.next = None
            self.tail = newTail
            return
        temp = self.head
        while temp is not None:
            if temp.data == remove_data:
                break
            temp = temp.next
        if temp:
            temp.next.prev = temp.prev
            temp.prev.next = temp.next
            return

list = DoublyLinkedList()
list.head = Node(10)

e2 = Node(20)
e3 = Node(30)

list.head.next = e2
e2.prev = list.head
e2.next = e3
e3.prev = e2

list.tail = e3

list.insertBeginning(5)

list.insertEnd(80)
list.insertEnd(50)

list.insertInbetween(e2, 22)
list.insertInbetween(e2, 21)

list.remove(10)
list.remove(20)

list.printlist()


class Solution:
    def halvesAreAlike(self, s: str) -> bool:
        n, ans = len(s), 0
        for i in range(n):
            if s[i] in 'aeiouAEIOU':
                ans += 1 if i < n // 2 else -1
        return ans == 0

if __name__ == '__main__':
    s = "book"
    print(Solution().halvesAreAlike(s))


'''

You are given an integer array nums and an integer goal.

You want to choose a subsequence of nums such that the sum of its elements is
the closest possible to goal. That is, if the sum of the subsequence's elements is sum,
then you want to minimize the absolute difference abs(sum - goal).

Return the minimum possible value of abs(sum - goal).

Note that a subsequence of an array is an array formed by removing some elements
(possibly all or none) of the original array.

Example 1:

Input: nums = [5,-7,3,5], goal = 6
Output: 0
Explanation: Choose the whole array as a subsequence, with a sum of 6.
This is equal to the goal, so the absolute difference is 0.

'''

'''

Brute Forces:

	DFS or Backtracking can be used to calculate all the possible sums
		for all the subsequence of the nums here

		How many total combinations or total different sums we can calculate given a nums array

			2^n where n is the length of the nums

			The reason being for each number, we have either pick or not pick

				that's why the total combinations for this kind of array is 2^n

-------

Technique:

	Meet in the middle

	Since we can't handle 2^40, but we can handle 2^20

	We split the array into two parts
		then we can brute force to calculate all the possible sums on each side

		suppose we have sum1 in the left side

		sum2 on the right side

		-------

		Then we can basically loop through the total value of the sums on the left side

		and then we try to find the closest one on the right side

			so that we can meet right in the middle

			suppose we have s1 from the left side, and s2 from the right side

			and we primarily want s1 + s2 as close to the goal as possible

	-------

	So to loop through everything from the sum1 here is basically
		2^n/2  --> these are the total number of sums we can get

		on the right side for each of 2^n/2 if we perform another brute force
			to search on the right one

			it will lead to the complexity of 2^n/2 so the resultant is again 2^n  --> TLE

		However, what we can do is that we can sort the second part
			and then we can perform the binary search

			Since we have s1 on the left side, our target element to search on the right side will be

				target = goal - s1

			We can use this target to perform a binary search on the sorted part

		However there is again an issue here
			for example suppose we have an array arr = [1, 2, 3] and goal = -7

			so here what happens if the best solution
				for the sum in the left side (s1) is not selecting anything in the right side (s2)

			If that the case, how to perform a binary search in that scenario

		-------

		Suppose we have an array arr = [-2, -3, | 4, 5] and the goal is -7
			Let's suppose we pick -2 from the left side and the target is to get -7

			so here we shouldn't be adding any number from the right side

		-------

		Hence when we calculate the sum on each side we always add 0 as an element on both the sides
			so that if we are performing let's say a binary search on the right side to search for a
			number -5,

			we will get the closest element as 0

		-------

		Suppose our sum2 is [-20, -10, 0, 1, 4, 6, 10, 12]

			let's say our target is 7

			if we perform a binary search on the right side
				which index the search will return

				it will return the index where 10 is located

				and basically we are assuming that we will use that element to calculate the final absolute
					difference

					but can we only take that element (probably not)

					because other than 10, there might be some other good candidate available
						in this case 6

				So once we get the index of an element in the sum2 here
					after calculating the result using the current index
					we will also check it's neighbor on the left side only

				Why not right?

					Binary Search is here performing the 'bisect_left'
						that guarantees that we will find basically the first number that is greater than
						the target

'''

class Solution:
	def minAbsDifference(self, nums: List[int], goal: int) -> int:

		def dfs(i, curr, nums, res):
			if i == len(nums):
				res.append(curr)
				return
			# otherwise we have just two case, either we pick it or not
			dfs(i + 1, curr, nums, res)
			dfs(i + 1, curr + nums[i], nums, res)

		sum1 = []
		sum2 = []
		n = len(nums)
		dfs(0, 0, nums[:n//2], sum1)
		dfs(0, 0, nums[n//2:], sum2)

		# until here we have already calculate all the possible sums for the two halves

		sum2.sort()
		ans = sys.maxsize
		for s1 in sum1:
			t = goal - s1
			i = bisect_left(sum2, t)

			# if the index is within the length of sum2
			if i < len(sum2):

				# the difference between the target and the element in sum2 will be our min diff
				# for the current s1
				ans = min(ans, abs(t - sum2[i]))

			# the next if will cover two scenarios
			# 1. if i == 0 we can't to i - 1
			# 2. this will again cover two cases
			# let's suppose our array is [0, 1, 2, 4] and target is 3
			# we will get i = 3 and element is 4
			# so not only we need to check 4 but it's left neighbor also
			# and if suppose t = 5, which is greater than the biggest element in the array
			# i - 1 will still give us the left most element
			if i > 0:
				ans = min(ans, abs(t - sum2[i - 1]))

		return ans


import cv2
import numpy as np
import glob
import os

#call webcam
cap = cv2.VideoCapture(0)

#main Body
while(cap.isOpened):
    #read Image
    ret, img = cap.read()

    # get hand data from the rectangle sub window on the screen
    cv2.rectangle(img, (350,300), (50,50), (0,255,0),2)

    #crop Image with rectangle's Size
    crop_img = img[50:300, 50:350]

    #convert RGB to Gray Image
    gray = cv2.cvtColor(crop_img, cv2.COLOR_BGR2GRAY);

    # applying gaussian blur
    value = (25, 25)
    blurred = cv2.GaussianBlur(gray, value, 0)

    # thresholdin: Otsu's Binarization method
    _, thresh1 = cv2.threshold(blurred, 127, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

    # show thresholded image
    #cv2.imshow('Thresholded', thresh1)

    #calculate contours
    image, contours, hierarchy = cv2.findContours(thresh1.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

    # find contour with max area
    cnt = max(contours, key = lambda x: cv2.contourArea(x))

    # create bounding rectangle around the contour (can skip below two lines)
    x, y, w, h = cv2.boundingRect(cnt)
    cv2.rectangle(crop_img, (x, y), (x+w, y+h), (0, 0, 255), 1)

    #Crop Image with Contour Size
    contour_img = gray[y:y+h, x:x+w]
    #contour_img = cv2.resize(gray, (300,250))

    # finding convex hull
    hull = cv2.convexHull(cnt)

    # drawing contours
    drawing = np.zeros(crop_img.shape,np.uint8)
    cv2.drawContours(drawing, [cnt], 0, (0, 255, 0), 0)
    cv2.drawContours(drawing, [hull], 0,(0, 0, 255), 0)

    # finding convex hull
    hull = cv2.convexHull(cnt, returnPoints=False)

    # finding convexity defects
    defects = cv2.convexityDefects(cnt, hull)
    count_defects = 0
    cv2.drawContours(thresh1, contours, -1, (0, 255, 0), 3)

    #call template Image Dataset
    #template_data=[]
    mypath= glob.glob('dataSet\\*.jpg')

    #matching All Image
    for file in mypath:
        #split FileName and FileType
        filename, ext = os.path.splitext(file)

        #get only FileName
        filename = filename[filename.rfind("\\")+3:]

        #read matching image with gray
        image = cv2.imread(file, 0)

        #matching with Method
        #cv2.TM_CCOEFF, cv2.TM_CCOEFF_NORMED, cv2.TM_CCORR, cv2.TM_CCORR_NORMED, cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED
        res = cv2.matchTemplate(contour_img, image,cv2.TM_CCOEFF_NORMED)
        #template_data.append(image)

        #matching with Threshold Vale
        threshold = 0.6

        #matching Image location by Threshold
        loc = np.where(res >= threshold)

        #Display Text with specified location
        for pt in zip(*loc[::-1]):
            font = cv2.FONT_HERSHEY_SIMPLEX
            cv2.putText(crop_img, filename, (20,50), font, 1.5,(255,10,10),2,cv2.LINE_AA)
    #print(filename)

    #For View Windows
    cv2.imshow('Main Image', img)
    cv2.imshow('Gray Contour Image', contour_img);
    #cv2.imshow('Contours Image', drawing)
    #all_img = np.hstack((drawing, contour_img))
    #cv2.imshow('Contours', all_img)

    #For Terminal Windows
    key = cv2.waitKey(10)
    if(key==27):
        break

ASL Recognition System (WLC-Group)/handRecognizer.py


from pathlib import Path
import os
from typing import List

import pandas as pd
import pytest
import numpy as np
import nrrd

import navis

@pytest.fixture(scope="session")
def data_dir():
    return Path(__file__).resolve().parent.parent / "navis" / "data"

@pytest.fixture(
    params=["Path", "pathstr", "swcstr", "textbuffer", "rawbuffer", "DataFrame"]
)
def swc_source(request, swc_paths: List[Path]):
    swc_path: Path = swc_paths[0]
    if request.param == "Path":
        yield swc_path
    elif request.param == "pathstr":
        yield str(swc_path)
    elif request.param == "swcstr":
        yield swc_path.read_text()
    elif request.param == "textbuffer":
        with open(swc_path) as f:
            yield f
    elif request.param == "rawbuffer":
        with open(swc_path, "rb") as f:
            yield f
    elif request.param == "DataFrame":
        df = pd.read_csv(swc_path, sep=" ", header=None, comment="#")
        df.columns = navis.io.swc_io.NODE_COLUMNS
        yield df
    else:
        raise ValueError("Unknown parameter")

@pytest.fixture(
    params=["dirstr", "dirpath", "list", "listwithdir"],
)
def swc_source_multi(request, swc_paths: List[Path]):
    fpath = swc_paths[0]
    dpath = fpath.parent
    if request.param == "dirstr":
        yield str(dpath)
    elif request.param == "dirpath":
        yield dpath
    elif request.param == "list":
        yield [fpath, fpath]
    elif request.param == "listwithdir":
        yield [dpath, fpath]
    else:
        raise ValueError(f"Unknown parameter '{request.param}'")

@pytest.fixture
def voxel_nrrd_path(tmp_path):
    parent = tmp_path / "nrrd"
    parent.mkdir()
    path = parent / "simple.nrrd"
    data = np.zeros((15, 15, 15))
    rng = np.random.RandomState(1991)
    core = rng.random((5, 5, 15))
    data[5:10, 5:10, :] = core

    header = {
        "space directions": np.diag([1, 2, 3]).tolist(),
        "space units": ["um", "um", "um"],
    }
    nrrd.write(os.fspath(path), data, header)

    return path

def data_paths(dpath, glob="*"):
    return sorted(dpath.glob(glob))

@pytest.fixture(scope="session")
def swc_paths(data_dir: Path):
    return data_paths(data_dir / "swc", "*.swc")

@pytest.fixture(scope="session")
def gml_paths(data_dir: Path):
    return data_paths(data_dir / "gml", "*.gml")

@pytest.fixture(scope="session")
def obj_paths(data_dir: Path):
    return data_paths(data_dir / "obj", "*.obj")

@pytest.fixture(scope="session")
def synapses_paths(data_dir: Path):
    return data_paths(data_dir / "synapses", "*.csv")

@pytest.fixture(scope="session")
def volumes_paths(data_dir: Path):
    return data_paths(data_dir / "volumes", "*.obj")

@pytest.fixture
def treeneuron_dfs(swc_paths, synapses_paths):
    swc_reader = navis.io.swc_io.SwcReader()
    out = []
    for swc_path, syn_path in zip(swc_paths, synapses_paths):
        neuron = swc_reader.read_file_path(swc_path)
        neuron.connectors = pd.read_csv(syn_path)
        out.append(neuron)
    return out


from pyclipper import *
from math import *
from ..common.geom import *
from .milling_tool import *

class RapidMove(object):
    pass

class Tab(object):
    def __init__(self, start, end, helical_entry=None):
        self.start = start
        self.end = end
        # Entry into the part after the tab
        self.helical_entry = helical_entry
    def cut(self, slen, elen, tlen):
        if slen >= self.end or elen <= self.start:
            return True
        if slen >= self.start and elen <= self.end:
            return False
        segs = []
        if slen < self.start:
            segs.append((slen, self.start))
        if elen >= self.end:
            segs.append((self.end, elen))
        return segs
    # Start and end point coordinates
    def coords(self, path):
        return (path_point(path, self.start), path_point(path, self.end))
    def __repr__(self):
        return f"Tab({self.start}, {self.end})"

class Tabs(object):
    def __init__(self, tabs):
        last = 0
        last_tab = None
        newtabs = []
        # Merge overlapping tabs
        for tab in sorted(tabs, key=lambda tab: tab.start):
            if last_tab is not None and tab.start < last_tab.end:
                last_tab.end = max(last_tab.end, tab.end)
            else:
                newtabs.append(tab)
                last_tab = tab
        self.tabs = newtabs
    def cut(self, slen, elen, tlen):
        result = [(slen, elen)]
        for tab in self.tabs:
            nextres = []
            for slen2, elen2 in result:
                res = tab.cut(slen2, elen2, tlen)
                if res is True:
                    nextres.append((slen2, elen2))
                elif res is False:
                    pass # Segment removed entirely
                else:
                    nextres += res
            result = nextres
            if not result:
                return False
        # Convert to relative
        if result == [(slen, elen)]:
            return True
        fres = []
        l = elen - slen
        for s, e in result:
            fres.append(((s - slen) / l, (e - slen) / l))
        return fres
    def roll(self, amount, tlength):
        for i in self.tabs:
            if i.end <= amount:
                i.start = tlength + i.start - amount
                i.end = tlength + i.end - amount
            else:
                i.start -= amount
                i.end -= amount
        self.tabs = sorted(self.tabs, key=lambda tab: tab.start)
    # Start and end point coordinates
    def coords(self, path):
        return [tab.coords(path) for tab in self.tabs]

class TabMaker(object):
    def __init__(self, tab_locations, max_tab_distance, tab_length):
        self.tab_locations = tab_locations
        self.max_tab_distance = max_tab_distance
        self.tab_length = tab_length
    def tabify(self, cut_path, path_notabs):
        tab_inst = path_notabs.usertabs(self.tab_locations, self.max_tab_distance, width=self.tab_length)
        # Make sure the original path starts right after a tab, to eliminate the
        # need for additional re-entry at the start of the path
        breakpoint = path_notabs.roll_breakpoint(tab_inst)
        path_notabs.roll_by_tabs(breakpoint, cut_path.helical_entry_func)
        tab_inst.roll(breakpoint, path_notabs.tlength)
        # Create a tabbed version of the rolled path (it starts right after the tab)
        paths_withtabs = path_notabs.cut_by_tabs(tab_inst, cut_path.helical_entry_func)
        cut_path.correct_helical_entry(paths_withtabs)
        paths_withtabs = [p.with_helical_from_top(not p.is_tab and i != 0) for i, p in enumerate(paths_withtabs)]
        cut_path.generate_preview(paths_withtabs)
        return paths_withtabs

class PlungeEntry(object):
    def __init__(self, point):
        self.start = point

class HelicalEntry(object):
    def __init__(self, point, r, angle=0, climb=True):
        self.point = point
        self.r = r
        self.angle = angle
        self.start = PathPoint(point.x + r * cos(angle), point.y + r * sin(angle))
        self.climb = climb

class Toolpath(object):
    def __init__(self, path, tool, transform=None, helical_entry=None, bounds=None, is_tab=False, segmentation=None, was_previously_cut=False, is_cleanup=False, helical_from_top=False, tab_maker=None):
        assert isinstance(path, Path)
        assert path.nodes
        self.path = path
        self.tool = tool
        self.transform = transform if not is_tab else None
        self.is_tab = is_tab
        self.transformed_cache = None
        self.lines_to_arcs_cache = None
        self.optimize_lines_cache = None
        self.segmentation = segmentation
        self.was_previously_cut = was_previously_cut
        self.helical_from_top = helical_from_top
        self.is_cleanup = is_cleanup
        if segmentation and helical_entry is None and segmentation[0][0] == 0 and isinstance(segmentation[0][2], HelicalEntry):
            helical_entry = segmentation[0][2]
        self.helical_entry = helical_entry
        # Allow borrowing bounds from the non-simplified shape to avoid calculating arc bounds
        self.bounds = self.calc_bounds() if bounds is None else bounds
        self.lengths = path.lengths()
        self.tlength = self.lengths[-1]
        self.tab_maker = tab_maker

    def transformed(self):
        if self.transform is None:
            return self
        if self.transformed_cache is None:
            self.transformed_cache = self.transform(self)
        return self.transformed_cache

    def calc_bounds(self):
        if self.path.is_empty():
            return None
        xcoords = [p.x for p in self.path.nodes if p.is_point()]
        ycoords = [p.y for p in self.path.nodes if p.is_point()]
        tr = 0.5 * self.tool.diameter
        return (min(xcoords) - tr, min(ycoords) - tr, max(xcoords) + tr, max(ycoords) + tr)

    def lines_to_arcs(self):
        if self.lines_to_arcs_cache is None:
            self.lines_to_arcs_cache = Toolpath(Path(CircleFitter.simplify(self.path.nodes), self.path.closed), self.tool, transform=self.transform, helical_entry=self.helical_entry, bounds=self.bounds, is_tab=self.is_tab, was_previously_cut=self.was_previously_cut, is_cleanup=self.is_cleanup, helical_from_top=self.helical_from_top, tab_maker=self.tab_maker)
        return self.lines_to_arcs_cache

    def optimize_lines(self):
        if self.optimize_lines_cache is None:
            self.optimize_lines_cache = Toolpath(Path(LineOptimizer.simplify(self.path.nodes), self.path.closed), self.tool, transform=self.transform, helical_entry=self.helical_entry, bounds=self.bounds, is_tab=self.is_tab, was_previously_cut=self.was_previously_cut, is_cleanup=self.is_cleanup, helical_from_top=self.helical_from_top, tab_maker=self.tab_maker)
        return self.optimize_lines_cache

    def optimize(self):
        path = self
        if GeometrySettings.simplify_arcs:
            path = path.lines_to_arcs()
        if GeometrySettings.simplify_lines:
            path = path.optimize_lines()
        return path

    def subpath(self, start, end, is_tab=False, helical_entry=None):
        path = self.path.subpath(start, end)
        if path is None:
            return None
        tp = Toolpath(path, self.tool, transform=self.transform, helical_entry=helical_entry, is_tab=is_tab, was_previously_cut=self.was_previously_cut and start == 0, is_cleanup=self.is_cleanup, tab_maker=self.tab_maker)
        return tp

    def for_tab_below(self):
        return self.without_circles() if self.is_tab else self.with_helical_from_top(False)

    def without_circles(self):
        assert self.is_tab
        return Toolpath(self.path.without_circles(), self.tool, helical_entry=self.helical_entry, is_tab=self.is_tab, was_previously_cut=self.was_previously_cut, is_cleanup=self.is_cleanup, helical_from_top=False, tab_maker=self.tab_maker)

    def with_helical_from_top(self, value=True):
        assert not value or not self.is_tab
        if self.helical_from_top == value:
            return self
        return Toolpath(self.path, self.tool, helical_entry=self.helical_entry, is_tab=self.is_tab, was_previously_cut=self.was_previously_cut, is_cleanup=self.is_cleanup, helical_from_top=value, tab_maker=self.tab_maker)

    def roll_breakpoint(self, tabs):
        if not tabs.tabs:
            return
        return tabs.tabs[0].end

    def roll_by_tabs(self, breakpoint, helical_entry_func):
        if not breakpoint:
            return
        self.path = self.path.subpath(breakpoint, self.tlength).joined(self.path.subpath(0, breakpoint))
        self.helical_entry = helical_entry_func(self.path) if helical_entry_func else None
        # No need for entry from the top for the untabbed part of the path
        self.helical_from_top = False

    def cut_by_tabs(self, tabs, helical_entry_func):
        tabs = sorted(tabs.tabs, key=lambda tab: tab.start)
        pos = 0
        res = []
        def add_subpath(sp):
            if sp is not None and not sp.is_empty():
                res.append(sp)
        helical_entry = self.helical_entry
        for tab in tabs:
            assert tab.start <= tab.end
            if pos < tab.start:
                add_subpath(self.subpath(pos, tab.start, is_tab=False, helical_entry=helical_entry))
            add_subpath(self.subpath(tab.start, tab.end, is_tab=True))
            helical_entry = tab.helical_entry
            # No transform on tabs, so that no time is wasted doing trochoidal
            # milling of empty space above the tab
            pos = tab.end
        if pos < self.tlength:
            add_subpath(self.subpath(pos, self.tlength, is_tab=False, helical_entry=helical_entry))
        if helical_entry_func:
            for i in res:
                if i.helical_entry is None and not i.is_tab:
                    i.helical_entry = helical_entry_func(i.path)
        return res

    def flattened(self):
        return [self]

    def autotabs(self, tool, ntabs, width=1):
        if not ntabs:
            return []
        orient = self.path.orientation()
        tlength = self.path.length()
        offset = tlength / (2 * ntabs)
        tablist = []
        tabw = tool.diameter * (1 + width)
        for i in range(ntabs):
            pos = offset + i * tlength / ntabs
            if orient:
                pos = tlength - pos
            tablist.append(self.path.point_at(pos))
        return tablist

    def usertabs(self, tab_locations, maxdist, width=1):
        tablist = []
        tabw = self.tool.diameter * (1 + width)
        if 2 * tabw < self.tlength:
            for tab in tab_locations:
                pos, dist = self.path.closest_point(tab)
                if dist <= maxdist:
                    start = pos - tabw / 2
                    end = pos + tabw / 2
                    if start < 0:
                        start += self.tlength
                    if end > self.tlength:
                        end -= self.tlength
                    inc = tabw / 8
                    for i in range(4):
                        p1 = self.path.point_at(start)
                        p2 = self.path.point_at(end)
                        if p1.dist(p2) <= 0.99 * tabw:
                            start -= inc
                            end += inc
                            if start < 0:
                                start += self.tlength
                            if end > self.tlength:
                                end -= self.tlength
                        else:
                            break
                    if start < end:
                        tablist.append(self.align_tab_to_segments(start, end))
                    else:
                        tablist.append(self.align_tab_to_segments(start, self.tlength))
                        tablist.append(self.align_tab_to_segments(0, end))
        return Tabs(tablist)

    def align_tab_to_segments(self, spos, epos):
        helical_entry = None
        if self.segmentation:
            cspos = 0
            cepos = None
            for pos1, pos2, he in self.segmentation:
                if pos2 < spos:
                    cspos = pos2
                if cepos is None and pos1 >= epos:
                    cepos = pos1
                    helical_entry = he
            if cepos is None:
                cepos = epos
            #print (spos, epos, '->', cspos, cepos)
            spos, epos = cspos, cepos
        return Tab(spos, epos, helical_entry)

    def tabify(self, cutpath):
        if not self.tab_maker:
            return self
        return Toolpaths(self.tab_maker.tabify(cutpath, self))

    def render_as_outlines(self):
        points = CircleFitter.interpolate_arcs(self.path.nodes, False, 2)
        resolution = GeometrySettings.RESOLUTION
        offset = resolution * self.tool.diameter / 2
        if offset > 200:
            resolution *= 200 / offset
            offset = resolution * self.tool.diameter / 2
        intsFull = PtsToInts(points, resolution)
        if self.path.closed:
            intsFull += [intsFull[0]]
        outlines = []
        step = 50
        for i in range(0, len(intsFull), step):
            ints = intsFull[i : i + step + 1]
            ints += ints[::-1]
            pc = PyclipperOffset()
            pc.AddPath(ints, JT_ROUND, ET_OPENROUND)
            initv = min(offset, 3)
            res = pc.Execute(initv)
            if res:
                outlines += res

        if is_calculation_cancelled():
            return []
        pc = Pyclipper()
        for o in outlines:
            pc.AddPath(o, PT_SUBJECT, True)
        outlines = pc.Execute(CT_UNION, PFT_NONZERO, PFT_NONZERO)
        outlines2 = []
        for o in outlines:
            if is_calculation_cancelled():
                return []
            pc = PyclipperOffset()
            pc.AddPath(o, JT_ROUND, ET_CLOSEDLINE)
            outlines2 += pc.Execute(offset - initv)
        outlines = outlines2
        pc = Pyclipper()
        for o in outlines:
            pc.AddPath(o, PT_SUBJECT, True)
        outlines = pc.Execute(CT_UNION, PFT_NONZERO, PFT_NONZERO)
        return [PtsFromInts(ints, resolution) for ints in outlines]
    def is_empty(self):
        return self.path.is_empty()

class Toolpaths(object):
    def __init__(self, toolpaths):
        self.set_toolpaths(toolpaths)
    def set_toolpaths(self, toolpaths):
        self.toolpaths = toolpaths
        self.bounds = self.calc_bounds()
        self.flattened_cache = self.calc_flattened()
    def flattened(self):
        return self.flattened_cache
    def calc_flattened(self):
        res = []
        for path in self.toolpaths:
            if isinstance(path, Toolpaths):
                res += path.flattened()
            elif isinstance(path, Toolpath):
                res.append(path)
            else:
                assert False, f"Unexpected type: {type(path)}"
        return res
    def calc_bounds(self):
        return max_bounds(*[tp.bounds for tp in self.toolpaths])
    def lines_to_arcs(self):
        return Toolpaths([tp.lines_to_arcs() for tp in self.toolpaths])
    def optimize_lines(self):
        return Toolpaths([tp.optimize_lines() for tp in self.toolpaths])
    def optimize(self):
        return Toolpaths([tp.optimize() for tp in self.toolpaths])
    def is_empty(self):
        return all([tp.is_empty() for tp in self.toolpaths])
    def for_tab_below(self):
        return Toolpaths([i.for_tab_below() for i in self.toolpaths])

def findPathNesting(tps):
    nestings = []
    contours = Toolpaths(tps).flattened()
    contours = sorted(contours, key=lambda item: bounds_area(item.bounds))
    for subtp in contours:
        for children in nestings:
            if inside_bounds(children[-1].bounds, subtp.bounds):
                # subtp contains this chain of contours
                children.append(subtp)
                break
        else:
            # Doesn't contain any earlier contour, so start a nesting.
            nestings.append([subtp])
    return nestings

def fixPathNesting(tps):
    nestings = findPathNesting(tps)
    res = []
    nestings = sorted(nestings, key=len)
    for nesting in nestings:
        res += nesting
    return res

# XXXKF this may cut corners sometimes, need to add collision checking
def joinClosePaths(tps):
    def findClosest(points, lastpt, diameter):
        mindist = None
        closest = 0
        for i, pt in enumerate(points):
            if i == 0 or dist(lastpt, pt) < mindist:
                closest = i
                mindist = dist(lastpt, pt)
        if closest > 0 and mindist <= diameter:
            points = points[closest:] + points[:closest]
        return points, mindist

    tps = fixPathNesting(tps)
    last = None
    res = []
    for tp in tps:
        if isinstance(tp, Toolpaths):
            res.append(tp)
            last = None
            continue
        if last is not None and last.tool is tp.tool:
            points = tp.path.nodes
            found = False
            if tp.path.closed:
                points, mindist = findClosest(points, lastpt, tp.tool.diameter)
                if mindist > tp.tool.diameter:
                    # Desperate second-chance joining by retracing the already milled path
                    # XXXKF this is rather bad, O(N^2), needs rethinking
                    for j in range(len(last.path.nodes) - 1, 0, -1):
                        points, mindist = findClosest(points, last.path.nodes[j], tp.tool.diameter)
                        if mindist <= tp.tool.diameter:
                            res[-1] = Toolpath(Path(last.path.nodes + (last.path.nodes[0:1] if last.path.closed else []) + last.path.nodes[:j - 1:-1] + points + points[0:1], False), tp.tool)
                            last = res[-1]
                            lastpt = last.path.nodes[-1]
                            found = True
                            break
            if found:
                continue
            if dist(lastpt, points[0]) <= tp.tool.diameter:
                res[-1] = Toolpath(Path(last.path.nodes + (last.path.nodes[0:1] if last.path.closed else []) + points + (points[0:1] if tp.path.closed else []), False), tp.tool)
                last = res[-1]
                lastpt = last.path.nodes[-1]
                continue
        res.append(tp)
        lastpt = tp.path.seg_end()
        last = tp
    return res

def joinClosePathsWithCollisionCheck(tps, boundary, islands):
    def findClosest(points, lastpt, diameter):
        mindist = None
        closest = 0
        for i, pt in enumerate(points):
            if i == 0 or dist(lastpt, pt) < mindist:
                closest = i
                mindist = dist(lastpt, pt)
        if closest > 0 and mindist <= diameter:
            points = points[closest:] + points[:closest]
        return points, mindist

    last = None
    res = []
    for tp in tps:
        if isinstance(tp, Toolpaths):
            res.append(tp)
            last = None
            continue
        if last is not None and last.tool is tp.tool:
            points = tp.path.nodes
            found = False
            if tp.path.closed:
                points, mindist = findClosest(points, lastpt, tp.tool.diameter)
                if dist(lastpt, points[0]) <= tp.tool.diameter:
                    new_path = IntPath([lastpt, points[0]])
                    if new_path.int_points[0] == new_path.int_points[1]:
                        res[-1] = Toolpath(Path(last.path.nodes + (last.path.nodes[0:1] if last.path.closed else []) + points + (points[0:1] if tp.path.closed else []), False), tp.tool)
                        last = res[-1]
                        lastpt = last.path.nodes[-1]
                        continue
                    # XXXKF workaround clipper bug
                    if not boundary or not run_clipper_checkpath(CT_DIFFERENCE, subject_polys=[], clipper_polys=boundary, subject_paths=[new_path], fillMode=PFT_NONZERO):
                        if not islands or not run_clipper_checkpath(CT_INTERSECTION, subject_polys=[], clipper_polys=islands, subject_paths=[new_path], fillMode=PFT_NONZERO):
                            res[-1] = Toolpath(Path(last.path.nodes + (last.path.nodes[0:1] if last.path.closed else []) + points + (points[0:1] if tp.path.closed else []), False), tp.tool)
                            last = res[-1]
                            lastpt = last.path.nodes[-1]
                            continue
        res.append(tp)
        lastpt = tp.path.seg_end()
        last = tp
    return res

def findHelicalEntryPoints(toolpaths, tool, boundary, islands, margin):
    boundary_path = IntPath(boundary)
    boundary_path = boundary_path.force_orientation(True)
    island_paths = [IntPath(i).force_orientation(True) for i in islands]
    for tp in toolpaths:
        if type(tp) is Toolpaths:
            findHelicalEntryPoints(tp.toolpaths, tool, boundary, islands, margin)
            continue
        candidates = [tp.path.nodes[0]]
        if len(tp.path.nodes) > 1 and False:
            p1 = tp.path.nodes[0]
            p2 = tp.path.nodes[1]
            mid = p1
            angle = atan2(p2[1] - p1[1], p2[0] - p1[0]) + pi / 2
            d = tool.diameter * 0.5
            candidates.append((mid[0] + cos(angle) * d, mid[1] + sin(angle) * d))
            d = tool.diameter * -0.5
            candidates.append((mid[0] + cos(angle) * d, mid[1] + sin(angle) * d))
        for start in candidates:
            # Size of the helical entry hole
            mr = tool.min_helix_diameter
            d = (tool.diameter + 2 * mr) + 2 * margin
            c = IntPath(circle(start.x, start.y, d / 2))
            # Check if it sticks outside of the final shape
            # XXXKF could be optimized by doing a simple bounds check first
            if run_clipper_simple(CT_DIFFERENCE, [c], [boundary_path], bool_only=True):
                continue
            # Check for collision with islands
            if islands and any([run_clipper_simple(CT_INTERSECTION, [i], [c], bool_only=True) for i in island_paths]):
                continue
            tp.helical_entry = HelicalEntry(start, mr)
            break

def startWithClosestPoint(path, pt, dia):
    mindist = None
    mdpos = None
    for j, pt2 in enumerate(path.path.nodes):
        d = dist(pt, pt2)
        if mindist is None or d < mindist:
            mindist = d
            mdpos = j
    if mindist <= dia:
        path.path.nodes = path.path.nodes[mdpos:] + path.path.nodes[:mdpos + 1]
        return True
    return False

def mergeToolpaths(tps, new, dia):
    if type(new) is Toolpath:
        new = [new]
    else:
        new = new.toolpaths
    if not tps:
        tps.insert(0, Toolpaths(new))
        return
    last = tps[-1]
    new2 = []
    for i in new:
        assert i.path.closed
        pt = i.path.seg_start()
        found = False
        new_toolpaths = []
        for l in last.toolpaths:
            if found:
                new_toolpaths.append(l)
                continue
            if startWithClosestPoint(l, pt, dia):
                new_toolpaths.append(i)
                new_toolpaths.append(l)
                found = True
            else:
                new_toolpaths.append(l)
        if not found:
            new_toolpaths.append(i)
        last.set_toolpaths(new_toolpaths)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.nn.parallel
import torch.optim
import torch.utils.data
import random
import numpy as np
import higher
from torch.utils.tensorboard import SummaryWriter
import datetime
import copy
from models import *
import itertools
import time
from torchmetrics import Accuracy, F1, MatthewsCorrcoef

class BaseModel(nn.Module):
    def __init__(self, args, device):
        super().__init__()

        self.device = device

        if args.data_type == '4d5_syn' or args.data_type == '4d5_exp': self.num_classes = 3
        elif args.data_type == '5a12_2ag': self.num_classes = 4
        elif args.data_type.startswith('5a12_PUL'): self.num_classes = 2

        self.input_size = 17 #input sequence length
        self.ntokens = 21 #transformer embedding vocabulary

        #base model selection
        if args.base_model == 'cnn':
            filters, dense  = 512, 512
            self.model = CNN(input_size = self.input_size, conv_filters = filters,
                                 dense_nodes = dense, n_out = self.num_classes, kernel_size = args.kernel, dropout = args.dropout).to(self.device)

        elif args.base_model == 'transformer' :
            self.model = Transformer(ntoken = self.ntokens, emb_dim = 32, nhead = 2, nhid = 128, nlayers = 1,
                     n_classes = self.num_classes, seq_len = self.input_size, dropout = args.dropout,
                     out_dim = 512).to(self.device)

        elif args.base_model == 'logistic_regression' :
            self.model = LogisticRegression(input_size = self.input_size, n_classes = self.num_classes).to(self.device).to(self.device)

        elif args.base_model == 'mlp':
            self.model = MLP(input_size = self.input_size, hdim1 = 256, hdim2 = 512,
                             n_out = self.num_classes, dropout = args.dropout).to(self.device)

        #learning rate, & lr schedule, loss fn
        self.learning_rate = args.learn_rate

        if args.opt_id == 'sgd': self.optimizer = torch.optim.SGD(self.model.parameters(), lr=self.learning_rate, momentum=0.9)
        elif args.opt_id == 'adam':  self.optimizer = torch.optim.Adam(self.model.parameters(), lr=self.learning_rate, amsgrad=True, eps = 1e-8)

        else: self.optimizer = torch.optim.SGD(self.model.parameters(), lr=self.learning_rate, momentum=0.9)

        self.lr_scheduler = args.lr_scheduler

        if self.lr_scheduler: self.scheduler = torch.optim.lr_scheduler.MultiStepLR(self.optimizer, milestones=[15,30], gamma=0.1)
        else: self.scheduler = None

        self.loss_fn = nn.CrossEntropyLoss().to(self.device)

    def get_predictions(self,model, X, mask = None):

        if model.__class__.__name__ =='Transformer' or model.__class__.__name__ =='FunctionalTransformer':
            pred = model(X)
        else:
            pred = model(X.float())
        return pred

    def mlc_get_predictions(self,model, X):

        if model.__class__.__name__ =='Transformer' or model.__class__.__name__ =='FunctionalTransformer':
            pred = model(X, return_h=True)
        else:
            pred = model(X.float(), return_h=True)
        return pred

    def train_step(self,train_dataloader,meta_loader, epoch, tensorboard_writer, batch_size):
        train_loss = 0
        f1 = F1(num_classes = self.num_classes).to(self.device)
        mcc = MatthewsCorrcoef(num_classes = self.num_classes).to(self.device)

        self.model.train()
        for batch, (X, labels) in enumerate(train_dataloader):
            X = X.to(self.device)
            labels = labels.to(self.device)
            pred = self.get_predictions(self.model, X)
            loss = self.loss_fn(pred,labels)
            train_loss = loss.item()
            tensorboard_writer.add_scalar('train/ Loss', train_loss, epoch * len(train_dataloader) + batch)

            self.optimizer.zero_grad()
            loss.backward()
            self.optimizer.step()

            if self.scheduler is not None: self.scheduler.step()

            with torch.no_grad():
                predicted = (F.softmax(pred,1).data.argmax(1))
                batch_f1_mtr = f1(predicted,labels) #open bug in torchmetrics F1, therefore, softmax must be applied prior to calc
                batch_mcc_mtr = mcc(pred,labels)

        epoch_f1 = f1.compute()
        epoch_mcc = mcc.compute()

        print('\nTrain Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                        epoch, batch, len(train_dataloader),
                        100. * batch / len(train_dataloader), train_loss))
        print(f'Train F1 score: {epoch_f1 }')
        print(f'Train MCC: {epoch_mcc}')

        tensorboard_writer.add_scalar('train/ F1', epoch_f1, epoch)
        tensorboard_writer.add_scalar('train/ MCC', epoch_mcc, epoch)
        tensorboard_writer.flush()

    def test_step(self, test_loader,epoch, tensorboard_writer):
        self.model.eval()
        test_loss = 0
        f1 = F1(num_classes = self.num_classes, compute_on_step=False).to(self.device)
        mcc = MatthewsCorrcoef(num_classes = self.num_classes, compute_on_step=False).to(self.device)

        with torch.no_grad():
            for batch_idx, (inputs, labels) in enumerate(test_loader):
                inputs, labels = inputs.to(self.device), labels.to(self.device)
                outputs = self.get_predictions(self.model, inputs)
                test_loss +=F.cross_entropy(outputs, labels).item()
                predicted = (F.softmax(outputs,1).data.argmax(1))

                f1(predicted,labels) #open bug in torchmetrics F1, therefore, softmax must be applied prior to calc
                mcc(outputs,labels)

        epoch_f1 = f1.compute()
        epoch_mcc = mcc.compute()
        test_loss /= len(test_loader.dataset)

        tensorboard_writer.add_scalar('val/ Loss',test_loss,epoch)
        tensorboard_writer.add_scalar('val/ F1', epoch_f1, epoch)
        tensorboard_writer.add_scalar('val/ MCC', epoch_mcc, epoch)
        tensorboard_writer.flush()

        print(f'Val set: Average loss: {test_loss}')
        print(f"Val set Avg MCC: {epoch_mcc}")

        return epoch_f1, epoch_mcc

    def eval_training_batch(self, f1, mcc, minibatch_loss, epoch, batch_idx, outputs, labels, length_train_loader, tensorboard_writer):

        with torch.no_grad():
            #-------------        Record Train  Metrics -----------------
            train_loss = minibatch_loss.item()
            tensorboard_writer.add_scalar('train/ Loss', train_loss, epoch * length_train_loader + batch_idx)
            preds = (F.softmax(outputs,1).data.argmax(1))

            batch_f1_mtr = f1(preds,labels) #open bug in torchmetrics F1, therefore, softmax must be applied prior to calc
            batch_mcc_mtr = mcc(outputs,labels)

            if batch_idx % 10000 == 0:
                print('\nEpoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( epoch, batch_idx, length_train_loader, 100. * batch_idx / length_train_loader, train_loss))
                print(f'Train F1 score: {batch_f1_mtr}')
                print(f'Train MCC score: {batch_mcc_mtr}')
            tensorboard_writer.flush()
        return batch_f1_mtr, batch_mcc_mtr

    def eval_meta_batch(self, f1, mcc, minibatch_loss, epoch, batch_idx, outputs, labels, length_train_loader, tensorboard_writer):

        with torch.no_grad():
            #-------------        Record Train  Metrics -----------------
            train_loss = minibatch_loss.item()
            tensorboard_writer.add_scalar('meta/ Loss', train_loss, epoch * length_train_loader + batch_idx)
            preds = (F.softmax(outputs,1).data.argmax(1))

            batch_f1_mtr = f1(preds,labels) #open bug in torchmetrics F1, therefore, softmax must be applied prior to calc
            batch_mcc_mtr = mcc(outputs,labels)

            if batch_idx % 10000 == 0:
                print('Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( epoch, batch_idx, length_train_loader, 100. * batch_idx / length_train_loader, train_loss))
                print(f'Meta F1 score: {batch_f1_mtr}')
                print(f'Meta MCC score: {batch_mcc_mtr}')
            tensorboard_writer.flush()
        return batch_f1_mtr, batch_mcc_mtr


# !@coding  :utf-8
# !@Time    :2021/2/7 16:00
# !@Author  :liulei

business_view_btn = ('xpath', '//a[@name="menu-20301"]')
business_view_check_page = ('xpath', '//li[text()="报表一览"]')

tax_declaration_btn = ('xpath', '//*[@name="menu-20302"]')
tax_declaration_check_page = ('xpath', '//li[text()="税款申报"]')

zero_declaration_btn = ('xpath', '//*[@name="menu-20303"]')
zero_declaration_check_page = ('xpath', '//li[text()="零申报"]')

pay_btn = ('xpath', '//*[@name="menu-20304"]')
pay_check_page = ('xpath', '//li[text()="缴款"]')

fail_declare_btn = ('xpath', '//*[@name="menu-20305"]')
fail_declare_check_page = ('xpath', '//li[text()="漏报检查"]')

task_manager_btn = ('xpath', '//a[@name="menu-20306"]')
task_manager_check_page = ('xpath', '//li[text()="任务管理"]')

setting_btn = ('xpath', '//*[@name="menu-20307"]')
setting_check_page = ('xpath', '//li[text()="设置"]')

page_list = [business_view_btn, tax_declaration_btn, zero_declaration_btn, pay_btn, fail_declare_btn, task_manager_btn,
             setting_btn]
check_list = [business_view_check_page, tax_declaration_check_page, zero_declaration_check_page, pay_check_page,
              fail_declare_check_page, task_manager_check_page, setting_check_page]