import collections
import math
import numbers

from simian.public.proto import motion_model_pb2
from simian.public.transforms import proto_util

_Phase = collections.namedtuple("_Phase", "end_time command")

# General support for pre-canned motion commands. Skipping trajectory
# and sequence mode commands for now.
class Sequencer:
    @classmethod
    def FromSpec(cls, motion_command_sequence_proto):
        """Converts a MotionCommandSequence proto to a Sequencer object with specified commands."""
        sequencer = cls()
        for single_command in motion_command_sequence_proto.command_list:
            sequencer._total_duration += single_command.duration
            sequencer._phases.append(_Phase(sequencer._total_duration, single_command.command))
        return sequencer

    def __init__(self):
        self._time = 0.0
        self._total_duration = 0.0
        self._phases = []

    def get_total_duration(self):
        return self._total_duration

    def parse_list_of_dicts(self, specs):
        _dispatch = {
            "velocity_yawrate": self.parse_velocity_yawrate,
            "acceleration_yawrate": self.parse_acceleration_yawrate,
            "normalized_dbw": self.parse_normalized_dbw,
            "velocity_steering": self.parse_velocity_steering,
            "normalized_torque_steering": self.parse_normalized_torque_steering,
            "force_brake_steering": self.parse_force_brake_steering,
            "normalized_dbw_gear": self.parse_normalized_dbw_gear,
            "rover_wheel_command": self.parse_rover_wheel_command,
            "composite_vehicle_command": self.parse_and_append_composite_vehicle_command,
        }
        for spec in specs:
            for key, value in spec.items():
                if key not in _dispatch:
                    raise ValueError('Invalid motion command type "%s".' % key)
                _dispatch[key](value)

    def parse_velocity_yawrate(self, spec):
        for phase in spec:
            self.append_velocity_yawrate(phase["duration"], phase["velocity"], phase["yawrate"])

    def append_velocity_yawrate(self, duration, velocity, yawrate):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.velocity_yawrate.velocity = velocity
        command.velocity_yawrate.yawrate = yawrate
        self._phases.append(_Phase(self._total_duration, command))

    def parse_acceleration_yawrate(self, spec):
        for phase in spec:
            self.append_acceleration_yawrate(
                phase["duration"], phase["acceleration"], phase["yawrate"]
            )

    def append_acceleration_yawrate(self, duration, acceleration, yawrate):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.acceleration_yawrate.acceleration = acceleration
        command.acceleration_yawrate.yawrate = yawrate
        self._phases.append(_Phase(self._total_duration, command))

    def parse_normalized_dbw(self, spec):
        for phase in spec:
            self.append_normalized_dbw(
                phase["duration"], phase["brake"], phase["throttle"], phase["steering"]
            )

    def append_normalized_dbw(self, duration, brake, throttle, steering):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        if brake < 0.0 or brake > 1.0:
            raise ValueError("Invalid brake %f (must be between 0 and 1)" % brake)
        if throttle < 0.0 or throttle > 1.0:
            raise ValueError("Invalid throttle %f (must be between 0 and 1)" % throttle)
        if abs(steering) > 1.0:
            raise ValueError("Invalid steering %f (must be between -1 and 1)" % steering)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.normalized_dbw.brake = brake
        command.normalized_dbw.throttle = throttle
        command.normalized_dbw.steering = steering
        self._phases.append(_Phase(self._total_duration, command))

    def parse_velocity_steering(self, spec):
        for phase in spec:
            self.append_velocity_steering(
                phase["duration"], phase["velocity"], phase["steering_angle"]
            )

    def append_velocity_steering(self, duration, velocity, steering_angle):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.velocity_steering.velocity = velocity
        command.velocity_steering.steering_angle = steering_angle
        self._phases.append(_Phase(self._total_duration, command))

    def parse_normalized_torque_steering(self, spec):
        for phase in spec:
            self.append_normalized_torque_steering(
                phase["duration"], phase["torque"], phase["steering"], phase.get("brake", 0.0)
            )

    def append_normalized_torque_steering(self, duration, torque, steering, brake):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        if abs(torque) > 1.0:
            raise ValueError("Invalid torque %f (must be between -1 and 1)" % torque)
        if abs(steering) > 1.0:
            raise ValueError("Invalid steering %f (must be between -1 and 1)" % steering)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.normalized_torque_steering.torque = torque
        command.normalized_torque_steering.steering = steering
        command.normalized_torque_steering.brake = brake
        self._phases.append(_Phase(self._total_duration, command))

    def parse_force_brake_steering(self, spec):
        for phase in spec:
            self.append_force_brake_steering(
                phase["duration"], phase["motor_force"], phase["brake"], phase["steering"]
            )

    def append_force_brake_steering(self, duration, motor_force, brake, steering):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        if motor_force < 0.0:
            raise ValueError("Invalid motor_force %f (must be positive)" % motor_force)
        if brake > 1.0 or brake < 0.0:
            raise ValueError("Invalid brake %f (must be between 0 and 1)" % brake)
        if abs(steering) > 1.0:
            raise ValueError("Invalid steering %f (must be between -1 and 1)" % steering)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.force_brake_steering.motor_force = motor_force
        command.force_brake_steering.brake = brake
        command.force_brake_steering.steering = steering
        self._phases.append(_Phase(self._total_duration, command))

    def parse_normalized_dbw_gear(self, spec):
        for phase in spec:
            self.append_normalized_dbw_gear(
                phase["duration"],
                phase["brake"],
                phase["throttle"],
                phase["steering"],
                phase["gear"],
            )

    def append_normalized_dbw_gear(self, duration, brake, throttle, steering, gear):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        if brake < 0.0 or brake > 1.0:
            raise ValueError("Invalid brake %f (must be between 0 and 1)" % brake)
        if throttle < 0.0 or throttle > 1.0:
            raise ValueError("Invalid throttle %f (must be between 0 and 1)" % throttle)
        if abs(steering) > 1.0:
            raise ValueError("Invalid steering %f (must be between -1 and 1)" % steering)
        if gear < 1:
            raise ValueError("Invalid gear %f (must be greater than 0)" % gear)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.normalized_dbw_gear.brake = brake
        command.normalized_dbw_gear.throttle = throttle
        command.normalized_dbw_gear.steering = steering
        command.normalized_dbw_gear.gear = int(gear)
        self._phases.append(_Phase(self._total_duration, command))

    def parse_rover_wheel_command(self, spec):
        for phase in spec:
            self.append_rover_wheel_command(
                phase["duration"], phase["fl"], phase["fr"], phase["rl"], phase["rr"]
            )

    def append_rover_wheel_command(self, duration, fl, fr, rl, rr):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        self._total_duration += duration
        command = motion_model_pb2.Input()

        command.rover_wheel_command.fl.steering = fl["steering"]
        command.rover_wheel_command.fl.ang_vel = fl["ang_vel"]

        command.rover_wheel_command.fr.steering = fr["steering"]
        command.rover_wheel_command.fr.ang_vel = fr["ang_vel"]

        command.rover_wheel_command.rl.steering = rl["steering"]
        command.rover_wheel_command.rl.ang_vel = rl["ang_vel"]

        command.rover_wheel_command.rr.steering = rr["steering"]
        command.rover_wheel_command.rr.ang_vel = rr["ang_vel"]

        self._phases.append(_Phase(self._total_duration, command))

    def parse_and_append_composite_vehicle_command(self, spec):
        for phase in spec:
            command = motion_model_pb2.Input()
            cmd_short = command.composite_vehicle_command

            # Duration
            duration = phase["duration"]
            if duration <= 0.0:
                raise ValueError("Invalid duration %f (must be positive)" % duration)
            self._total_duration += duration

            # Brake input
            if "normalized_brake" in phase:
                cmd_short.brake_input.normalized_brake = phase["normalized_brake"]
            else:
                raise ValueError("Received unexpected or no brake_input.")

            # Powertrain input
            if "normalized_throttle" in phase:
                cmd_short.powertrain_input.normalized_throttle = phase["normalized_throttle"]
            elif "motor_torque" in phase:
                cmd_short.powertrain_input.motor_torque = phase["motor_torque"]
            elif "normalized_motor_torque" in phase:
                cmd_short.powertrain_input.normalized_motor_torque = phase[
                    "normalized_motor_torque"
                ]
            else:
                raise ValueError("Received unexpected or no powertrain_input.")

            # Steering input
            if "angle_rate" in phase:
                cmd_short.steering_input.angle_rate = phase["angle_rate"]
            elif "normalized_angle" in phase:
                cmd_short.steering_input.normalized_angle = phase["normalized_angle"]
            elif "normalized_angle_rate" in phase:
                cmd_short.steering_input.normalized_angle_rate = phase["normalized_angle_rate"]
            else:
                raise ValueError("Received unexpected or no steering_input.")

            self._phases.append(_Phase(self._total_duration, command))

    # Currently a bit of a one-off for when the caller already has a
    # state. As opposed to the others which are geared toward manual
    # text-based specification.
    def append_override_state(self, duration, state2d):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.override_state.MergeFrom(proto_util.state2d_to_proto(state2d))
        self._phases.append(_Phase(self._total_duration, command))

    def is_empty(self):
        return len(self._phases) == 0

    def assert_nonempty(self):
        if not self._phases:
            raise ValueError("Empty motion command sequence.")

    def create_command_relative_time(self, dt):
        return self.create_command_absolute_time(self._time + _to_value(dt))

    # Note this works (fingers crossed) for tt being either a number
    # or a datetime. Under the hood, it is all getting converted to
    # seconds, represented as a floating point for historical
    # reasons. Using a datetime or timedelta could be better here,
    # especially if the create_command_relative_time() method is used,
    # as that can accumulate roundoff errors.
    def create_command_absolute_time(self, tt):
        self.assert_nonempty()
        self._time = math.fmod(_to_value(tt), self._total_duration)
        # Simple linear search suffice for now, we don't expect very
        # long precanned sequences.
        for phase in self._phases:
            if phase.end_time < self._time:
                continue
            return phase.command
        raise Exception("Bug? Fell off the end of the precanned motion command sequence.")

def _to_value(value):
    if isinstance(value, numbers.Number):
        return value
    # For now assume the only alternative is what we use for sim_time
    # method arg plumbing (as opposed to sim_time in sim data proto
    # which is just a float).
    return 3600 * value.hour + 60 * value.minute + value.second + 1e-6 * value.microsecond


# -*- coding: utf-8 -*-

from eaglet.decorator import param_required

from business import model as business_model
from db.mall import models as mall_models

from business.mall.corporation_factory import CorporationFactory

class EmailNotification(business_model.Model):
	"""
	邮件通知
	"""
	__slots__ = (
		'id',
		'email_addresses',  #收件人地址，'|'分割
		'black_member_ids',  #需要过滤的会员id，'|'分割，会员id
		'type',
		'is_active',
		'created_at'  # 添加时间
	)

	AFTER_CREATE_ORDER = mall_models.PLACE_ORDER  # 下单后
	AFTER_PAY_ORDER = mall_models.PAY_ORDER  # 付款后
	AFTER_SHIP_ORDER = mall_models.SHIP_ORDER  # 发货后
	AFTER_FINISH_ORDER = mall_models.SUCCESSED_ORDER  # 完成订单后
	AFTER_CANCEL_ORDER = mall_models.CANCEL_ORDER  # 取消订单后

	def __init__(self, db_model=None):
		business_model.Model.__init__(self)

		if db_model:
			self._init_slot_from_model(db_model)

			if db_model.status == mall_models.PLACE_ORDER:
				self.type = 'after_create_order'
			elif db_model.status == mall_models.PAY_ORDER:
				self.type = 'after_pay_order'
			elif db_model.status == mall_models.SHIP_ORDER:
				self.type = 'after_ship_order'
			elif db_model.status == mall_models.SUCCESSED_ORDER:
				self.type = 'after_finish_order'
			elif db_model.status == mall_models.CANCEL_ORDER:
				self.type = 'after_cancel_order'
			else:
				self.type = 'unknown'

			self.email_addresses = [] if len(db_model.emails) == 0 else db_model.emails.split('|')
			self.black_member_ids = [] if len(db_model.black_member_ids) == 0 else db_model.black_member_ids.split('|')

	def enable(self):
		"""
		启用
		"""
		self.is_active = True
		mall_models.UserOrderNotifySettings.update(is_active=True).dj_where(id=self.id).execute()

	def disable(self):
		"""
		禁用
		"""
		self.is_active = False
		mall_models.UserOrderNotifySettings.update(is_active=False).dj_where(id=self.id).execute()

	def update(self, email_addresses, black_member_ids):
		"""
		"""
		email_addresses = '|'.join(email_addresses)
		black_member_ids = '|'.join(black_member_ids)

		corp_id = CorporationFactory.get().id
		mall_models.UserOrderNotifySettings.update(emails=email_addresses, black_member_ids=black_member_ids).dj_where(user_id=corp_id, id=self.id).execute()


from aiogram import Dispatcher
from aiogram.dispatcher.webhook import WebhookRequestHandler
from aiohttp import web
from functools import partial
from .singleton import Singleton
from logging import getLogger
logger = getLogger('GitHubBot.telegram.Executor')

class HookExecutor(metaclass=Singleton):
    def __init__(self, dispatcher, **kwargs):
        self.dispatcher = dispatcher
        self.skip_updates = kwargs['skip_updates']
        self.check_ip = kwargs['check_ip']
        self.retry_after = kwargs['retry_after']
        self.loop = kwargs['loop']
        self.on_startup = kwargs['on_startup']
        self.on_shutdown = kwargs['on_shutdown']
        self._web_app = None
        self._frozen = False

        from aiogram import Bot, Dispatcher
        Bot.set_current(dispatcher.bot)
        Dispatcher.set_current(dispatcher)

        self._setup()

    @property
    def _assert_not_frozen(self):
        if self._frozen:
            raise RuntimeError("Execution is frozen!")

    @property
    def web_app(self):
        return self._web_app

    def _setup(self, webhook_path='/', handler=WebhookRequestHandler):
        self._assert_not_frozen()
        self._frozen = True

        if self.web_app: return

        self._web_app = web.Application()

        self._web_app['RETRY_AFTER'] = self.retry_after | None

        self._web_app.router.add_route('*', webhook_path, handler, name="tg_webhook_handler")

        async def _wrap_callback(cb, _):
            return await cb(self.dispatcher)

        for callback in self.on_startup:
            self._web_app.on_startup.append(partial(_wrap_callback, callback))

        for callback in self.on_shutdown:
            self._web_app.on_shutdown.append(partial(_wrap_callback, callback))

        self._web_app['APP_EXECUTOR'] = self
        self._web_app['BOT_DISPATCHER'] = self.dispatcher
        self._web_app['_check_ip'] = self.check_ip


import string
from nltk.corpus import stopwords
import spacy
from spacy.lang.es.examples import sentences

def clean_text(text, filterStopwords=False, filterPos=None, lang="es"):

	cleanTokens = []
	stopwordList = []
	nlp = None

	if lang=="es":
		nlp = spacy.load('es_core_news_sm')
		stopwordList = stopwords.words('spanish')
		doc = nlp(text)

	elif lang =="en":
		stopwordList = stopwords.words('english')
		nlp = spacy.load('en_core_web_sm')
		doc = nlp(text)

	else:
		return None

	for token in doc:
		#ignore usernames, hashtags, urls and numbers
		if not token.text.startswith("@") and not token.like_url and not token.like_email and not token.like_num and not token.text.startswith("#"):
			if filterPos and not filterStopwords:
				if token.pos_ in filterPos:
					cleanTokens.append(token.text)

			elif filterStopwords and not filterPos:
				if token.text not in stopwordList:
					cleanTokens.append(token.text)

			elif filterStopwords and filterPos:
				if token.text not in stopwordList and token.pos_ in filterPos:
					cleanTokens.append(token.text)

			elif not filterStopwords and not filterPos:
				cleanTokens.append(token.text)

	return cleanTokens

def clean_get_lemmas(text):
	nlp = spacy.load('es_core_news_sm')
	cleanTokens = []
	doc = nlp(text)

	for token in doc:
		cleanTokens.append(token.lemma_)

	return cleanTokens


# -*- coding: mbcs -*-
# Do not delete the following import lines
from abaqus import *
from abaqusConstants import *
import __main__
import visualization
import xyPlot
import displayGroupOdbToolset as dgo
import csv

def openOdb(odbName):
    if odbName is None:
        # ===== Read the .odb file opened in current viewport, so make sure to open the correct .odb file in Abaqus CAE =====
        vp = session.viewports[session.currentViewportName]
        odbName = vp.odbDisplay.name
        odb = session.odbs[odbName]
    else:
        odb = session.openOdb(name=odbName)
    return odb

def cleanXYDataInCurrentSession():
    for xyDataName in session.xyDataObjects.keys():
        del session.xyDataObjects[xyDataName]
    return

def plotResponseAndSave(nodeLabels, odbName=None, stepNames=None, instanceName=None, timeReduction=0):
    # NOTE: Abaqus' built-in xyPlot can get field outputs way faster than getting them frame by frame in Python.
    # So it's recommended to use plotResponseAndSave() over getResponseAndSave.
    # NOTE 2: Unfortunately, for unknown reason, plotResponseAndSave() can only be run with GUI. xyPlot.xyDataListFromField will raise an error with noGUI option.
    # /// Handle input variables
    if type(nodeLabels) is not list:
        nodeLabels = [nodeLabels]
    odb = openOdb(odbName)
    odbName = odb.name # NOTE: In case the input odbName is None
    if stepNames is None:
        stepNames = odb.steps.keys()
    elif stepNames is not None and type(stepNames) is not list:
        stepNames = [stepNames]
    if instanceName is None and len(odb.rootAssembly.instances) == 1:
        instanceName = odb.rootAssembly.instances.keys()[0]
    else:
        raise ValueError('The model contains multiple instances. instanceName must be defined.')
    cleanXYDataInCurrentSession()
    quantities = ['U', 'V', 'A']
    for nodeLabel in nodeLabels:
        xyData = [['Time(s)', 'X|(m)', 'Y-(m)', 'Z.(m)', 'X|(m/s)', 'Y-(m/s)', 'Z.(m/s)', 'X|(m/s2)', 'Y-(m/s2)', 'Z.(m/s2)']]
        suffix = 'PI: %s N: %d'%(instanceName, nodeLabel)
        for stepName in stepNames:
            session.odbData[odbName].setValues(activeFrames=((stepName, ('0:-1', )), ))
            xyList = xyPlot.xyDataListFromField(odb=odb, outputPosition=NODAL, variable=(
                ('U', NODAL, ((COMPONENT, 'U1'), (COMPONENT, 'U2'), (COMPONENT, 'U3'), )),
                ('V', NODAL, ((COMPONENT, 'V1'), (COMPONENT, 'V2'), (COMPONENT, 'V3'), )),
                ('A', NODAL, ((COMPONENT, 'A1'), (COMPONENT, 'A2'), (COMPONENT, 'A3'), )),
                ), nodeLabels=((instanceName, (nodeLabel, )), ))
            times = [x[0] for x in session.xyDataObjects['_U:U1 '+suffix]]
            for i, time in enumerate(times):
                line = ['%.5f'%(time - timeReduction)]
                for quantity in quantities:
                    for component in [1, 2, 3]:
                        line.append(session.xyDataObjects['_%s:%s%d %s'%(quantity, quantity, component, suffix)][i][1])
                xyData.append(line)
        with open('disp_vel_accel.%s.%s.csv'%(instanceName, nodeLabel), 'wb') as f:
            writer = csv.writer(f)
            writer.writerows(xyData)
    return

# def getNodeIndex(odb, instanceName, nodeLabel, stepName, fieldOutputName):
#     ''' Check whether instance and node label exist and find the corresponding index for getting field output values '''
#     if len(odb.rootAssembly.instances) > 1:
#         if instanceName is None:
#             raise ValueError('Instance Name must be specified if there are more than 1 instance in the model.')
#         if instanceName not in odb.rootAssembly.instances.keys():
#             raise ValueError('The specified instance %s does not exist in the model. Available names include %s'%(instanceName, ', '.join(odb.rootAssembly.instances.keys())))
#         nodeIndex = None
#         for i, value in enumerate(odb.steps[stepName].frames[0].fieldOutputs[fieldOutputName].values):
#             if value.instance is not None and value.instance.name == instanceName and value.nodeLabel == nodeLabel:
#                 nodeIndex = i
#                 print('Corresponding node index for node label %d is %d\n'%(nodeLabel, nodeIndex))
#                 break
#         if nodeIndex is None:
#             raise ValueError('Node label %d does not exist on instance %s.'%(nodeLabel, instanceName))
#     else:
#         nodeIndex = nodeLabel - 1
#     return nodeIndex

# def getResponseAndSave(nodeLabels, odbName=None, stepNames=None, instanceName=None, quantities=['U', 'V', 'A']):
#     # /// Handle input variables
#     if type(nodeLabels) is not list:
#         nodeLabels = [nodeLabels]
#     odb = openOdb(odbName)
#     if stepNames is None:
#         stepNames = odb.steps.keys()
#     elif stepNames is not None and type(stepNames) is not list:
#         stepNames = [stepNames]
#     # =====
#     components = {'U': ['X|(m)', 'Y-(m)', 'Z.(m)'], 'V': ['X|(m/s)', 'Y-(m/s)', 'Z.(m/s)'], 'A': ['X|(m/s2)', 'Y-(m/s2)', 'Z.(m/s2)']}
#     for nodeLabel in nodeLabels:
#         xyData = [['Time(s)']]
#         for quantity in quantities:
#             xyData[0].extend(components[quantity])
#         for stepName in stepNames:
#             nodeIndex = getNodeIndex(odb, instanceName, nodeLabel, stepName, quantities[0])
#             for frame in odb.steps[stepName].frames:
#                 line = ['%.5f'%frame.frameValue]
#                 for quantity in quantities:
#                     for i, componentLabels in enumerate(frame.fieldOutputs[quantity].componentLabels):
#                         line.append(frame.fieldOutputs[quantity].values[nodeIndex].data[i])
#                         # NOTE: For history output, can use odb.steps[stepName].historyRegions['Node %s.%d'%(instanceName, nodeLabel)].historyOutputs['%s%d'%(quantity, component)].data[i]
#                 xyData.append(line)
#         fileNames = {'U': 'disp', 'V': 'vel', 'A': 'accel'}
#         fileName = '_'.join([fileNames[quantity] for quantity in quantities]) + '.%d.csv'%nodeLabel
#         with open(fileName, 'wb') as f:
#             writer = csv.writer(f)
#             writer.writerows(xyData)

def plotAndSaveHistoryOutput(nodeLabels, odbName=None):
    if type(nodeLabels) is not list:
        nodeLabels = [nodeLabels]
    odb = openOdb(odbName)
    odbName = odb.name # NOTE: In case the input odbName is None
    historyOutputNames = session.odbData[odb.name].historyVariables.keys()
    quantities = ['Spatial displacement: U', 'Spatial velocity: V', 'Spatial acceleration: A']
    for nodeLabel in nodeLabels:
        xyData = []
        for quantity in quantities:
            for direction in [1, 2, 3]:
                prefix = quantity+str(direction)+' at Node '+str(nodeLabel)
                for historyOutputName in historyOutputNames:
                    if historyOutputName.startswith(prefix):
                        xyData.append(session.XYDataFromHistory(name=quantity[-1]+str(direction),
                            odb=odb, outputVariableName=historyOutputName))
                        break
        session.writeXYReport(
            fileName = 'disp_vel_accel.%s.rpt'%nodeLabel, appendMode=OFF, xyData=tuple(xyData))

if __name__ == '__main__':
    # nodeLabels = [8302, 8922]
    nodeLabels = [29406, 36011]
    # plotResponseAndSave(nodeLabels)
    plotAndSaveHistoryOutput(nodeLabels)


import spacy

# Cargar el modelo en español
nlp = spacy.load("es_core_news_sm")

def procesar_oracion(oracion):
    # Procesar la oración con spaCy
    doc = nlp(oracion)

    # Obtener las entidades nombradas encontradas
    entidades_nombradas = [{entidad.text: entidad.label_} for entidad in doc.ents]
    resultado_final = {k: v for dic in entidades_nombradas for k, v in dic.items()}

    return resultado_final

def procesar_lista(lista):
    resultados = []
    for elemento in lista:
        resultado = {}
        resultado["oracion"] = elemento
        resultado["entidades"] = procesar_oracion(elemento)
        resultados.append(resultado)

    return resultados


# https://programmers.co.kr/learn/courses/30/lessons/92335

# n의 base 진법으로 나타낸 수 구하기
def cal(n, base):
    ans = ''
    while n > 0 :
        n, r = divmod(n, base)
        ans += str(r)

    return ans[::-1]

def solution(n, k):
    # 변환한 수
    c_num = cal(n,k)
    # 소수의 개수
    cnt = 0
    # '0' 기준으로 나누기
    num_list = c_num.split('0')

    for num in num_list:
        # 연속된 0의 경우 ''가 나타날 수 있으므로
        if num == '':
            continue

        num = int(num)

        # 소수 판별하기
        result = True
        if num == 1 :
            continue

        for i in range(2, int(num**0.5)+1):
            if num % i == 0:
                result = False
                break

        if result :
            cnt += 1

    return cnt

n = 110011
k = 10
print(solution(n,k))

Programmers_Algorithm/level 2/k진수에서 소수 개수 구하기.py

k진수에서 소수 개수 구하기.py


import pandas as pd
import joblib
import gzip
from sklearn.linear_model import ElasticNetCV, LassoCV, RidgeCV
from sklearn.ensemble import GradientBoostingRegressor, VotingRegressor
from sklearn.model_selection import KFold, train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, OrdinalEncoder
from sklearn.impute import SimpleImputer
from sklearn.compose import ColumnTransformer
from mlxtend.regressor import StackingCVRegressor
from sklearn.metrics import ConfusionMatrixDisplay
from xgboost import XGBRegressor
from lightgbm import LGBMRegressor
import warnings
warnings.filterwarnings('ignore')

# Defineing necesaries variales columns
LotShape = ['IR3', 'IR2', 'IR1', 'Reg']
Utilities = ['ELO', 'NoSeWa', 'NoSewr', 'AllPub']
LandSlope = ['Sev', 'Mod', 'Gtl']
HouseStyle = ['1Story', '1.5Fin', '1.5Unf', '2Story', '2.5Fin', '2.5Unf', 'SFoyer', 'SLvl']
ExterQual = ['Po', 'Fa', 'TA', 'Gd', 'Ex']
ExterCond = ['Po', 'Fa', 'TA', 'Gd', 'Ex']
BsmtQual = ['NA', 'Po', 'Fa', 'TA', 'Gd', 'Ex']
BsmtCond = ['NA', 'Po', 'Fa', 'TA', 'Gd', 'Ex']
BsmtExposure = ['NA', 'No', 'Mn', 'Av', 'Gd']
BsmtFinType1 = ['NA', 'Unf', 'LwQ', 'Rec', 'BLQ', 'ALQ', 'GLQ']
BsmtFinType2 = ['NA', 'Unf', 'LwQ', 'Rec', 'BLQ', 'ALQ', 'GLQ']
HeatingQC = ['Po', 'Fa', 'TA', 'Gd', 'Ex']
CentralAir = ['N', 'Y']
Electrical = ['Mix', 'FuseP', 'FuseF', 'FuseA', 'SBrkr']
KitchenQual = ['Po', 'Fa', 'TA', 'Gd', 'Ex']
Functional = ['Sal', 'Sev', 'Maj2', 'Maj1', 'Mod', 'Min2', 'Min1', 'Typ']
FireplaceQu = ['NA', 'Po', 'Fa', 'TA', 'Gd', 'Ex']
GarageType = ['NA', 'Detchd', 'CarPort', 'BuiltIn', 'Basment', 'Attchd', '2Types']
GarageFinish = ['NA', 'Unf', 'RFn', 'Fin']
GarageQual = ['NA', 'Po', 'Fa', 'TA', 'Gd', 'Ex']
GarageCond = ['NA', 'Po', 'Fa', 'TA', 'Gd', 'Ex']
PavedDrive = ['N', 'P', 'Y']
PoolQC = ['NA', 'Fa', 'TA', 'Gd', 'Ex']
Fence = ['NA', 'MnWw', 'GdWo', 'MnPrv', 'GdPrv']
ord_cols_mf_cat = [Electrical, Functional, Utilities, KitchenQual]
ord_cols_na_cat = [LotShape, LandSlope, HouseStyle, ExterQual, ExterCond, BsmtQual,
                   BsmtCond, BsmtExposure, BsmtFinType1, BsmtFinType2, HeatingQC,
                   CentralAir, FireplaceQu, GarageType, GarageFinish, GarageQual,
                   GarageCond, PavedDrive, PoolQC, Fence]
num_cols_0 = ['MSSubClass', 'LotFrontage', 'LotArea', 'OverallQual', 'OverallCond',
              'YearBuilt', 'YearRemodAdd', 'MasVnrArea', 'BsmtFinSF1', 'BsmtFinSF2',
              'BsmtUnfSF', 'TotalBsmtSF', '1stFlrSF', '2ndFlrSF', 'LowQualFinSF',
              'GrLivArea', 'BsmtFullBath', 'BsmtHalfBath', 'FullBath', 'HalfBath',
              'BedroomAbvGr', 'KitchenAbvGr', 'TotRmsAbvGrd', 'Fireplaces',
              'GarageYrBlt', 'GarageCars', 'GarageArea', 'WoodDeckSF', 'OpenPorchSF',
              'EnclosedPorch', '3SsnPorch', 'ScreenPorch', 'PoolArea', 'MiscVal',
              'MoSold', 'YrSold']
ord_cols_mf = ['Electrical', 'Functional', 'Utilities', 'KitchenQual']
ord_cols_na = ['LotShape', 'LandSlope', 'HouseStyle', 'ExterQual', 'ExterCond',
               'BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2',
               'HeatingQC', 'CentralAir', 'FireplaceQu', 'GarageType', 'GarageFinish',
               'GarageQual', 'GarageCond', 'PavedDrive', 'PoolQC', 'Fence']
oh_cols_na = ['MSZoning', 'Street', 'Alley', 'LandContour', 'LotConfig', 'Neighborhood',
              'Condition1', 'Condition2', 'BldgType', 'RoofStyle', 'RoofMatl',
              'Exterior1st', 'Exterior2nd', 'MasVnrType', 'Foundation', 'Heating',
              'MiscFeature', 'SaleType', 'SaleCondition']

# Importamos datos
df = pd.read_csv('in/train.csv')
y = df['SalePrice']
df.drop('SalePrice', axis=1, inplace=True)
X_train, X_test, y_train, y_test = train_test_split(df, y, test_size=0.15, random_state=7)

# Define Pipelines
pipe_num_0 = Pipeline(steps=[
    ('imp', SimpleImputer(strategy='constant', fill_value=0))
    ])
pipe_ord_mf = Pipeline(steps=[
    ('imp', SimpleImputer(strategy='most_frequent')),
    ('ord', OrdinalEncoder(categories=ord_cols_mf_cat))
    ])
pipe_ord_na = Pipeline(steps=[
    ('imp', SimpleImputer(strategy='constant', fill_value='NA')),
    ('ord', OrdinalEncoder(categories=ord_cols_na_cat))
    ])
pipe_oh_na = Pipeline(steps=[
    ('imp', SimpleImputer(strategy='constant', fill_value='NA')),
    ('ord', OneHotEncoder(handle_unknown='ignore'))
    ])

# Preprocessing all columns
preprocessing = ColumnTransformer(transformers=[('drop_id', 'drop', ['Id']),
                                                ('trans_num_0', pipe_num_0, num_cols_0),
                                                ('trans_ord_mf', pipe_ord_mf, ord_cols_mf),
                                                ('trans_ord_na', pipe_ord_na, ord_cols_na),
                                                ('trans_oh_na', pipe_oh_na, oh_cols_na)
                                                ])

kfolds = KFold(n_splits=10, shuffle=True, random_state=42)

alphas_alt = [14.5, 14.6, 14.7, 14.8, 14.9, 15, 15.1, 15.2, 15.3, 15.4, 15.5]
alphas2 = [5e-05, 0.0001, 0.0002, 0.0003, 0.0004, 0.0005, 0.0006, 0.0007, 0.0008]
e_alphas = [0.0001, 0.0002, 0.0003, 0.0004, 0.0005, 0.0006, 0.0007]
e_l1ratio = [0.8, 0.85, 0.9, 0.95, 0.99, 1]

# declarando models
ridge = RidgeCV(alphas=alphas_alt, cv=kfolds)

lasso = LassoCV(max_iter=100, alphas=alphas2,
                random_state=42, cv=kfolds)

elasticnet = ElasticNetCV(max_iter=100, alphas=e_alphas,
                          cv=kfolds, l1_ratio=e_l1ratio)

gbr = GradientBoostingRegressor(n_estimators=3000, learning_rate=0.05,
                                max_depth=4, max_features='sqrt',
                                min_samples_leaf=15, min_samples_split=10,
                                loss='huber', random_state=42)

lightgbm = LGBMRegressor(objective='regression',
                         num_leaves=4,
                         learning_rate=0.01,
                         n_estimators=5000,
                         max_bin=200,
                         bagging_fraction=0.75,
                         bagging_freq=5,
                         bagging_seed=7,
                         feature_fraction=0.2,
                         feature_fraction_seed=7,
                         verbose=-1,
                         # min_data_in_leaf=2,
                         # min_sum_hessian_in_leaf=11
                         )

xgboost = XGBRegressor(learning_rate=0.01, n_estimators=3460,
                       max_depth=3, min_child_weight=0,
                       gamma=0, subsample=0.7,
                       colsample_bytree=0.7,
                       objective='reg:squarederror', nthread=-1,
                       scale_pos_weight=1, seed=27,
                       reg_alpha=0.00006)

# Stack model
stack_gen = StackingCVRegressor(regressors=(ridge, lasso, elasticnet,
                                            gbr, xgboost, lightgbm),
                                meta_regressor=xgboost,
                                use_features_in_secondary=True)

# Voting model
voting = VotingRegressor(estimators=[('ridge',ridge), ('lasso',lasso), ('elasticnet',elasticnet),
                                     ('gbr',gbr), ('lightgbm',lightgbm),
                                     ('xgboost',xgboost),('stack_gen',stack_gen)],
                        weights=[0.1,0.1,0.1,0.1,0.1,0.15,0.25])

# Finaly pipeline
pipe = Pipeline(steps=[('preprocessing', preprocessing),
                       ('models', voting)
                       ])

# Fit pipeline
print('fitting')
pipe.fit(X_train, y_train)

# Test accuracy
print("Accuracy: %s " % str(ridge.score(X_test, y_test)))

# Export model pipeline
joblib.dump(ridge, gzip.open('../models/model_binary.dat.gz', "wb"))


## @file
## @brief Distilled `metaL` / SICP chapter 4 /

from metaL import *

## @defgroup distill distill
## @ingroup samples
## @brief Distilled `metaL` / SICP chapter 4 /
## https://www.notion.so/metalang/Distilled-metaL-SICP-chapter-4-237378d385024f899e5a24597da7a19d
## @{

## metaL core implementation
py = pyFile('metaL')

## metaL core tests
test = pytestFile(py)

## inherit special Module type for metaLayer-based projects
class meModule(minpyModule):

    ## @param[in] V by default `pyModule` uses current `__file__` for module naming
    def __init__(self, V=None):
        # most Python project setup will be done by a parent `pyModule` constructor
        super().__init__(V)

    ## will be called by `super().__init__` to generate `metaL.py`
    def init_py(self):
        ## module master `.py` `File`
        self.py = py
        self['py'] = self.py
        # ## module tests
        self.test = test
        self['test'] = self.test
        self.test.mid // ('from %s import *' % py.val)
        # module (project) root `Dir`ectory
        self.diroot // self.py // self.test
        # `File` does not reflects on disk until direct `.sync()` call is done
        self.py.sync()
        self.test.sync()

    ## patch default `Makefile` from `pyModule` with REPL
    def init_mk(self):
        super().init_mk()
        # force module name
        self.mk.module.dropall() // (f'{"MODULE":<8} = {py}')
        # build Makefile/all section with REPL pattern
        self.mk.all //\
            '.PHONY: all' //\
            'all: repl' //\
            '.PHONY: repl' //\
            (S('repl: $(PYT) $(PY) %s' % py.file()) //
                ('$(PYT) %s' % test.file()) //
                ('$(PY) -i %s' % py.file()) //
                '$(MAKE) $@'
             )
        self.mk.sync()

    def init_reqs(self):
        super().init_reqs()
        (self.reqs // 'pytest').sync()

    def init_vscode_launch(self):
        super().init_vscode_launch()
        self.vscode.launch.program[0] = '"program": "%s",' % py.file()
        self.vscode.launch.sync()

MODULE = meModule()

TITLE = Title('Distilled `metaL` / SICP chapter 4 /')
MODULE['TITLE'] = TITLE

ABOUT = '''
* [`metaL` manifest](https://www.notion.so/metalang/metaL-manifest-f7c2e3c9f4494986a620f3a71cf39cff)
* SICP:
  * `.html`ed:
    * https://sarabander.github.io/sicp/html/Chapter-4.xhtml
    * http://zv.github.io/sicp-chapter-4
  * in Clojure: http://www.afronski.pl/sicp-in-clojure/2015/10/05/sicp-in-clojure-chapter-4.html
'''
MODULE['ABOUT'] = ABOUT

GITHUB = Url('https://github.com/ponyatov/metaL/tree/master/')
GITHUB['branch'] = ''
MODULE['GITHUB'] = GITHUB

README = README(MODULE)
MODULE.diroot // README
README.sync()

py.top // f'## @brief {TITLE} -- reference implementation'
py.top // ('## ' + Url('https://www.notion.so/metalang/Distilled-metaL-SICP-chapter-4-237378d385024f899e5a24597da7a19d').file())

## @name Object
## @{

py.objs = Section('Object')
py.mid // py.objs

## `class Object`
py.obj = pyClass('Object')
py.objs // py.obj

## `class Nil`
py.nil = pyClass('Nil', [py.obj])
py.objs // py.nil

## `class Error`
py.err = Class('Error', [py.obj])
py.objs // py.err

## @name Primitive
## @{

py.prims = Section('Primitive')
py.mid // py.prims

## `class Primitive`
py.prim = Class('Primitive', [py.obj])
py.prims // py.prim

## `class Symbol`
py.sym = Class('Symbol', [py.prim])
py.prims // py.sym

## `class String`
py.str = Class('String', [py.prim])
py.prims // py.str

## `class Number`
py.num = Class('Number', [py.prim])
py.prims // py.num

## `class Integer`
py.int = Class('Integer', [py.prim])
py.prims // py.int

## @}

## @name Container
## @{

py.conts = Section('Container')
py.mid // py.conts

## `class Container`
py.cont = Class('Container', [py.obj])
py.conts // py.cont

## `class Vector`
py.vect = Class('Vector', [py.cont])
py.conts // py.vect

## `class Stack` FIFO buffer
py.stack = Class('Stack', [py.cont])
py.conts // py.stack

## `class Dict` associative array
py.dict = Class('Dict', [py.cont])
py.conts // py.dict

## `class Set` engle-entry container
py.set = Class('Set', [py.cont])
py.conts // py.set

## `class Queue` LIFO thread-safe buffer
py.queue = Class('Queue', [py.cont])
py.conts // py.queue

## @}

## @name Active
## @{

py.actives = Section('Active')
py.mid // py.actives

## `class Active`
py.active = Class('Active', [py.obj])
py.actives // py.active

# index for later patching
ctxi = Section('Context')
py.actives // ctxi

## `class Context` execution context
py.ctx = Class('Context', [py.active])
ctxi // py.ctx

## `class Fn` function
py.fn = Class('Fn', [py.active])
py.actives // py.fn

## `class Op` operator
py.op = Class('Op', [py.active])
py.actives // py.op

## @}

## @name Meta
## @{

py.metas = Section('Meta')
py.mid // py.metas

## `class Meta`
py.meta = Class('Meta', [py.obj])
py.metas // py.meta

## `class Module` software module (compilation module, library)
py.module = Class('Module', [py.meta])
py.metas // py.module

## `class Class`
py.clazz = Class('Class', [py.meta])
py.metas // py.clazz

## class-bound `Method` (encapsulated function)
py.method = Class('Method', [py.meta, py.fn])
py.metas // py.method

## `Fn`/`Method` and `Class`-inheritance arguments
py.args = Class('Args', [py.meta, py.vect])
py.metas // py.args

## @}

## @name IO
## @{

py.ios = Section('IO')
py.mid // py.ios

## `class IO`
py.io = Class('IO', [py.obj])
py.ios // py.io

## `class Dir`
py.dir = Class('Dir', [py.io])
py.ios // py.dir

## `class File`
py.file = Class('File', [py.io])
py.ios // py.file

## @}

## @name metaL manifest fields
## [metaL manifest](https://www.notion.so/metalang/metaL-manifest-f7c2e3c9f4494986a620f3a71cf39cff)
## @{

fields = pyInterface('fields: metaL manifest')
py.obj // (fields << Url('https://www.notion.so/metalang/metaL-manifest-f7c2e3c9f4494986a620f3a71cf39cff#70d2d317a4fd4c95904b0a4bf46f2027'))

## object graph node constructor
init = pyMethod('__init__', ['V'])
fields // init
init //\
    (S('## type/class tag') //
        'self.tag  = self.__class__') //\
    (S('## scalar value: object name, string, number,..') //
        'self.val  = V') //\
    (S('## slots = attributes = associative array') //
        'self.slot = {}') //\
    (S('## nested AST = vector = stack = queue') //
        'self.nest = []') //\
    (S('## parent nodes refset') //
        'self.par  = set()') //\
    (S('## unique global storage identifier (*content* fast 32-bit hash)') //
        'self.gid = id(self)') //\
    ''

## @}

## @name dump
## @{

dumpi = pyInterface('dump')
py.obj // (dumpi << Url('https://www.notion.so/metalang/Distilled-metaL-SICP-chapter-4-237378d385024f899e5a24597da7a19d#2cd65706a8b843dca6fa8c4ae69920d5'))

## system method dumps any object in a string form
reprr = (pyMethod('__repr__') // Return('self.dump()'))
dumpi // reprr

## method used in `test_metaL.py` dumps wihout `#hash`/`@id`
testt = (pyMethod('test') // Return('self.dump(test=True)'))
dumpi // testt

## @name metaL sample: how to use "exteral" source elements (shared function [a]rguments)
## @{

## dump recursion depth
adepth = Arg('depth')
## prefix default:''
aprefix = Arg('prefix')
## test flag
atest = Arg('test')

## @}

## full text-tree dump
dump = pyMethod('dump')
dumpi // dump
dump.args //\
    Arg("cycle=[]") //\
    Arg(f"{adepth}=0") //\
    Arg(f"{aprefix}=''") //\
    Arg(f"{atest}=False")
dump //\
    f"ret = self.pad({adepth}) + self.head({aprefix}, {atest})" //\
    (S("for i in sorted(self.slot.keys()):") //
        "ret += self.slot[i].dump(cycle, depth+1, prefix=f'{i} = ', test=test)") //\
    'idx = 0' //\
    (S("for j in self.nest:") //
        "ret += j.dump(cycle, depth+1, prefix=f'{idx}: ', test=test)" //
        "idx += 1") //\
    Return('ret')

## short `<T:V>` header only
head = pyMethod('head')
dumpi // head
head.args // f"{aprefix}=''" // f"{atest}=False"
head //\
    f"ret = '%s<%s:%s>' % (prefix, self._tag(), self._val())" //\
    f"if not test: ret += '#%.8x @%x ' % (self.gid, id(self))" //\
    Return('ret')

## padding method
pad = pyMethod('pad')
dumpi // pad
pad.args // adepth
pad //\
    Return(f"'\\n' + '\\t' * {adepth}")

## `.tag`-formatter for dumps
dtag = pyMethod('_tag')
dumpi // (dtag // Return('self.tag.__name__.lower()'))

## `.val`-formatter for dumps
dval = pyMethod('_val')
dumpi // (dval // Return("'%s' % self.val"))

## @}

## @name operator
## @{

operi = pyInterface('operator')
py.obj // operi

## indexing key
key = Arg('key')
## operand `B`
that = Arg('that')

## most operators return `self` : modified object `A`
rself = Return('self')

## `A[key]`
getitem = pyMethod('__getitem__')
operi // getitem
getitem.args // key
getitem //\
    (S("if isinstance(key,str):") //
     Return(f'self.slot[{key}]')) //\
    (S("if isinstance(key,int):") //
     Return(f'self.nest[{key}]')) //\
    'raise TypeError(key)'

## `A // B -> A.push(B)`
floordiv = pyMethod('__floordiv__')
operi // floordiv
floordiv.args // that
floordiv //\
    f'self.nest.append({that})' //\
    rself

## @}

## @name testing
## @{

test_hello = pyTest('hello')
test_hello['for'] = fields
test // "hello = Object('hello')"
test // "world = Object('world')"
test // test_hello
test_hello //\
    "assert hello.test() == '\\n<object:hello>'" //\
    "assert world.test() == '\\n<object:world>'" //\
    "hello // world" //\
    "print(hello.test())" //\
    (S("assert hello.test() ==\\") //
        "'\\n<object:hello>' +\\" //
        "'\\n\\t0: <object:world>'") //\
    ''

## @}

## @name evaluation
## @{

evali = pyInterface('evaluation')
py.obj // evali

## computation context
ctx = Arg('ctx')

## `.eval()` method template
evall = pyMethod('eval')
evall.args // ctx

## `.apply()` method template
apply = pyMethod('apply')
apply.args // that // ctx

## `Object.eval()`
evali // (evall.cp() // 'raise NotImplementedError')

## `Object.apply()`
evali // (apply.cp() // 'raise NotImplementedError')

# most primitives evaluates to itself
py.prim // (evall.cp() // Return('self'))

# symbol must lookup itself in context
py.sym // (evall.cp() // Return(f'{ctx}[self.val]'))

# for other class evaluation we need to define the global context
ctxi // '' // "glob = Context('global')" // ''

## @}

py.sync()
test.sync()

## @}

# hello = Object('hello')
# hello['world'] = Object('world')
# # hello.world = Object('WORLD')
# print(1,hello)
# print(2,hello.world)
# print(3,hello.val)
# print(4,hello.vaz)


class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        numCountList = [0,0,0]
        for numItem in nums:
            numCountList[numItem] +=1

        tempList = []
        for idx, numCountValue in enumerate(numCountList):
            tempList.extend([idx] * numCountValue)

        for idx in range(len(nums)):
            nums[idx]=tempList[idx]


"""
# Sample code to perform I/O:

name = input()                  # Reading input from STDIN
print('Hi, %s.' % name)         # Writing output to STDOUT

# Warning: Printing unwanted or ill-formatted data to output will cause the test cases to fail
"""

# Write your code here
from functools import reduce
from operator import or_

t = int(input())
for _ in range(t):
    n, x = map(int, input().strip().split())
    a = list(map(int, input().strip().split()))
    temp = reduce(or_, a, 0)
    if temp < x:
        print(0)
    else:
        subarrays = []
        temp = a[:]
        for i in range(n):
            flag = False
            for j in range(n - i):
                temp[j] = temp[j] | a[i + j]
                if temp[j] >= x:
                    subarrays.append([j + 1, j + i + 1])
                    flag = True
            if flag:
                break
        print(len(subarrays))
        for l, r in subarrays:
            print(l, r)


# -*- coding: utf-8 -*-

from __future__ import unicode_literals

from h import models
from h.models import group
from h._compat import urlparse

class ListGroupsService(object):

    """
    A service for providing filtered lists of groups.

    This service filters groups by user session, scope, etc.

    ALl public methods return a list of relevant group model objects.
    """

    def __init__(self, session, request_authority):
        """
        Create a new list_groups service.

        :param _session: the SQLAlchemy session object
        :param _request_authority: the authority to use as a default
        """
        self._session = session
        self.request_authority = request_authority

    def _authority(self, user=None, authority=None):
        """Determine which authority to use.

           Determine the appropriate authority to use for querying groups.
           User's authority will always supersede if present; otherwise provide
           default value—request.authority—if no authority specified.
        """

        if user is not None:
            return user.authority
        return authority or self.request_authority

    def all_groups(self, user=None, authority=None, document_uri=None):
        """
        Return a list of groups relevant to this session/profile (i.e. user).

        Return a list of groups filtered on user and authority. All open
        groups matching the authority will be included.
        """
        all_open_groups = self._open_groups(user, authority)
        private_groups = self._private_groups(user)

        return all_open_groups + private_groups

    def request_groups(self, authority, user=None, document_uri=None):
        """
        Return a list of groups relevant to this request and user combination.

        Return a list of groups filtered on user, authority, document_uri.
        Include all types of relevant groups (open and private).

        Open groups will be filtered by scope (via document_uri).
        """
        scoped_open_groups = self._scoped_open_groups(authority, document_uri)

        world_group = self._world_group(authority)
        world_group = [world_group] if world_group else []

        private_groups = self._private_groups(user)

        return scoped_open_groups + world_group + private_groups

    def _open_groups(self, user=None, authority=None):
        """
        Return all open groups for the authority.
        """

        authority = self._authority(user, authority)
        groups = (self._session.query(models.Group)
                      .filter_by(authority=authority,
                                 readable_by=group.ReadableBy.world)
                      .all())
        return self._sort(groups)

    def _private_groups(self, user=None):
        """Return this user's private groups per user.groups."""

        if user is None:
            return []
        return self._sort(user.groups)

    def _parse_origin(self, uri):
        """
        Return the origin of a URI or None if empty or invalid.

        Per https://tools.ietf.org/html/rfc6454#section-7 :
        Return ``<scheme> + '://' + <host> + <port>``
        for a URI.

        :param uri: URI string
        """

        if uri is None:
            return None
        parsed = urlparse.urlsplit(uri)
        # netloc contains both host and port
        origin = urlparse.SplitResult(parsed.scheme, parsed.netloc, '', '', '')
        return origin.geturl() or None

    def _scoped_open_groups(self, authority, document_uri):
        """Return scoped groups for the URI and authority"""
        origin = self._parse_origin(document_uri)
        if not origin:
            return []

        groups = (self._session.query(models.GroupScope, models.Group)
                      .filter(models.Group.id == models.GroupScope.group_id)
                      .filter(models.GroupScope.origin == origin)
                      .filter(models.Group.authority == authority)
                      .all())

        scoped_groups = [group for groupscope, group in groups]
        return self._sort(scoped_groups)

    def _sort(self, groups):
        """ sort a list of groups of a single type """
        return sorted(groups, key=lambda group: (group.name.lower(), group.pubid))

    def _world_group(self, authority):
        """
        Return the world group for the given authority, if any.

        Return the so-called 'world-readable Public group' (or channel) for
        the indicated authority.

        The Public group is special: at present its metadata makes it look
        identical to any non-scoped open group. Its only distinguishing
        characteristic is its unique and predictable ``pubid``
        """
        return (self._session.query(models.Group)
                    .filter_by(authority=authority,
                               readable_by=group.ReadableBy.world,
                               pubid=u'__world__')
                    .one_or_none())

def list_groups_factory(context, request):
    """Return a ListGroupsService instance for the passed context and request."""
    return ListGroupsService(session=request.db,
                             request_authority=request.authority)


import logging
import datetime
from typing import List, Optional
from betfairlightweight.resources.bettingresources import MarketBook, RunnerBook

from .utils import (
    SimulatedPlaceResponse,
    SimulatedCancelResponse,
    SimulatedUpdateResponse,
)
from ..utils import get_price, get_size, wap
from ..order.ordertype import OrderTypes
from .. import config

logger = logging.getLogger(__name__)

class SimulatedOrder:
    """
    Class to hold `simulated` order
    matching and status.
    """

    def __init__(self, order):
        self.order = order
        self.size_matched = 0
        self.average_price_matched = 0
        self.matched = []  # [[publishTime, price, size]..]
        self.size_cancelled = 0.0
        self.size_lapsed = 0.0
        self.size_voided = 0.0
        self.market_version = None  # version at place so we can lapse if needed
        self._piq = 0.0
        self._bsp_reconciled = False

    def __call__(self, market_book: MarketBook, runner_traded: tuple) -> None:
        # simulates order matching
        if self._bsp_reconciled is False and market_book.bsp_reconciled:
            if self.take_sp:
                runner = self._get_runner(market_book)
                self._process_sp(market_book.publish_time_epoch, runner)
                return
            else:
                self._bsp_reconciled = True

        if self.order.order_type.ORDER_TYPE == OrderTypes.LIMIT:
            if market_book.version != self.market_version:
                self.market_version = market_book.version  # update for next time
                if market_book.status == "SUSPENDED":  # Material change
                    if self.order.order_type.persistence_type == "LAPSE":
                        self.size_lapsed += self.size_remaining
                        return

            # todo estimated piq cancellations
            traded = runner_traded[1]
            if traded:
                self._process_traded(market_book.publish_time_epoch, traded)

            if config.simulation_available_prices:
                self._process_available(
                    market_book.publish_time_epoch, runner_traded[0]
                )

    def place(
        self, order_package, market_book: MarketBook, instruction: dict, bet_id: int
    ) -> SimulatedPlaceResponse:
        # simulates placeOrder request->matching->response
        # validate market status
        if market_book.status != "OPEN":
            self.size_voided += self.size_remaining
            return self._create_place_response(
                None,
                status="FAILURE",
                error_code="ERROR_IN_ORDER",
            )

        # validate market version
        self.market_version = market_book.version
        if (
            order_package.market_version
            and order_package.market_version["version"] != self.market_version
        ):
            self.size_voided += self.size_remaining
            return self._create_place_response(
                None,
                status="FAILURE",
                error_code="ERROR_IN_ORDER",
            )

        runner = self._get_runner(market_book)
        # validate runner status
        if runner.status == "REMOVED":
            self.size_voided += self.size_remaining
            return self._create_place_response(
                None,
                status="FAILURE",
                error_code="RUNNER_REMOVED",
            )
        if self.order.order_type.ORDER_TYPE == OrderTypes.LIMIT:
            price = self.order.order_type.price
            size = self.order.order_type.size
            if "limitOrder" in instruction:
                time_in_force = instruction["limitOrder"].get("timeInForce")
                min_fill_size = instruction["limitOrder"].get("minFillSize") or 0
            else:
                time_in_force = None
                min_fill_size = None
            if size is None:
                raise NotImplementedError(
                    "Simulated betTargetSize placement not implemented"
                )
            if self.order.side == "BACK":
                available_to_back = get_price(runner.ex.available_to_back, 0) or 1.01
                if (
                    not order_package.client.best_price_execution
                    and available_to_back > price
                ):
                    self.size_lapsed += self.size_remaining
                    return self._create_place_response(
                        None,
                        status="FAILURE",
                        error_code="BET_LAPSED_PRICE_IMPROVEMENT_TOO_LARGE",
                    )
                elif time_in_force == "FILL_OR_KILL":
                    available_size = get_size(runner.ex.available_to_back, 0) or 0
                    if price > available_to_back:
                        self.size_lapsed += self.size_remaining
                        return self._create_place_response(bet_id)
                    elif price == available_to_back:
                        if available_size >= min_fill_size:
                            self._process_price_matched(
                                market_book.publish_time_epoch,
                                price,
                                size,
                                runner.ex.available_to_back,
                            )
                        self.size_lapsed += self.size_remaining
                        return self._create_place_response(bet_id)
                    else:
                        self._process_price_matched_vwap(
                            market_book.publish_time_epoch,
                            price,
                            size,
                            runner.ex.available_to_back,
                            min_fill_size=min_fill_size,
                        )
                        self.size_lapsed += self.size_remaining
                        return self._create_place_response(bet_id)
                elif available_to_back >= price:
                    self._process_price_matched(
                        market_book.publish_time_epoch,
                        price,
                        size,
                        runner.ex.available_to_back,
                    )
                    return self._create_place_response(bet_id)
                available = runner.ex.available_to_lay
            else:
                available_to_lay = get_price(runner.ex.available_to_lay, 0) or 1000
                if (
                    not order_package.client.best_price_execution
                    and available_to_lay < price
                ):
                    self.size_lapsed += self.size_remaining
                    return self._create_place_response(
                        None,
                        status="FAILURE",
                        error_code="BET_LAPSED_PRICE_IMPROVEMENT_TOO_LARGE",
                    )
                elif time_in_force == "FILL_OR_KILL":
                    available_size = get_size(runner.ex.available_to_lay, 0) or 0
                    if price < available_to_lay:
                        self.size_lapsed += self.size_remaining
                        return self._create_place_response(bet_id)
                    elif price == available_to_lay:
                        if available_size >= min_fill_size:
                            self._process_price_matched(
                                market_book.publish_time_epoch,
                                price,
                                size,
                                runner.ex.available_to_lay,
                            )
                        self.size_lapsed += self.size_remaining
                        return self._create_place_response(bet_id)
                    else:
                        self._process_price_matched_vwap(
                            market_book.publish_time_epoch,
                            price,
                            size,
                            runner.ex.available_to_lay,
                            min_fill_size=min_fill_size,
                        )
                        self.size_lapsed += self.size_remaining
                        return self._create_place_response(bet_id)
                elif available_to_lay <= price:
                    self._process_price_matched(
                        market_book.publish_time_epoch,
                        price,
                        size,
                        runner.ex.available_to_lay,
                    )
                    return self._create_place_response(bet_id)
                available = runner.ex.available_to_back

            # calculate position in queue
            for avail in available:
                if avail["price"] == price:
                    self._piq = avail["size"]
                    break

            logger.debug("Simulated order %s PIQ: %s", self.order.id, self._piq)
            return self._create_place_response(bet_id)
        else:
            # validate BSP available, not reconciled and market not inplay
            if (
                market_book.market_definition.bsp_market is False
                or market_book.bsp_reconciled is True
                or market_book.inplay is True
            ):
                self.size_voided += self.size_remaining
                return self._create_place_response(
                    None,
                    status="FAILURE",
                    error_code="MARKET_NOT_OPEN_FOR_BSP_BETTING",
                )
            return self._create_place_response(bet_id)

    def _create_place_response(
        self,
        bet_id: Optional[int],
        status: str = "SUCCESS",
        order_status: str = None,
        error_code: str = None,
    ) -> SimulatedPlaceResponse:
        if self.order.client.simulated_full_match:
            if status == "SUCCESS" and self.size_remaining:
                self.matched.append(
                    [0, self.order.order_type.price, self.size_remaining]
                )
                self.size_matched, self.average_price_matched = wap(self.matched)
        if order_status is None:
            if self.size_remaining == 0:
                order_status = "EXECUTION_COMPLETE"
            else:
                order_status = "EXECUTABLE"
        return SimulatedPlaceResponse(
            status=status,
            order_status=order_status,
            bet_id=str(bet_id) if bet_id else bet_id,
            average_price_matched=self.average_price_matched,
            size_matched=self.size_matched,
            placed_date=datetime.datetime.utcnow(),
            error_code=error_code,
        )

    def cancel(self, market_book: MarketBook) -> SimulatedCancelResponse:
        # simulates cancelOrder request->cancel->response
        if market_book.status != "OPEN":
            return SimulatedCancelResponse(
                status="FAILURE",
                error_code="ERROR_IN_ORDER",
            )
        if self.order.order_type.ORDER_TYPE == OrderTypes.LIMIT:
            _size_reduction = (
                self.order.update_data.get("size_reduction") or self.size_remaining
            )
            _size_cancelled = min(
                _size_reduction, self.size_remaining
            )  # cancelled cannot be more than remaining (does not error)
            self.size_cancelled += _size_cancelled
            return SimulatedCancelResponse(
                status="SUCCESS",  # todo handle errors
                size_cancelled=_size_cancelled,
                cancelled_date=datetime.datetime.utcnow(),
            )
        else:
            return SimulatedCancelResponse(
                status="FAILURE",
                error_code="BET_ACTION_ERROR",
            )

    def update(
        self, market_book: MarketBook, instruction: dict
    ) -> SimulatedUpdateResponse:
        # simulates updateOrder request->update->response
        if market_book.status != "OPEN":
            return SimulatedUpdateResponse(
                status="FAILURE",
                error_code="ERROR_IN_ORDER",
            )
        # validate BSP available
        if market_book.market_definition.persistence_enabled is False:
            return SimulatedUpdateResponse(
                status="FAILURE",
                error_code="INVALID_PERSISTENCE_TYPE",
            )
        if (
            self.order.order_type.ORDER_TYPE == OrderTypes.LIMIT
            and self.size_remaining > 0
        ):
            self.order.order_type.persistence_type = instruction.get(
                "newPersistenceType"
            )
            return SimulatedUpdateResponse(status="SUCCESS")
        else:
            return SimulatedUpdateResponse(
                status="FAILURE",
                error_code="BET_ACTION_ERROR",
            )

    def _get_runner(self, market_book: MarketBook) -> RunnerBook:
        runner_dict = {
            (runner.selection_id, runner.handicap): runner
            for runner in market_book.runners
        }
        return runner_dict.get((self.order.selection_id, self.order.handicap))

    def _process_price_matched(
        self, publish_time: int, price: float, size: float, available: list
    ) -> None:
        # calculate matched on execution
        size_remaining = size
        for avail in available:
            if size_remaining == 0:
                break
            elif (self.side == "BACK" and price <= avail["price"]) or (
                self.side == "LAY" and price >= avail["price"]
            ):
                _size_remaining = size_remaining
                size_remaining = max(size_remaining - avail["size"], 0)
                if size_remaining == 0:
                    _size_matched = _size_remaining
                else:
                    _size_matched = avail["size"]
                _matched = [publish_time, avail["price"], round(_size_matched, 2)]
                self._update_matched(_matched)
            else:
                break

    def _process_price_matched_vwap(
        self,
        publish_time: int,
        price: float,
        size: float,
        available: list,
        min_fill_size: float,
    ) -> None:
        # calculate vwap matched on execution
        size_remaining = size
        for avail in available:
            if size_remaining == 0:
                break
            # create copy of current matched
            _all_matched = self.matched.copy()
            # get current match
            _size_remaining = size_remaining
            size_remaining = max(size_remaining - avail["size"], 0)
            if size_remaining == 0:
                _size_matched = _size_remaining
            else:
                _size_matched = avail["size"]
            _matched = [publish_time, avail["price"], round(_size_matched, 2)]
            _all_matched.append(_matched)
            # get potential vwap
            _, _average_price_matched = wap(_all_matched)
            # check
            if self.side == "BACK" and _average_price_matched >= price:
                self._update_matched(_matched)
            elif self.side == "LAY" and _average_price_matched <= price:
                self._update_matched(_matched)
            else:
                break
        if self.size_matched < min_fill_size:
            self.matched = []
            self.size_matched, self.average_price_matched = wap(self.matched)
            self.size_lapsed += self.size_remaining

    def _process_sp(self, publish_time: int, runner: RunnerBook) -> None:
        # calculate matched on BSP reconciliation
        actual_sp = runner.sp.actual_sp
        if actual_sp:
            self._bsp_reconciled = True
            _order_type = self.order.order_type
            if _order_type.ORDER_TYPE == OrderTypes.LIMIT:
                if self.side == "BACK":
                    size = self.size_remaining
                else:
                    remaining_risk = (_order_type.price - 1.0) * self.size_remaining
                    client = self.order.client
                    if remaining_risk >= client.min_bsp_liability:
                        size = round(remaining_risk / (actual_sp - 1.0), 2)
                        # Cancel remaining size
                        self.size_cancelled += round(self.size_remaining - size, 2)
                    else:  # lapse
                        self.size_lapsed += self.size_remaining
                        self.order.execution_complete()
                        return
            elif _order_type.ORDER_TYPE == OrderTypes.LIMIT_ON_CLOSE:
                if self.side == "BACK":
                    if actual_sp < _order_type.price:
                        self.order.execution_complete()
                        return
                    size = _order_type.liability
                else:
                    if actual_sp > _order_type.price:
                        self.order.execution_complete()
                        return
                    size = round(
                        _order_type.liability / (actual_sp - 1), 2
                    )  # todo round 2dp down
            elif _order_type.ORDER_TYPE == OrderTypes.MARKET_ON_CLOSE:
                if self.side == "BACK":
                    size = _order_type.liability
                else:
                    size = round(_order_type.liability / (actual_sp - 1), 2)
            else:
                raise NotImplementedError()
            self._update_matched([publish_time, actual_sp, size])
            self.order.execution_complete()
        else:
            logger.warning(
                "SP not available for order %s on runner %s",
                self.order.id,
                runner.selection_id,
            )

    def _process_traded(self, publish_time: int, traded: dict) -> None:
        # calculate matched on MarketBook update
        price = self.order.order_type.price
        side = self.side
        for traded_price, traded_size in traded.items():
            if logger.isEnabledFor(logging.DEBUG):
                logger.debug(
                    "Simulated order %s traded: %s - %s",
                    self.order.id,
                    traded_price,
                    traded_size,
                )
            if side == "BACK" and traded_price >= price:
                matched = self._calculate_process_traded(publish_time, traded_size)
                if matched:
                    traded[traded_price] = max(traded_size - matched, 0.0)
            elif side == "LAY" and traded_price <= price:
                matched = self._calculate_process_traded(publish_time, traded_size)
                if matched:
                    traded[traded_price] = max(traded_size - matched, 0.0)

    def _calculate_process_traded(self, publish_time: int, traded_size: float) -> float:
        _traded_size = traded_size / 2
        if self._piq - _traded_size < 0:
            size = _traded_size - self._piq
            size = round(min(self.size_remaining, size), 2)
            if size:
                self._update_matched(
                    [
                        publish_time,
                        self.order.order_type.price,
                        size,
                    ]
                )
            _matched = (self._piq + size) * 2
            self._piq = 0
            return _matched
        else:
            self._piq -= _traded_size
            logger.debug("Simulated order %s PIQ: %s", self.order.id, self._piq)
            return traded_size

    def _process_available(self, publish_time: int, runner: RunnerBook) -> None:
        # todo prevent double counting
        price = self.order.order_type.price
        side = self.side
        if side == "BACK":
            for update in runner.ex.available_to_back:
                if update["price"] >= price:
                    self._calculate_process_available(
                        publish_time, update["price"], update["size"]
                    )
        elif side == "LAY":
            for update in runner.ex.available_to_lay:
                if update["price"] <= price:
                    self._calculate_process_available(
                        publish_time, update["price"], update["size"]
                    )

    def _calculate_process_available(
        self, publish_time: int, price: float, size: float
    ) -> None:
        size = round(min(self.size_remaining, size), 2)
        if size:
            self._update_matched(
                [
                    publish_time,
                    price,
                    size,
                ]
            )
        self._piq = 0

    @property
    def take_sp(self) -> bool:
        if self.order.order_type.ORDER_TYPE == OrderTypes.LIMIT:
            if self.order.order_type.persistence_type == "MARKET_ON_CLOSE":
                return True
            return False
        else:
            return True

    @property
    def side(self) -> str:
        return self.order.side

    def _update_matched(self, data: List) -> None:
        logger.debug("Simulated order %s matched: %s", self.order.id, data)
        self.matched.append(data)
        self.size_matched, self.average_price_matched = wap(self.matched)

    @property
    def size_remaining(self) -> float:
        if self.order.order_type.ORDER_TYPE == OrderTypes.LIMIT:
            size = self.order.order_type.size or self.order.order_type.bet_target_size
            return round(
                size
                - self.size_matched
                - self.size_cancelled
                - self.size_lapsed
                - self.size_voided,
                2,
            )
        else:
            return 0.0

    @property
    def profit(self) -> float:
        number_of_dead_heat_winners = self.order.number_of_dead_heat_winners or 1
        if self.order.market_type == "EACH_WAY":
            divisor = self.order.each_way_divisor
            win = self.size_matched * (self.average_price_matched - 1)
            place = self.size_matched * (
                (self.average_price_matched - 1) * (1 / divisor)
            )
            if number_of_dead_heat_winners > 1:  # todo dead heat
                logger.error("Each Way Dead Heat Detected but not handled")
            if self.order.runner_status == "WINNER":
                profit = round(win + place, 2)
                if self.side == "BACK":
                    return profit
                else:
                    return -profit
            elif self.order.runner_status == "PLACED":
                if self.side == "BACK":
                    profit = place - self.size_matched
                    return round(profit, 2)
                else:
                    profit = self.size_matched - place
                    return round(profit, 2)
            elif self.order.runner_status == "LOSER":
                matched = round(self.size_matched * 2, 2)
                if self.side == "BACK":
                    return -matched
                else:
                    return matched
            else:
                return 0.0
        else:
            if self.order.runner_status == "WINNER":
                profit = (self.size_matched / number_of_dead_heat_winners) * (
                    self.average_price_matched - 1
                )
                if number_of_dead_heat_winners == 2:
                    profit = profit - (self.size_matched / number_of_dead_heat_winners)
                elif number_of_dead_heat_winners > 2:
                    profit = profit - (
                        self.size_matched
                        * (number_of_dead_heat_winners - 1)
                        / number_of_dead_heat_winners
                    )
                if self.side == "LAY":
                    profit = -profit
                return round(profit, 2)
            elif self.order.runner_status == "LOSER":
                if self.side == "BACK":
                    return -self.size_matched
                else:
                    return self.size_matched
            else:
                return 0.0

    @property
    def status(self) -> str:
        if self.take_sp:
            if self._bsp_reconciled:
                return "EXECUTION_COMPLETE"
            else:
                return "EXECUTABLE"
        else:
            if self.size_remaining:
                return "EXECUTABLE"
            else:
                return "EXECUTION_COMPLETE"

    @property
    def info(self) -> dict:
        return {
            "profit": self.profit,
            "piq": self._piq,
            "matched": self.matched,
        }

    def __bool__(self):
        return config.simulated or bool(
            self.order.client and self.order.client.paper_trade
        )


import random
import config

from datasets import AnimeDataset
from pix2pix import UNetGenerator, PatchDiscriminator

import numpy as np
import torch
from torch.utils import data

import torchvision
from torchvision import transforms

from tqdm import tqdm

def main():
    start_epoch = 0
    n_epochs = config.epochs
    weights_folder = config.ckpt_dir

    G, D = UNetGenerator(init_weights=True), PatchDiscriminator(init_weights=True)
    G.to(config.device)
    D.to(config.device)

    optim_G = torch.optim.Adam(G.parameters(), lr=config.lr, betas=(0.5, 0.999))
    optim_D = torch.optim.Adam(D.parameters(), lr=config.lr, betas=(0.5, 0.999))

    bce_loss = torch.nn.BCEWithLogitsLoss()
    l1_loss = torch.nn.L1Loss()

    train_transform = [
        transforms.Resize((256, 256)),
        transforms.ToPILImage(),
        # transforms.ColorJitter(),
        transforms.ToTensor(),
        transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))
    ]
    train_transform = transforms.Compose(train_transform)

    train_data = AnimeDataset(config.train_dir, train_transform)
    train_loader = data.DataLoader(train_data, batch_size=config.batch_size, shuffle=True, num_workers=config.num_workers)

    val_data = AnimeDataset(config.val_dir, train_transform)
    val_loader = data.DataLoader(val_data, batch_size=5)

    for epoch in range(start_epoch, n_epochs):
        train_one_epoch(epoch, G, D, optim_G, optim_D, train_loader, bce_loss, l1_loss)
        torch.save(G.state_dict(), f'{weights_folder}/G-checkpoint-{str(epoch).zfill(3)}epoch.pth')
        torch.save(D.state_dict(), f'{weights_folder}/D-checkpoint-{str(epoch).zfill(3)}epoch.pth')
        test(G, val_loader, epoch)
        # TODO: save里保存epoch信息
        # TODO: 增加tensorboard 或 wandb 配置

def train_one_epoch(epoch, G, D, optim_G, optim_D, train_loader, gan_loss, dist_loss):
    pbar = tqdm(train_loader)
    pbar.set_description(desc=f'Epoch {epoch + 1}/{config.epochs}')

    for i, (x, y) in enumerate(pbar):
        x, y = x.to(config.device), y.to(config.device)

        y_fake = G(x)   # 生成器生成假图
        d_real = D(x, y)    # 判别器对真图进行判别
        d_fake = D(x, y_fake.detach())   # 判别器对假图进行判别

        real = torch.ones_like(d_real)    # 真图全1
        fake = torch.zeros_like(d_real)   # 假图全0

        r_loss = gan_loss(d_real, real)
        f_loss = gan_loss(d_fake, fake)
        D_loss = (r_loss + f_loss) / 2

        # 训练判别器，不需要l1_loss
        D.zero_grad()
        D_loss.backward()
        optim_D.step()

        # 训练生成器
        d_fake = D(x, y_fake)
        G_gan_loss = gan_loss(d_fake, fake)
        l1_loss = dist_loss(y_fake, y)
        G_loss = G_gan_loss + config.l1_lambda * l1_loss
        G.zero_grad()
        G_loss.backward()
        optim_G.step()

        pbar.set_postfix(
            {'D Loss': '{:.5f}'.format(round(D_loss.item(), 4)), 'G Loss': '{:.5f}'.format(round(G_loss.item(), 4))})

def test(gen, val_loader, epoch):
    x, y = next(iter(val_loader))
    x, y = x.to(config.device), y.to(config.device)

    gen.eval()
    with torch.no_grad():
        y_fake = gen(x)
        y_fake = y_fake * 0.5 + 0.5    # 消除正则
        x = x * 0.5 + 0.5
        output = torch.cat((x, y_fake), 3)
        torchvision.utils.save_image(output, config.output_dir + f"/output_{epoch}.png")

    gen.train()

def random_seeds(seed):
    # Python built-in random module
    random.seed(seed)
    # Numpy
    np.random.seed(seed)
    # Torch
    torch.manual_seed(seed)
    if torch.cuda.is_available():
        torch.cuda.manual_seed(seed)
        torch.cuda.manual_seed_all(seed)
    torch.backends.cudnn.benchmark = False
    torch.backends.cudnn.deterministic = True

if __name__ == '__main__':
    random_seeds(42)      # 宇宙的答案 42
    main()


from flask import Blueprint, request
from flask_login import login_required, current_user
from app.models import User, Transaction, db
from app.forms import PayRequestForm
from .auth_routes import validation_errors_to_error_messages

transaction_routes = Blueprint('transactions', __name__)

@transaction_routes.route('')
@login_required
def transactions():
    """
    Query for all transactions of the current user and its friends, and returns them in a list of transaction dictionaries
    """
    user_transactions = current_user.to_dict_luxury()['transactions']
    user_transactions_ids = [tran['id'] for tran in user_transactions]

    fds_from_ids = filter(lambda friend: friend.is_confirmed, current_user.friends_from)
    fds_to_ids = filter(lambda friend: friend.is_confirmed, current_user.friends_to)
    fds_from = [User.query.get(fds.to_user_id).to_dict_luxury() for fds in fds_from_ids]
    fds_to = [User.query.get(fds.from_user_id).to_dict_luxury() for fds in fds_to_ids]
    friends = [*fds_from, *fds_to]

    friends_transactions = []
    friend_trans_dups = []

    for f in friends:
        friend_trans = f['transactions']
        for t in friend_trans:
            if t['id'] not in user_transactions_ids and t['id'] not in friend_trans_dups:
                friends_transactions.append(t)
                friend_trans_dups.append(t['id'])

    return {'UserTransactions': user_transactions, "FriendsTransactions": friends_transactions}

@transaction_routes.route('/<int:id>')
@login_required
def transaction(id):
    """
    Query for a transaction by id and returns that transaction in a dictionary
    """
    transaction = Transaction.query.get(id)

    # get all confirmed friend ids.
    fds_from_ids = [
        friendship.to_user_id for friendship in current_user.friends_from if friendship.is_confirmed]
    fds_to_ids = [
        friendship.from_user_id for friendship in current_user.friends_to if friendship.is_confirmed]

    friends = [*fds_from_ids, *fds_to_ids]

    # print('--------------------------------------------------')
    # print(current_user.id, 'currend_user.id')
    # print(transaction.from_user_id, 'transaction.from_user_id')
    # print(transaction.to_user_id, 'transaction.to_user_id')

    if current_user.id != transaction.from_user_id and current_user.id != transaction.to_user_id \
        and transaction.from_user_id not in friends and transaction.to_user_id not in friends:
            # print('-------------------------returning unauthorized-------------------------')
            return {'errors': 'Unauthorized'}, 401

    if not transaction:
        return {'errors': 'Transaction is not found.'}, 404

    return transaction.to_dict_luxury()

@transaction_routes.route('', methods=['POST'])
@login_required
def create_transaction():
    """
    Create a transaction and returns the newly created transaction in a dictionary
    """
    form = PayRequestForm()

    form['csrf_token'].data = request.cookies['csrf_token']
    if form.validate_on_submit():
        if form.data['to_user_id'] == current_user.id:
            return {'error': 'You cannot transfer fund to yourself.'}, 401

        # user_from = User.query.with_for_update(of=User).filter_by(id=current_user.id).first()
        # user_to = User.query.with_for_update(of=User).filter_by(id=form.data['to_user_id']).first()
        user_from = db.session.query(User).populate_existing().with_for_update(of=User.balance).filter_by(id=current_user.id).first()
        user_to = db.session.query(User).populate_existing().with_for_update(of=User.balance).filter_by(id=form.data['to_user_id']).first()

        if user_from.balance < form.data['amount']:
            return {'error': 'insufficient fund.'}

        user_from.balance -= form.data['amount']
        user_to.balance += form.data['amount']

        transaction = Transaction(
            amount=form.data['amount'],
            note=form.data['note'],
            user_from=user_from,
            user_to=user_to
        )

        db.session.add(transaction)
        db.session.commit()

        return transaction.to_dict_fancy()

    return {'errors': validation_errors_to_error_messages(form.errors)}, 401

# !!! for development only, to remove !!!
@transaction_routes.route('/<int:transaction_id>', methods=['DELETE'])
@login_required
def delete_transaction(transaction_id):
    t = Transaction.query.get(transaction_id)
    db.session.delete(t)
    db.session.commit()

    return 'deleted'


# -*- coding: utf-8 -*-
import numpy as np

class algorithm_sort(object):
	'''Usage: sort a list

	input:
		a random unsorted array

	return:
		a sorted array
	'''
	def __init__(self, sortlist):
		self._sortlist = sortlist		#private variable
		self._num = len(sortlist)

	# @staticmethod @classmethod
	def bubblesort(self, templist):
		'''bubble sort'''
		templist=self._sortlist
		i = 0
		args = False
		while i <= self._num-1 and not args:
			args = True
			for j in xrange(self._num-1, i, -1):
				if templist[j] < templist[j-1]:
					templist[j], templist[j-1] = templist[j-1], templist[j]		#interchange j and j-1
					args = False
			i = i+1
			# print templist, args

		return templist

	def selectsort(self,templist):
		'''select sort'''
		templist = self._sortlist
		for i in xrange(self._num-1):
			k = i
			for j in xrange(i+1, self._num):
				if templist[j] < templist[k]:
					k = j
			if k != i:
				templist[i], templist[k] = templist[k], templist[i]		#interchange i and k
		# #====second way to handle the problem====
		# for i in xrange(self._num-1):
		# 	for j in xrange(i+1,self._num):
		# 		if templist[j]<=templist[i]:
		# 			# print templist[i],templist[j]
		# 			templist[i],templist[j]=templist[j],templist[i]
		return templist

	def insertsort(self,templist):
		'''insert sort'''
		templist = self._sortlist
		for i in xrange(1, self._num):
			x = templist[i]
			j = i-1
			while j >= 0 and templist[j] > x:
				templist[j+1] = templist[j]
				j = j-1
			templist[j+1] = x

		return templist

	def bottomup_merge(self, templist, p, q, r):
		'''merge method used by bottomup sort'''
		# templist = self._sortlist
		tempB = np.zeros(r-p+1)		#use this method,the memory used will be smaller.
		s = p-1; t = q; k = p-1
		while s <= q-1 and t <= r-1:
			if templist[s] <= templist[t]:
				tempB[k-(p-1)] = templist[s]
				s=s+1
			else:
				tempB[k-(p-1)] = templist[t]
				t=t+1
			k=k+1
		if s==q:
			for i in xrange(k, r):
				tempB[i-(p-1)] = templist[t]
				t=t+1
			# print "t={0}, r={1}".format(t,r),'===='
		else:
			for i in xrange(k, r):
				tempB[i-(p-1)] = templist[s]
				s=s+1
			# print "s={0}, q={1}".format(s,q),'####'
		for i in xrange(p-1,r):
			templist[i] = tempB[i-(p-1)]
		# print 'the auxiliary array:', tempB
		return templist[p-1:r]

	def bottomupsort(self,templist):
		'''bottomup sort'''
		templist = self._sortlist
		t = 1
		while t < self._num:
			s=t; t=2*s; i=0
			while i+t < self._num:
				# print "i={0}, s={1}, t={2}".format(i, s, t), '======'
				self.bottomup_merge(templist, i+1, i+s, i+t)
				i=i+t
			if i+s < self._num:
				# print "i={0}, s={1}, t={2}".format(i, s, t), '######'
				self.bottomup_merge(templist, i+1, i+s, self._num)

		return templist

	def modbinarysearch(self, templist, x):
		'''binary search, but return x's position'''
		# templist=self._sortlist
		low=0; high=len(templist)-1; j=0
		while low <= high:
			mid=(low+high)/2
			# print low,high,mid
			if x== templist[mid]:
				j=mid               #if find the x, then return j
				# print '======'
				return j
			elif x < templist[mid]:
				high=mid-1
			else:
				low=mid+1
		if j==0:                    #if don't find x, then return index of x
			# print '#####'
			j=(low+high)/2+1        #these two lines are both right
			# j=high+1

		return j

	def modinsertsort(self, templist):
		'''modinsert sort'''
		templist=self._sortlist
		for i in xrange(1,self._num):
			x=templist[i]
			k=self.modbinarysearch(templist[0:i],x)
			# print x, templist[0:i], k
			for j in xrange(i-1,k-1,-1):
				templist[j+1]=templist[j]
			templist[k]=x
		#====the below code is also right,and don't need function modbinarysearch====
		# for i in xrange(1,self._num):
		# 	low=0; temp=templist[i];high=i-1
		# 	while low <= high:
		# 		mid=(low+high)/2
		# 		if temp < templist[mid]:
		# 			high=mid-1
		# 		else:
		# 			low=mid+1
		# 	for j in xrange(i-1,high,-1):
		# 		templist[j+1]=templist[j]
		# 	templist[high+1]=temp

		return templist


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Oct 13 04:41:16 2018

@author: rishabh
"""

import os
import json
import numpy as np
#import matplotlib.pyplot as plt

from util import find_analogies

from brown import get_sentences_with_word2idx_limit_vocab as get_brown

class Glove:
    def __init__(self, D, V, context_sz):
        self.D = D
        self.V = V
        self.context_sz =context_sz

    def fit(self, sentences, cc_matrix=None, learning_rate=1e-4, reg=0.1, xmax=100, alpha=0.75, epochs=10, gd=True):
        # build co-occurrence matrix
        # paper calls it X, so we will call it X, instead of calling
        # the training data X
        V = self.V
        D = self.D

        if not os.path.exists(cc_matrix):
            X = np.zeros((V,V))
            N = len(sentences)
            print("Number of sentences to process:",N)
            it = 0
            for sentence in sentences:
                it += 1
                if it % 10000 == 0:
                    print("processed", it, "/", N)
                n = len(sentence)
                for i in range(n):
                    # i just points to which element of the sequence (sentence) we're looking at
                    wi = sentence[i]

                    start = max(0, i - self.context_sz)
                    end = min(n, i+ self.context_sz)

                    if i - self.context_sz < 0:
                        points = 1.0 / (i + 1)
                        X[wi,0] += points
                        X[0,wi] += points
                    if i + self.context_sz > n:
                        points = 1 / (n - i)
                        X[wi,1] += points
                        X[1,wi] += points
                    # left side
                    for j in range(start, i):
                        wj = sentence[j]
                        points = 1 / (i - j)
                        X[wi,wj] += points
                        X[wj,wi] += points

                    # right side
                    for j in range(i + 1, end):
                        wj = sentence[j]
                        points = 1 / (j - i)
                        X[wi,wj] += points
                        X[wj,wi] += points
            np.save(cc_matrix,X)
        else:
            X = np.load(cc_matrix)

        print("max in X:",X.max())

        # Weighting
        fX = np.zeros((V,V))
        fX[X < xmax] = (X[X < xmax] / float(xmax)) ** alpha
        fX[X >= xmax] = 1

        # target
        logX = np.log(X + 1)

        print("max in log(X)",logX.max())

        # initialize weights
        W = np.random.randn(V,D) / np.sqrt(V + D)
        b = np.zeros(V)
        U = np.random.randn(V,D) / np.sqrt(V + D)
        c = np.zeros(V)
        mu = logX.mean()

        costs = []
        sentence_indexes = range(len(sentences))
        for epoch in range(epochs):
            delta = W.dot(U.T) + b.reshape(V,1) + c.reshape(1,V) + mu-logX
            cost = (fX * delta * delta).sum()
            costs.append(cost)
            print("epoch:",epoch,"cost:",cost)

            if gd:
                for i in range(V):
                    W[i] -= learning_rate*(fX[i,:]*delta[i,:]).dot(U)
                W -= learning_rate*reg*W

                for i in range(V):
                    b[i] -= learning_rate*fX[i,:].dot(delta[i,:])

                for j in range(V):
                    U[j] -= learning_rate*(fX[:,j]*delta[:,j]).dot(W)
                U -= learning_rate*reg*U

                for j in range(V):
                    c[j] -= learning_rate*fX[:,j].dot(delta[:,j])
            else:
                # ALS Method
                # update W
                for i in range(V):
                    matrix = reg*np.eye(D) + (fX[i,:] * U.T).dot(U)

                    vector = (fX[i,:] * (logX[i,:] - b[i] - c - mu)).dot(U)
                    W[i] = np.linalg.solve(matrix, vector)

                # update b
                for i in range(V):
                    denominator = fX[i,:].sum()
                    numerator = fX[i,:].dot(logX[i,:] - W[i].dot(U.T) -c -mu)

                    b[i] = numerator / denominator / (1 + reg)

                # update U
                for j in range(V):
                    matrix = reg * np.eye(D) + (fX[:,j]*W.T).dot(W)
                    vector = (fX[:,j]*(logX[:,j] -b -c[j])).dot(W)

                    U[j] = np.linalg.solve(matrix,vector)

                # update c
                for j in range(V):
                    denominator = fX[:,j].sum()
                    numerator = fX[:,j].dot(logX[:,j] - W.dot(U[j]) - b - mu)

                    c[j] = numerator / denominator / (1 + reg)

        self.W = W
        self.U = U

        #plt.plot(costs)
        #plt.show()

    def save(self, fn):
        # function word_analogies expects a (V,D) matrx and a (D,V) matrix
        arrays = [self.W, self.U.T]
        np.savez(fn, *arrays)

def main(we_file, w2_ifile):

    cc_matrix = "cc_matrix_brown.npy"

    if os.path.exists(cc_matrix):
        with open(w2_ifile) as f:
            word2idx = json.load(f)
        sentences  = []
    else:
        keep_words = set([
        'king', 'man', 'woman',
        'france', 'paris', 'london', 'rome', 'italy', 'britain', 'england',
        'french', 'english', 'japan', 'japanese', 'chinese', 'italian',
        'australia', 'australian', 'december', 'november', 'june',
        'january', 'february', 'march', 'april', 'may', 'july', 'august',
        'september', 'october',
        ])
        sentences, word2idx = get_brown(n_vocab=5000, keep_words=keep_words)
        with open(w2_ifile,'w') as f:
            json.dump(word2idx, f)

    V = len(word2idx)
    model = Glove(200, V, 10)

    model.fit(sentences, cc_matrix=cc_matrix, epochs=20)
    model.save(we_file)

if __name__ == '__main__':
    we = 'glove_model_50.npz'
    w2i = 'glove_word2idx_50.json'

    main(we, w2i)
    npz = np.load(we)
    W1 = npz['arr_0']
    W2 = npz['arr_1']

    with open(w2i) as f:
        word2idx = json.load(f)
        idx2word = {i:w for w,i in word2idx.items()}

    for concat in (True,False):
        print("** concat:", concat)

        if concat:
            We = np.hstack([W1, W2.T])
        else:
            We = (W1 + W2.T) / 2

        find_analogies('king', 'man', 'woman', We, word2idx, idx2word)
        find_analogies('france', 'paris', 'london', We, word2idx, idx2word)
        find_analogies('france', 'paris', 'rome', We, word2idx, idx2word)
        find_analogies('paris', 'france', 'italy', We, word2idx, idx2word)
        find_analogies('france', 'french', 'english', We, word2idx, idx2word)
        find_analogies('japan', 'japanese', 'chinese', We, word2idx, idx2word)
        find_analogies('japan', 'japanese', 'italian', We, word2idx, idx2word)
        find_analogies('japan', 'japanese', 'australian', We, word2idx, idx2word)
        find_analogies('december', 'november', 'june', We, word2idx, idx2word)