import array
from collections import Counter

import numpy as np
import tqdm
import pysam

from hits import fastq, utilities

from .collapse_cython import hq_mismatches_from_seed
from repair_seq.annotations import Annotations

progress = tqdm.tqdm_notebook

NUM_READS_TAG = 'ZR'
CLUSTER_ID_TAG = 'ZC'

HIGH_Q = 31
LOW_Q = 10
N_Q = 2

def consensus_seq_and_qs(reads, max_read_length, bam):
    if max_read_length is None:
        max_read_length = len(reads[0].query_sequence)

    statistics = fastq.quality_and_complexity(reads, max_read_length, alignments=bam, min_q=30)
    shape = statistics['c'].shape

    rl_range = np.arange(max_read_length)

    fields = [
        ('c_above_min_q', int),
        ('c', int),
        ('average_q', float),
    ]

    stat_tuples = np.zeros(shape, dtype=fields)
    for k in ['c_above_min_q', 'c', 'average_q']:
        stat_tuples[k] = statistics[k]

    argsorted = stat_tuples.argsort()
    second_best_idxs, best_idxs = argsorted[:, -2:].T

    best_stats = stat_tuples[rl_range, best_idxs]

    majority = (best_stats['c'] / len(reads)) > 0.5
    at_least_one_hq = best_stats['c_above_min_q'] > 0

    qs = np.full(max_read_length, LOW_Q, dtype=int)
    qs[majority & at_least_one_hq] = HIGH_Q

    ties = (best_stats == stat_tuples[rl_range, second_best_idxs])

    best_idxs[ties] = utilities.base_to_index['N']
    qs[ties] = N_Q

    seq = ''.join(utilities.base_order[i] for i in best_idxs)

    return seq, qs

def call_consensus(reads, max_read_length, bam):
    seq, qs = consensus_seq_and_qs(reads, max_read_length, bam)

    if bam:
        consensus = pysam.AlignedSegment()
        consensus.query_sequence = seq
        consensus.query_qualities = array.array('B', qs)
        consensus.set_tag(NUM_READS_TAG, len(reads), 'i')
    else:
        guide_reads = []
        for read in reads:
            annotation = Annotations['UMI_guide'].from_identifier(read.name)
            guide_read = fastq.Read('PH', annotation['guide'], annotation['guide_qual'])
            guide_reads.append(guide_read)

        guide_seq, guide_qs = consensus_seq_and_qs(guide_reads, None, False)
        guide_qual = fastq.encode_sanger(guide_qs)

        annotation = Annotations['collapsed_UMI'](UMI='PH',
                                                  num_reads=len(reads),
                                                  guide=guide_seq,
                                                  guide_qual=guide_qual,
                                                  cluster_id=0,
                                                 )
        name = str(annotation)
        qual = fastq.encode_sanger(qs)
        consensus = fastq.Read(name, seq, qual)

    return consensus

def within_radius_of_seed(seed, reads, max_hq_mismatches):
    seed_b = seed.encode()
    ds = [hq_mismatches_from_seed(seed_b, read.query_sequence.encode(), read.query_qualities, 20)
          for read in reads]

    near_seed = []
    remaining = []

    for i, (d, al) in enumerate(zip(ds, reads)):
        if d <= max_hq_mismatches:
            near_seed.append(al)
        else:
            remaining.append(al)

    return near_seed, remaining

def propose_seed(reads, max_read_length, bam):
    seqs = (read.query_sequence for read in reads)

    seq_counts = Counter(seqs).most_common()

    highest_count = seq_counts[0][1]
    most_frequents = [s for s, c in seq_counts if c == highest_count]

    # If there is a tie, take the alphabetically first for determinism.
    seq = sorted(most_frequents)[0]

    if highest_count > 1:
        seed = seq
    else:
        consensus = call_consensus(reads, max_read_length, bam)
        seed = consensus.query_sequence

    return seed

def make_singleton_cluster(read, bam):
    if bam:
        singleton = pysam.AlignedSegment()
        singleton.query_sequence = read.query_sequence
        singleton.query_qualities = read.query_qualities
        singleton.set_tag(NUM_READS_TAG, 1, 'i')
    else:
        annotation = Annotations['UMI_guide'].from_identifier(read.name)
        name = Annotations['collapsed_UMI'](UMI=annotation['UMI'],
                                            guide=annotation['guide'],
                                            guide_qual=annotation['guide_qual'],
                                            cluster_id=0,
                                            num_reads=1,
                                           )
        singleton = fastq.Read(str(name), read.seq, read.qual)

    return singleton

def form_clusters(reads, max_read_length=None, max_hq_mismatches=0, bam=False):
    if len(reads) == 0:
        clusters = []

    elif len(reads) == 1:
        clusters = [make_singleton_cluster(read, bam) for read in reads]

    else:
        seed = propose_seed(reads, max_read_length, bam)
        near_seed, remaining = within_radius_of_seed(seed, reads, max_hq_mismatches)

        if len(near_seed) == 0:
            # didn't make progress, so give up
            clusters = [make_singleton_cluster(read, bam) for read in reads]

        else:
            consensus_near_seed = call_consensus(near_seed, max_read_length, bam)
            all_others = form_clusters(remaining, max_read_length, max_hq_mismatches, bam)
            clusters = [consensus_near_seed] + all_others

    return clusters


#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# __author__ : YiXuan
# __date__ : 1/23/2021 8:23 PM
# __software__ : PyCharm

'''

插入排序（英语：Insertion Sort）是一种简单直观的排序算法。
它的工作原理是通过构建有序序列，对于未排序数据，在已排序序列中从后向前扫描，找到相应位置并插入。

'''

# 从小到大排列
def insertionSort(lst):
    for i in range(1, len(lst)):
        key = lst[i]
        j = i
        while j > 0 and key < lst[j-1]:
            lst[j] = lst[j-1]
            j -= 1
        lst[j] = key

    print(f'从小到大插入排序后: {lst}')

# 从大到小
def insertionSort1(lst):
    # 从第二个元素开始遍历，此时第一个元素自然就是有序序列
    for i in range(1, len(lst)):

        key = lst[i]
        j = i
        while j > 0 and key > lst[j-1]:
            lst[j] = lst[j-1]
            j -= 1
        lst[j] = key

    print(f'从大到小插入排序后: {lst}')

if __name__ == '__main__':
    lst = [0, 6, 1, 7, 8, 3, 9, 4, 5, 2]
    print(f'原始列表: {lst}')

    insertionSort(lst)
    insertionSort1(lst)


import sqlite3
import datetime
from operator import itemgetter

from app.config import config

class DB:
    def __init__(self):
        db_file = config['DB']['db_file']
        self.conn = sqlite3.connect(db_file)
        self.c = self.conn.cursor()

    def get_data_for_chart(self, service: str, parameter='temperature', history_days=config['DB']['history_days'],
                            forecast_days=config['DB']['forecast_days']) -> list:
        # SELECT * FROM session WHERE stop_time > (SELECT DATETIME('now', '-7 day'))
        history_dt_req = '''(SELECT DATETIME('now', '-%s day'))''' % history_days
        forecast_dt_req = '''(SELECT DATETIME('now', '+%s day'))''' % forecast_days
        req = ''' SELECT datetime
            FROM %s
            WHERE service = ?
            AND datetime > %s
            AND datetime < %s''' % (parameter, history_dt_req, forecast_dt_req)
        self.c.execute(req, (service,))
        rows = self.c.fetchall()

        dt_list = []
        for r in rows:
            if r not in dt_list:
                dt_list.append(r)

        data = []
        for dt in dt_list:
            dt = dt[0]
            abs_min = self.get_min(dt, parameter, service)
            abs_max = self.get_max(dt, parameter, service)
            latest = self.get_two_latest(dt, parameter, service)
            if len(latest) == 2:
                latest_min = latest[0][0]
                latest_max = latest[1][0]
            if len(latest) == 1:
                latest_min = latest_max = latest[0][0]
            if latest_min > latest_max:
                latest_min, latest_max = latest_max, latest_min

            dic = {
                'date': dt,
                'absolute_min': abs_min,
                'absolute_max': abs_max,
                'latest_min': latest_min,
                'latest_max': latest_max
            }

            data.append(dic)
        data_sorted = sorted(data, key=itemgetter('date'))
        return data_sorted

    def get_max(self, dt, parameter, service):
        req = '''SELECT max("value")
                 FROM %s
                 WHERE service = "%s"
                 AND datetime = "%s"''' % (parameter, service, dt)
        self.c.execute(req)
        result_raw = self.c.fetchone()
        return result_raw[0]

    def get_min(self, dt, parameter, service):
        req = '''SELECT min("value")
                 FROM %s
                 WHERE service = "%s"
                 AND datetime = "%s"''' % (parameter, service, dt)
        self.c.execute(req)
        result_raw = self.c.fetchone()
        return result_raw[0]

    def get_two_latest(self, dt, parameter, service, column="value"):
        req = '''SELECT %s
                 FROM %s
                 WHERE service = "%s"
                 AND datetime = "%s"
                 ORDER BY timestamp DESC
                 LIMIT 2''' % (column, parameter, service, dt)
        self.c.execute(req)
        result_raws = self.c.fetchall()
        return result_raws

    def get_last_value(self, parameter, service):
        req = '''SELECT value
                 FROM %s
                 WHERE service = "%s"
                 ORDER BY timestamp DESC
                 LIMIT 1''' % (parameter, service)
        self.c.execute(req)
        result_raws = self.c.fetchone()
        return result_raws

    def save_sensor_data(self, sensor_name, parameter, value):
        dt = datetime.datetime.now().isoformat(sep=' ', timespec='seconds')
        data_tpl = (dt, dt, value, sensor_name)
        if parameter == 't':
            self.c.execute('INSERT INTO temperature(timestamp, datetime, value, service) VALUES (?,?,?,?)', data_tpl)
        if parameter == 'p':
            self.c.execute('INSERT INTO pressure(timestamp, datetime, value, service) VALUES (?,?,?,?)', data_tpl)
        if parameter == 'h':
            self.c.execute('INSERT INTO humidity(timestamp, datetime, value, service) VALUES (?,?,?,?)', data_tpl)
        self.conn.commit()

    def db_close(self):
        self.conn.close()


from __future__ import absolute_import
import os
import warnings

import pytest
import numpy as np

from pynpoint.core.pypeline import Pypeline
from pynpoint.readwrite.fitsreading import FitsReadingModule
from pynpoint.readwrite.fitswriting import FitsWritingModule
from pynpoint.util.tests import create_config, create_star_data, remove_test_data

warnings.simplefilter("always")

limit = 1e-10

class TestFitsWritingModule(object):

    def setup_class(self):

        self.test_dir = os.path.dirname(__file__) + "/"

        create_star_data(path=self.test_dir+"fits")
        create_config(self.test_dir+"PynPoint_config.ini")

        self.pipeline = Pypeline(self.test_dir, self.test_dir, self.test_dir)

    def teardown_class(self):

        remove_test_data(self.test_dir, folders=["fits"], files=["test.fits"])

    def test_fits_reading(self):

        read = FitsReadingModule(name_in="read",
                                 input_dir=self.test_dir+"fits",
                                 image_tag="images",
                                 overwrite=True,
                                 check=True)

        self.pipeline.add_module(read)
        self.pipeline.run_module("read")

        data = self.pipeline.get_data("images")
        assert np.allclose(data[0, 50, 50], 0.09798413502193704, rtol=limit, atol=0.)
        assert np.allclose(np.mean(data), 0.00010029494781738066, rtol=limit, atol=0.)
        assert data.shape == (40, 100, 100)

    def test_fits_writing(self):

        write = FitsWritingModule(file_name="test.fits",
                                  name_in="write1",
                                  output_dir=None,
                                  data_tag="images",
                                  data_range=None,
                                  overwrite=True)

        self.pipeline.add_module(write)
        self.pipeline.run_module("write1")

    def test_filename_string(self):

        with pytest.raises(ValueError) as error:
            FitsWritingModule(file_name=0.,
                              name_in="write2",
                              output_dir=None,
                              data_tag="images",
                              data_range=None,
                              overwrite=True)

        assert str(error.value) == "Output 'file_name' needs to be a string."

    def test_filename_extension(self):

        with pytest.raises(ValueError) as error:
            FitsWritingModule(file_name="test.dat",
                              name_in="write3",
                              output_dir=None,
                              data_tag="images",
                              data_range=None,
                              overwrite=True)

        assert str(error.value) == "Output 'file_name' requires the FITS extension."

    def test_data_range(self):

        write = FitsWritingModule(file_name="test.fits",
                                  name_in="write4",
                                  output_dir=None,
                                  data_tag="images",
                                  data_range=(0, 10),
                                  overwrite=True)

        self.pipeline.add_module(write)
        self.pipeline.run_module("write4")

    def test_not_overwritten(self):

        write = FitsWritingModule(file_name="test.fits",
                                  name_in="write5",
                                  output_dir=None,
                                  data_tag="images",
                                  data_range=None,
                                  overwrite=False)

        self.pipeline.add_module(write)

        with pytest.warns(UserWarning) as warning:
            self.pipeline.run_module("write5")

        assert len(warning) == 1
        assert warning[0].message.args[0] == "Filename already present. Use overwrite=True " \
                                             "to overwrite an existing FITS file."


#!/usr/bin/python3
""" uses the Github API to display id """
import requests
from sys import argv

def main():
    """ uses the Github API to display id """
    url = "https://api.github.com/user"
    try:
        response = requests.get(url, auth=(argv[1], argv[2])).json()
        print(response['id'])
    except:
        print('None')

if __name__ == "__main__":
    main()


import util

def depthFirstSearch(problem):
    fringe = util.Stack()
    current_state = [problem.getStartState(), []]
    successors = None
    explored = set()
    item = None

    while(not problem.isGoalState(current_state[0])):
        (current_pos, directions) = current_state
        successors = problem.getSuccessors(current_state[0])
        for nextGameState, action, cost in successors:
            fringe.push((nextGameState, directions + [action]))
        while (True):
            if (fringe.isEmpty()):
                return None
            item = fringe.pop()
            if (str(item[0]) not in explored):
                break
        current_state = item
        explored.add(str(item[0]))

    solution= current_state
    return solution

def breadthFirstSearch(problem):
    fringe = util.Queue()
    current_state = [problem.getStartState(), []]
    fringe.push(current_state)
    visited = []
    while not fringe.isEmpty():
        current_state= fringe.pop()
        node, actions = current_state
        for nextGameState, action, cost in problem.getSuccessors(node):
            if not str(nextGameState) in visited:
                if problem.isGoalState(nextGameState):
                    return (nextGameState ,actions + [action])
                fringe.push((nextGameState, actions + [action]))
                visited.append(str(nextGameState))

# Abbreviations
dfs = depthFirstSearch
bfs = breadthFirstSearch


from helpers.binance import binance
import socketio
sio = socketio.Client()
SYMBOL = 'ETH/USDT'

@sio.event
def connect():
    print('connected to server')
    price = binance.fetch_ticker(SYMBOL)['close']
    sio.emit('priceETH', str(price))
    sio.disconnect()
sio.connect('http://127.0.0.1:8000')
sio.wait()


from typing import Dict, Union

from rest_framework.response import Response
from rest_framework import status

from CabPriceCoefficientApp.redis_db import RedisDataBaseAccessObject
from CabPriceCoefficientApp.serializers.output_serializer import CabPriceCoefficientSerializer
from CabPriceCoefficientApp.serializers.input_serializer import LatitudeLongitudeSerializer
from ThresholdWeightApp.models import ThresholdWeightModel

from rest_framework.views import APIView

import hashlib
from geopy.geocoders import Nominatim
import datetime

class CabPriceCoefficientView(APIView):

    def __init__(self):
        super().__init__()
        self.serializer_class = LatitudeLongitudeSerializer
        self.redis_dao = RedisDataBaseAccessObject()

    def post(self, request) -> Response:
        """
           Cabs price coefficient generated by 'lat' (latitude), 'lon' (longitude) of cabs location

        """

        serialized_latitude_longitude = LatitudeLongitudeSerializer(data=request.data)
        if serialized_latitude_longitude.is_valid():
            latitude_and_longitude_dict: Dict = serialized_latitude_longitude.data
            geolocator = Nominatim(user_agent="snapp_cab_app")
            address_of_the_cab: Dict = \
                geolocator.reverse((latitude_and_longitude_dict['latitude'], latitude_and_longitude_dict['longitude']),
                                   language='en', exactly_one=True).raw['address']
            if address_of_the_cab:
                request_id: str = self._set_request_id_in_redis(latitude_and_longitude_dict, address_of_the_cab)
                serialized_threshold_coefficient_record: CabPriceCoefficientSerializer = \
                    self._get_price_coefficient_from_request_threshold(request_id)
                if serialized_threshold_coefficient_record:
                    return Response(serialized_threshold_coefficient_record.data, status=status.HTTP_200_OK)
        return Response(status=status.HTTP_400_BAD_REQUEST)

    @staticmethod
    def _create_request_key_to_store_in_redis(data: dict, address_of_the_cab: dict) -> str:
        data_string: str = str(data)
        data_byte: bytes = data_string.encode('utf_8')
        data_hash: str = hashlib.md5(data_byte).hexdigest()

        now: datetime = datetime.datetime.now()
        date_time_now: str = now.strftime("%Y-%m-%d %H:%M:%S")

        suburb_of_cab_location: str = address_of_the_cab.get("suburb")

        return '{}:{}:{}'.format(suburb_of_cab_location, data_hash, date_time_now)

    def _set_request_id_in_redis(self, data: dict, address_of_the_cab: dict) -> str:
        request_id: str = self._create_request_key_to_store_in_redis(data, address_of_the_cab)
        self.redis_dao.set_request_id(request_id)
        return request_id

    def _get_price_coefficient_from_request_threshold(self, request_id: str) -> Union[None, dict]:
        number_of_requests_in_cab_location: int = self.redis_dao.get_number_of_cabs_in_specific_origin(request_id)
        threshold_coefficient_query_set = ThresholdWeightModel.objects.filter(
            requests_threshold__lte=number_of_requests_in_cab_location).order_by('-requests_threshold').values()[:1]
        if threshold_coefficient_query_set:
            threshold_coefficient_record_dict: dict = threshold_coefficient_query_set.get()
            serialized_threshold_coefficient_record: CabPriceCoefficientSerializer = \
                CabPriceCoefficientSerializer(threshold_coefficient_record_dict)
            return serialized_threshold_coefficient_record


import cv2                                                            # import libraries of python OpenCV
title = 'monitoring'
cv2.namedWindow(title)                                                # capture frames from a camera
video = cv2.VideoCapture(0)

if video.isOpened():                                                  # check if video is opened
    rval, frame = video.read()                                        # return the value as  video frame
else:
    rval = False                                                      # else return 0

# Paths to haarcascade_frontalface_alt.xml and haarcascade_eye.xml and smile.xml files which are available in OpenCV list
faceCascade = cv2.CascadeClassifier("C:/Users/HP/Anaconda2/pkgs/opencv3-3.1.0-py35_0/Library/etc/haarcascades/haarcascade_frontalface_alt.xml")
eye_cascade = cv2.CascadeClassifier('C:/Users/HP/Anaconda2/pkgs/opencv3-3.1.0-py35_0/Library/etc/haarcascades/haarcascade_eye_tree_eyeglasses.xml')
smile_cascade = cv2.CascadeClassifier('C:/Users/HP/Anaconda2/pkgs/opencv3-3.1.0-py35_0/Library/etc/haarcascades/haarcascade_smile.xml')
font = cv2.FONT_HERSHEY_SIMPLEX
thickness = 2                                                         # Line thickness of 2 px
while rval:                                                           # infinite loop till the return value is true
    cv2.imshow(title, frame)                                          # Display an image and title in a window
    rval, frame = video.read()                                        # reads frames from a camera

    if len(faceCascade.detectMultiScale(frame))>0:                    # check the length of frame in detection
        faces = faceCascade.detectMultiScale(frame)                   # Detects faces of different sizes in the input image

        for (x, y, w, h) in faces:                                    # To draw a rectangle in a face(x and y coordinate, width and height)
            cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
            if w > 0:                                                 # if width is greater than 0

                if len(eye_cascade.detectMultiScale(frame))>0:        # check the lenth of eye frame
                    eyes = eye_cascade.detectMultiScale(frame)        # Detects eyes of different sizes in the input image
                    for (ex, ey, ew, eh) in eyes:                     # To draw a rectangle in eyes
                        if ew > 0:                                    # if the eye width is greater then 0
                            cv2.rectangle(frame, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 2)  #frame around eyes
                    smile = smile_cascade.detectMultiScale(frame,scaleFactor=1.8, minNeighbors=20,minSize=(25, 25),)
                    for (ex, ey, ew, eh) in smile:                    # To draw rectangle around smile
                        if ew > 0:                                    # if smile width is present
                            cv2.rectangle(frame, (ex,ey), (ex+ew, ey+eh), (0,255,255), 2)     # make a rectangle around smile

    key = cv2.waitKey(1)
    if key == 27:
        break

video.release()                                                        # release the window
cv2.destroyWindow(title)                                               # De-allocate any associated memory usage


from enum import Enum, auto

import torch
import torch.nn as nn
from torch.distributions import Normal, kl

class NoiseType(Enum):
    DIAGONAL = auto()
    ISOTROPIC = auto()
    FIXED = auto()

class NormalNetwork(nn.Module):

    def __init__(self, in_dim, out_dim, hidden_dim, noise_type, fixed_noise_level=None):
        super().__init__()
        assert (fixed_noise_level is not None) == (noise_type is NoiseType.FIXED)
        num_sigma_channels = {
            NoiseType.DIAGONAL: out_dim,
            NoiseType.ISOTROPIC: 1,
            NoiseType.FIXED: 0,
        }[noise_type]
        self.in_dim, self.out_dim = in_dim, out_dim
        self.noise_type, self.fixed_noise_level = noise_type, fixed_noise_level
        self.network = nn.Sequential(
            nn.Linear(in_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, out_dim + num_sigma_channels),
        )

    def forward(self, x, eps=1e-6):
        params = self.network(x)
        mu, log_sigma_param = params[..., :self.out_dim], params[..., self.out_dim:]
        if self.noise_type is NoiseType.DIAGONAL:
            sigma = torch.exp(log_sigma_param + eps)
        if self.noise_type is NoiseType.ISOTROPIC:
            sigma = torch.exp(log_sigma_param + eps).repeat(1, self.out_dim)
        if self.noise_type is NoiseType.FIXED:
            sigma = torch.full_like(mu, fill_value=self.fixed_noise_level)
        return Normal(loc=mu, scale=sigma)

class VAE(nn.Module):

    def __init__(self, input_dim, latent_dim, hidden_dim):
        super().__init__()
        self.prior = Normal(torch.zeros(latent_dim), torch.ones(latent_dim))
        self.z_given_x = NormalNetwork(input_dim, latent_dim, hidden_dim, NoiseType.ISOTROPIC)
        self.x_given_z = NormalNetwork(latent_dim, input_dim, hidden_dim, NoiseType.ISOTROPIC)

    def loss(self, x):
        pred_z = self.z_given_x(x)
        kl_div = kl.kl_divergence(pred_z, self.prior)
        monte_carlo_z = pred_z.rsample()
        monte_carlo_x = self.x_given_z(monte_carlo_z)
        rec_loss = torch.sum(monte_carlo_x.log_prob(x), dim=1, keepdim=True)
        return -(rec_loss - kl_div).squeeze(dim=1)

    def sample_z(self, n_samples):
        return self.prior.rsample((n_samples,))


class Solution:

    # 2022/06/23
    # Heap [O(nlogn + nlogn): 20% / O(n): 51%]
    def scheduleCourse(self, courses: List[List[int]]) -> int:
        h = []
        cur = 0
        courses.sort(key = lambda x: x[1])
        for duration, lastDay in courses:
            heapq.heappush(h, -duration)
            cur += duration
            while cur > lastDay:
                pop = heapq.heappop(h)
                cur += pop
        return len(h)

    # Greedy [Incorrect]
    def scheduleCourse1(self, courses: List[List[int]]) -> int:
        carr = []
        for duration, last in courses:
            heapq.heappush(carr, (last - duration, duration, last))
        cur = 0
        count = 0
        while carr:
            pop = heapq.heappop(carr)
            if cur + pop[1] > pop[2]:
                continue
            cur += pop[1]
            count += 1
        return count


"""Soft Actor Critic Algorithm."""

from absl import logging
import numpy as np
import functools
from enum import Enum

import torch
import torch.nn as nn
import torch.distributions as td
from typing import Callable

import alf
from alf.algorithms.config import TrainerConfig
from alf.algorithms.off_policy_algorithm import OffPolicyAlgorithm
from alf.algorithms.one_step_loss import OneStepTDLoss
from alf.algorithms.rl_algorithm import RLAlgorithm
from alf.data_structures import TimeStep, Experience, LossInfo, namedtuple
from alf.data_structures import AlgStep, StepType
from alf.nest import nest
import alf.nest.utils as nest_utils
from alf.networks import ActorDistributionNetwork, CriticNetwork
from alf.networks import QNetwork, QRNNNetwork
from alf.tensor_specs import TensorSpec, BoundedTensorSpec
from alf.utils import losses, common, dist_utils, math_ops

ActionType = Enum('ActionType', ('Discrete', 'Continuous', 'Mixed'))
SacActionState = namedtuple("SacActionState", ["actor_network", "critic"], default_value=())
SacCriticState = namedtuple("SacCriticState", ["critics", "target_critics"])

SacState = namedtuple("SacState", ["action", "actor", "critic"], default_value=())

SacCriticInfo = namedtuple("SacCriticInfo", ["critics", "target_critic"])
SacActorInfo = namedtuple("SacActorInfo", ["actor_loss", "neg_entropy"], default_value=())
SacInfo = namedtuple(
    "SacInfo", [
        "reward", "step_type", "discount", "action", "action_distribution",
        "actor", "critic", "alpha", "log_pi"
    ], default_value=())

SacLossInfo = namedtuple('SacLossInfo', ["actor", "critic", "alpha"])

def _set_target_entropy(name, target_entropy, flat_action_spec):
    """A helper function for computing the target entropy under different
    scenarios of ``target_entropy``.

    Args:
        name (str): the name of the algorithm that calls this function.
        target_entropy (float|Callable|None): If a floating value, it will return as it is.
            If a callable function, then it will be called on the action spec to
            calculate a target entropy. If ``None``, a default entropy will be calculated.
        flat_action_spec (list[TensorSpec]): a flattened list of action specs.
    """
    if target_entropy is None or callable(target_entropy):
        if target_entropy is None:
            target_entropy = dist_utils.calc_default_target_entropy
        target_entropy = np.sum(list(map(target_entropy, flat_action_spec)))
        logging.info("Target entropy is calculated for {}: {}.".format(name, target_entropy))
    else:
        logging.info("User-supplied target entropy for {}: {}".format(name, target_entropy))
    return target_entropy

@alf.configurable
class SacAlgorithm(OffPolicyAlgorithm):
    r"""Soft Actor Critic algorithm, described in:

    ::

        Haarnoja et al "Soft Actor-Critic Algorithms and Applications", arXiv:1812.05905v2

    There are 3 points different with ``tf_agents.agents.sac.sac_agent``:

    1. To reduce computation, here we sample actions only once for calculating
    actor, critic, and alpha loss while ``tf_agents.agents.sac.sac_agent``
    samples actions for each loss. This difference has little influence on
    the training performance.

    2. We calculate losses for every sampled steps.
    :math:`(s_t, a_t), (s_{t+1}, a_{t+1})` in sampled transition are used
    to calculate actor, critic and alpha loss while
    ``tf_agents.agents.sac.sac_agent`` only uses :math:`(s_t, a_t)` and
    critic loss for :math:`s_{t+1}` is 0. You should handle this carefully,
    it is equivalent to applying a coefficient of 0.5 on the critic loss.

    3. We mask out ``StepType.LAST`` steps when calculating losses but
    ``tf_agents.agents.sac.sac_agent`` does not. We believe the correct
    implementation should mask out ``LAST`` steps. And this may make different
    performance on same tasks.

    In addition to continuous actions addressed by the original paper, this
    algorithm also supports discrete actions and a mixture of discrete and
    continuous actions. The networks for computing Q values :math:`Q(s,a)` and
    sampling acitons can be divided into 3 cases according to action types:

    1. Discrete only: a ``QNetwork`` is used for estimating Q values. There will
       be no actor network to learn because actions can be directly sampled from
       the Q values: :math:`p(a|s) \propto \exp(\frac{Q(s,a)}{\alpha})`.
    2. Continuous only: a ``CriticNetwork`` is used for estimating Q values. An
       ``ActorDistributionNetwork`` for sampling actions will be learned according
       to Q values.

    In addition to the entropy regularization described in the SAC paper, we
    also support KL-Divergence regularization if a prior actor is provided.
    In this case, the training objective is:
        :math:`E_\pi(\sum_t \gamma^t(r_t - \alpha D_{\rm KL}(\pi(\cdot)|s_t)||\pi^0(\cdot)|s_t)))`
    where :math:`pi^0` is the prior actor.
    """

    def __init__(self,
                 observation_spec,
                 action_spec: BoundedTensorSpec,
                 reward_spec=TensorSpec(()),
                 actor_network_cls=ActorDistributionNetwork,
                 critic_network_cls=CriticNetwork,
                 q_network_cls=QNetwork,
                 reward_weights=None,
                 epsilon_greedy=None,
                 use_entropy_reward=True,
                 calculate_priority=False,
                 num_critic_replicas=2,
                 env=None,
                 config: TrainerConfig = None,
                 critic_loss_ctor=None,
                 target_entropy=None,
                 prior_actor_ctor=None,
                 target_kld_per_dim=3.,
                 initial_log_alpha=0.0,
                 max_log_alpha=None,
                 target_update_tau=0.05,
                 target_update_period=1,
                 dqda_clipping=None,
                 actor_optimizer=None,
                 critic_optimizer=None,
                 alpha_optimizer=None,
                 debug_summaries=False,
                 reproduce_locomotion=False,
                 name="SacAlgorithm"):
        """
        Args:
            observation_spec (nested TensorSpec): representing the observations.
            action_spec (nested BoundedTensorSpec): representing the actions; can
                be a mixture of discrete and continuous actions. The number of
                continuous actions can be arbitrary while only one discrete
                action is allowed currently. If it's a mixture, then it must be
                a tuple/list ``(discrete_action_spec, continuous_action_spec)``.
            reward_spec (TensorSpec): a rank-1 or rank-0 tensor spec representing
                the reward(s).
            actor_network_cls (Callable): is used to construct the actor network.
                The constructed actor network will be called
                to sample continuous actions. All of its output specs must be
                continuous. Note that we don't need a discrete actor network
                because a discrete action can simply be sampled from the Q values.
            critic_network_cls (Callable): is used to construct critic network.
                for estimating ``Q(s,a)`` given that the action is continuous.
            q_network (Callable): is used to construct QNetwork for estimating ``Q(s,a)``
                given that the action is discrete. Its output spec must be consistent with
                the discrete action in ``action_spec``.
            reward_weights (None|list[float]): this is only used when the reward is
                multidimensional. In that case, the weighted sum of the q values
                is used for training the actor if reward_weights is not None.
                Otherwise, the sum of the q values is used.
            epsilon_greedy (float): a floating value in [0,1], representing the
                chance of action sampling instead of taking argmax. This can
                help prevent a dead loop in some deterministic environment like
                Breakout. Only used for evaluation. If None, its value is taken
                from ``alf.get_config_value(TrainerConfig.epsilon_greedy)``
            use_entropy_reward (bool): whether to include entropy as reward
            calculate_priority (bool): whether to calculate priority. This is
                only useful if priority replay is enabled.
            num_critic_replicas (int): number of critics to be used. Default is 2.
            env (Environment): The environment to interact with. ``env`` is a
                batched environment, which means that it runs multiple simulations
                simultateously. ``env` only needs to be provided to the root
                algorithm.
            config (TrainerConfig): config for training. It only needs to be
                provided to the algorithm which performs ``train_iter()`` by
                itself.
            critic_loss_ctor (None|OneStepTDLoss|MultiStepLoss): a critic loss
                constructor. If ``None``, a default ``OneStepTDLoss`` will be used.
            initial_log_alpha (float): initial value for variable ``log_alpha``.
            max_log_alpha (float|None): if not None, ``log_alpha`` will be
                capped at this value.
            target_entropy (float|Callable|None): If a floating value, it's the
                target average policy entropy, for updating ``alpha``. If a
                callable function, then it will be called on the action spec to
                calculate a target entropy. If ``None``, a default entropy will
                be calculated.
            prior_actor_ctor (Callable): If provided, it will be called using
                ``prior_actor_ctor(observation_spec, action_spec, debug_summaries=debug_summaries)``
                to constructor a prior actor. The output of the prior actor is
                the distribution of the next action. Two prior actors are implemented:
                ``alf.algorithms.prior_actor.SameActionPriorActor`` and
                ``alf.algorithms.prior_actor.UniformPriorActor``.
            target_kld_per_dim (float): ``alpha`` is dynamically adjusted so that
                the KLD is about ``target_kld_per_dim * dim``.
            target_update_tau (float): Factor for soft update of the target
                networks.
            target_update_period (int): Period for soft update of the target
                networks.
            dqda_clipping (float): when computing the actor loss, clips the
                gradient dqda element-wise between
                ``[-dqda_clipping, dqda_clipping]``. Will not perform clipping if
                ``dqda_clipping == 0``.
            actor_optimizer (torch.optim.optimizer): The optimizer for actor.
            critic_optimizer (torch.optim.optimizer): The optimizer for critic.
            alpha_optimizer (torch.optim.optimizer): The optimizer for alpha.
            debug_summaries (bool): True if debug summaries should be created.
            name (str): The name of this algorithm.
        """
        self._calculate_priority = calculate_priority
        self._use_entropy_reward = use_entropy_reward
        if epsilon_greedy is None:
            epsilon_greedy = alf.get_config_value('TrainerConfig.epsilon_greedy')
        self._epsilon_greedy = epsilon_greedy

        self._num_critic_replicas = num_critic_replicas
        critic_networks, actor_network, self._act_type = self._make_networks(
            observation_spec, action_spec, reward_spec, actor_network_cls,
            critic_network_cls, q_network_cls)

        action_state_spec = SacActionState(
            actor_network=(() if self._act_type == ActionType.Discrete else
                           actor_network.state_spec),
            critic=(() if self._act_type == ActionType.Continuous else
                    critic_networks.state_spec))
        train_state_spec = SacState(
            action=action_state_spec,
            actor=(() if self._act_type != ActionType.Continuous else
                   critic_networks.state_spec),
            critic=SacCriticState(
                critics=critic_networks.state_spec,
                target_critics=critic_networks.state_spec))
        predict_state_spec = SacState(action=action_state_spec)

        # % 继承
        super().__init__(
            observation_spec=observation_spec,
            action_spec=action_spec,
            reward_spec=reward_spec,
            train_state_spec=train_state_spec,
            predict_state_spec=predict_state_spec,
            reward_weights=reward_weights,
            env=env,
            config=config,
            debug_summaries=debug_summaries,
            name=name)

        log_alpha = nn.Parameter(torch.tensor(float(initial_log_alpha)))
        if actor_optimizer is not None and actor_network is not None:
            self.add_optimizer(actor_optimizer, [actor_network])
        if critic_optimizer is not None:
            self.add_optimizer(critic_optimizer, [critic_networks])
        if alpha_optimizer is not None:
            self.add_optimizer(alpha_optimizer, nest.flatten(log_alpha))

        self._log_alpha = log_alpha
        if max_log_alpha is not None:
            self._max_log_alpha = torch.tensor(float(max_log_alpha))
        else:
            self._max_log_alpha = None

        self._actor_network = actor_network
        self._critic_networks = critic_networks
        self._target_critic_networks = self._critic_networks.copy(name='target_critic_networks')
        self._dqda_clipping = dqda_clipping

        td_lambda = 0.95 if config.mini_batch_length > 2 else 0
        if critic_loss_ctor is None:
            critic_loss_ctor = OneStepTDLoss
        critic_loss_ctor = functools.partial(
            critic_loss_ctor, debug_summaries=debug_summaries)
        self._critic_losses = []
        for i in range(num_critic_replicas):
            self._critic_losses.append(critic_loss_ctor(td_lambda=td_lambda,
                                                        name="critic_loss%d" % (i + 1)))

        self._target_entropy = _set_target_entropy(
            self.name, target_entropy, nest.flatten(self._action_spec))

        self._training_started = False
        self._reproduce_locomotion = reproduce_locomotion

        self._update_target = common.get_target_updater(
            models=[self._critic_networks],
            target_models=[self._target_critic_networks],
            tau=target_update_tau,
            period=target_update_period)

    def _make_networks(self, observation_spec, action_spec, reward_spec,
                       continuous_actor_network_cls, critic_network_cls, q_network_cls):
        discrete_action_spec = [spec for spec in nest.flatten(action_spec) if spec.is_discrete]
        continuous_action_spec = [spec for spec in nest.flatten(action_spec) if spec.is_continuous]

        if discrete_action_spec:
            discrete_action_spec = action_spec
        elif continuous_action_spec:
            continuous_action_spec = action_spec

        actor_network = None
        if continuous_action_spec:
            assert continuous_actor_network_cls is not None, (
                "If there are continuous actions, then a ActorDistributionNetwork "
                "must be provided for sampling continuous actions!")
            actor_network = continuous_actor_network_cls(
                input_tensor_spec=observation_spec, action_spec=continuous_action_spec)
            act_type = ActionType.Continuous
            assert critic_network_cls is not None, (
                "If only continuous actions exist, then a CriticNetwork must be provided!")
            critic_network = critic_network_cls(
                input_tensor_spec=(observation_spec, continuous_action_spec))
            critic_networks = critic_network.make_parallel(self._num_critic_replicas)

        if discrete_action_spec:
            act_type = ActionType.Discrete
            assert len(alf.nest.flatten(discrete_action_spec)) == 1, (
                "Only support at most one discrete action currently! "
                "Discrete action spec: {}".format(discrete_action_spec))
            assert q_network_cls is not None, (
                "If there exists a discrete action, then QNetwork must "
                "be provided!")
            q_network = q_network_cls(
                input_tensor_spec=observation_spec, action_spec=action_spec)
            critic_networks = q_network.make_parallel(self._num_critic_replicas)

        return critic_networks, actor_network, act_type

    # % predict_step & rollout_step
    def predict_step(self, inputs: TimeStep, state: SacState):
        action_dist, action, _, action_state = self._predict_action(
            inputs.observation,
            state=state.action,
            epsilon_greedy=self._epsilon_greedy,  # 0.
            eps_greedy_sampling=True)
        return AlgStep(
            output=action,
            state=SacState(action=action_state),
            info=SacInfo(action_distribution=action_dist))

    def rollout_step(self, inputs: TimeStep, state: SacState):
        """``rollout_step()`` basically predicts actions like what is done by
        ``predict_step()``. Additionally, if states are to be stored a in replay
        buffer, then this function also call ``_critic_networks`` and
        ``_target_critic_networks`` to maintain their states.
        """
        action_dist, action, _, action_state = self._predict_action(
            inputs.observation,
            state=state.action,
            epsilon_greedy=1.0,
            eps_greedy_sampling=True,
            rollout=True)

        if self.need_full_rollout_state():
            _, critics_state = self._compute_critics(
                self._critic_networks, inputs.observation, action,
                state.critic.critics)
            _, target_critics_state = self._compute_critics(
                self._target_critic_networks, inputs.observation, action,
                state.critic.target_critics)
            critic_state = SacCriticState(
                critics=critics_state, target_critics=target_critics_state)
            if self._act_type == ActionType.Continuous:
                # During unroll, the computations of ``critics_state`` and
                # ``actor_state`` are the same.
                actor_state = critics_state
            else:
                actor_state = ()
        else:
            actor_state = state.actor
            critic_state = state.critic

        new_state = SacState(
            action=action_state, actor=actor_state, critic=critic_state)
        return AlgStep(
            output=action,
            state=new_state,
            info=SacInfo(action=action, action_distribution=action_dist))

    def _predict_action(self, observation, state: SacActionState,
                        epsilon_greedy=None, eps_greedy_sampling=False,
                        rollout=False):
        new_state = SacActionState()
        if self._act_type == ActionType.Continuous:
            continuous_action_dist, actor_network_state = self._actor_network(
                observation, state=state.actor_network)
            new_state = new_state._replace(actor_network=actor_network_state)
            if eps_greedy_sampling:  # predict 0. & rollout 1.
                continuous_action = dist_utils.epsilon_greedy_sample(continuous_action_dist, epsilon_greedy)
            else:  # train
                continuous_action = dist_utils.rsample_action_distribution(continuous_action_dist)

            action_dist = continuous_action_dist
            action = continuous_action

        q_values = None
        critic_network_inputs = (observation, None)
        if self._act_type == ActionType.Discrete:
            q_values, critic_state = self._compute_critics(
                self._critic_networks, *critic_network_inputs, state.critic)

            new_state = new_state._replace(critic=critic_state)
            alpha = torch.exp(self._log_alpha).detach()
            logits = q_values / alpha  # p(a|s) = exp(Q(s,a)/alpha) / Z;
            discrete_action_dist = td.Categorical(logits=logits)
            if eps_greedy_sampling:  # predict & rollout ε=0
                discrete_action = dist_utils.epsilon_greedy_sample(discrete_action_dist, epsilon_greedy)
            else:  # train ε=1
                discrete_action = dist_utils.sample_action_distribution(discrete_action_dist)

            action_dist = discrete_action_dist
            action = discrete_action

        if (self._reproduce_locomotion and rollout and not self._training_started):
            # This uniform sampling seems important because for a squashed Gaussian,
            # even with a large scale, a random policy is not nearly uniform.
            action = alf.nest.map_structure(
                lambda spec: spec.sample(outer_dims=observation.shape[:1]),
                self._action_spec)

        return action_dist, action, q_values, new_state

    def _compute_critics(self, critic_net, observation, action, critics_state,
                         replica_min=True):
        if self._act_type == ActionType.Continuous:
            observation = (observation, action)

        # discrete: critics shape [B, replicas, num_actions]
        # continuous: critics shape [B, replicas]
        critics, critics_state = critic_net(observation, state=critics_state)
        if replica_min:
            critics = critics.min(dim=1)[0]

        return critics, critics_state

    # % train_step()
    def train_step(self, inputs: TimeStep, state: SacState, rollout_info: SacInfo):
        self._training_started = True

        action_distribution, action, critics, action_state = self._predict_action(
            inputs.observation, state=state.action)

        # % 计算熵
        log_pi = nest.map_structure(lambda dist, a: dist.log_prob(a), action_distribution, action)
        log_pi = sum(nest.flatten(log_pi))  # Σπ'^logπ'^

        # % 计算损失
        actor_state, actor_loss = self._actor_train_step(
            inputs, state.actor, action, critics, log_pi, action_distribution)
        critic_state, critic_info = self._critic_train_step(
            inputs, state.critic, rollout_info, action, action_distribution)
        alpha_loss = self._alpha_train_step(log_pi)

        state = SacState(action=action_state, actor=actor_state, critic=critic_state)
        info = SacInfo(
            reward=inputs.reward,
            step_type=inputs.step_type,
            discount=inputs.discount,
            action=rollout_info.action,
            action_distribution=action_distribution,
            actor=actor_loss,
            critic=critic_info,
            alpha=alpha_loss,
            log_pi=log_pi)
        return AlgStep(action, state, info)

    def _select_q_value(self, action, q_values):
        """Use ``action`` to index and select Q values.
        Args:
            action (Tensor): discrete actions with shape ``[batch_size]``.
            q_values (Tensor): Q values with shape ``[batch_size, replicas, num_actions]``,
                replicas:
        Returns:
            Tensor: selected Q values with shape ``[batch_size, replicas]``.
        """
        # [batch_size] -> [batch_size, 1, 1]
        action = action.view(q_values.shape[0], 1, 1)
        # [batch_size, 1, 1] -> [batch_size, n, 1]
        action = action.expand(-1, q_values.shape[1], -1).long()
        return q_values.gather(2, action).squeeze(2)

    def _actor_train_step(self, inputs: TimeStep, state, action, critics,
                          log_pi, action_distribution):
        """Q - αlogπθ(a|s)"""
        neg_entropy = sum(nest.flatten(log_pi))

        if self._act_type == ActionType.Discrete:
            # Pure discrete case doesn't need to learn an actor network
            return (), LossInfo(extra=SacActorInfo(neg_entropy=neg_entropy))
        if self._act_type == ActionType.Continuous:
            q_value, critics_state = self._compute_critics(
                self._critic_networks, inputs.observation, action, state)
            cont_alpha = torch.exp(self._log_alpha).detach()

        def actor_loss_fn(dqda, action):
            if self._dqda_clipping:
                dqda = torch.clamp(dqda, -self._dqda_clipping, self._dqda_clipping)
            loss = 0.5 * losses.element_wise_squared_loss((dqda + action).detach(), action)
            return loss.sum(list(range(1, loss.ndim)))

        # This sum() will reduce all dims so q_value can be any rank
        dqda = nest_utils.grad(action, q_value.sum())
        actor_loss = nest.map_structure(actor_loss_fn, dqda, action)
        actor_loss = math_ops.add_n(nest.flatten(actor_loss))
        actor_loss += cont_alpha * log_pi

        actor_info = LossInfo(
            loss=actor_loss,
            extra=SacActorInfo(actor_loss=actor_loss, neg_entropy=neg_entropy))
        return critics_state, actor_info

    def _critic_train_step(self, inputs: TimeStep, state: SacCriticState,
                           rollout_info: SacInfo, action, action_distribution):
        critics, critics_state = self._compute_critics(
            self._critic_networks,
            inputs.observation,
            rollout_info.action,
            state.critics,
            replica_min=False)
        target_critics, target_critics_state = self._compute_critics(
            self._target_critic_networks,
            inputs.observation,
            action,
            state.target_critics)

        if self._act_type == ActionType.Discrete:
            critics = self._select_q_value(rollout_info.action, critics)
            probs = action_distribution.probs  # [B]
            target_critics = torch.sum(probs * target_critics, dim=1)  # V = ∑π(a|s) * Q(s,a)

        target_critic = target_critics.detach()

        state = SacCriticState(critics=critics_state, target_critics=target_critics_state)
        info = SacCriticInfo(critics=critics, target_critic=target_critic)

        return state, info

    def _alpha_train_step(self, log_pi):
        alpha_loss = nest.map_structure(lambda la, lp, t: la * (-lp - t).detach(),
                                        self._log_alpha, log_pi, self._target_entropy)
        return sum(nest.flatten(alpha_loss))

    # % calc_loss
    def calc_loss(self, info: SacInfo):
        critic_loss = self._calc_critic_loss(info)
        alpha_loss = info.alpha
        actor_loss = info.actor

        if self._reproduce_locomotion:
            policy_l = math_ops.add_ignore_empty(actor_loss.loss, alpha_loss)
            policy_mask = torch.ones_like(policy_l)
            policy_mask[0, :] = 0.
            critic_l = critic_loss.loss
            critic_mask = torch.ones_like(critic_l)
            critic_mask[-1, :] = 0.
            loss = critic_l * critic_mask + policy_l * policy_mask
        else:
            loss = math_ops.add_ignore_empty(actor_loss.loss, critic_loss.loss + alpha_loss)

        extra = SacLossInfo(actor=actor_loss.extra, critic=critic_loss.extra, alpha=alpha_loss)
        return LossInfo(loss=loss, priority=critic_loss.priority, extra=extra)

    def _calc_critic_loss(self, info: SacInfo):
        """Put entropy reward in ``experience.reward`` instead of ``target_critics`` 、
        because in multi-step TD learning, the entropy should also appear in intermediate steps!
        This doesn't affect one-step TD loss, however."""
        if self._use_entropy_reward:
            with torch.no_grad():
                entropy_reward = nest.map_structure(
                    lambda la, lp: -torch.exp(la) * lp, self._log_alpha, info.log_pi)
                entropy_reward = sum(nest.flatten(entropy_reward))
                discount = self._critic_losses[0].gamma * info.discount
                info = info._replace(reward=info.reward + entropy_reward * discount)

        critic_info = info.critic
        critic_losses = []
        for i, l in enumerate(self._critic_losses):
            critic_losses.append(
                l(info=info,
                  value=critic_info.critics[:, :, i, ...],
                  target_value=critic_info.target_critic).loss)
        critic_loss = math_ops.add_n(critic_losses)

        if self._calculate_priority:
            valid_masks = (info.step_type != StepType.LAST).to(torch.float32)
            valid_n = torch.clamp(valid_masks.sum(dim=0), min=1.0)
            priority = ((critic_loss * valid_masks).sum(dim=0) / valid_n).sqrt()
        else:
            priority = ()

        return LossInfo(
            loss=critic_loss,
            priority=priority,
            extra=critic_loss / float(self._num_critic_replicas))

    # % after_update
    def after_update(self, root_inputs, info: SacInfo):
        self._update_target()
        if self._max_log_alpha is not None:
            nest.map_structure(
                lambda la: la.data.copy_(torch.min(la, self._max_log_alpha)),
                self._log_alpha)

    def _trainable_attributes_to_ignore(self):
        return ['_target_critic_networks']


from bs4 import BeautifulSoup as Soup  # type: ignore[import]

'''this code operates on the text in the div.rm_content'''

def clean_string(s):
    return s.strip().replace('\xa0', '')

def get_page_links(s):
    links = []
    anchors = s.find_all("a")
    for a in anchors:
        string = list(map(clean_string, a.strings))
        string.append(a["href"])
        links.append(string)
    return list(filter(lambda x: len(x) > 1 and (x[1].split("/")[-1] in ["events", "draw"]), links))

def get_doc_data(s):
    return list(filter(lambda x: x and x != 'Documents', map(clean_string, s)))

def get_regatta_data(s):

    s = list(filter(lambda x: x, map(clean_string, s)))
    keys = "Regatta:,Date:,Venue:".split(",")
    indexes = list(map(lambda x: s.index(x), keys))
    name = s[indexes[0] + 1]
    venue = s[indexes[-1] + 1]
    date = ""
    x = indexes[1] + 1
    while x <= indexes[-1] - 1:
        date += s[x]
        x += 1
    d = dict(name=name, venue=venue, date=date)

    return d

def home_page_processor(s: str):
    soup = Soup(s, "lxml")
    content = soup.find(class_="rm_content")

    tables = content.find_all('table')
    [links, data, docs] = list(
        filter(lambda x: not isinstance(x, str), tables[1].tr.children)
    )
    return [
        get_page_links(links),
        get_regatta_data(data.strings),
        get_doc_data(docs.strings),
    ]


import numpy as np
import openvino.runtime as ov

from PIL import Image

import app_web.nmr as nmr

# const
IMAGE_SIZE = 640
IMAGE_PATH = '../dataset/cropweed/dataset/images/agri_0_14.jpeg'
MODEL_PATH = "./models/best.onnx"

# create openvin runtime
core = ov.Core()

# load and compile model
compiled_model = core.compile_model(MODEL_PATH, "AUTO")

# create infer request
infer_request = compiled_model.create_infer_request()

# load image
img_original = Image.open(IMAGE_PATH)

# preprocess image
img_original = img_original.resize((IMAGE_SIZE, IMAGE_SIZE))
img_original = np.array(img_original, dtype='float32')
img_original = img_original.transpose(2, 0, 1)
img_original = img_original / 255
img_original = img_original.reshape(1, 3, IMAGE_SIZE, IMAGE_SIZE)

# create tensor from external memory
input_tensor = ov.Tensor(array=img_original, shared_memory=False)

# set input tensor for model with one input
infer_request.set_input_tensor(input_tensor)

# start request
infer_request.start_async()
infer_request.wait()

# get output tensor for model with one output
output = infer_request.get_output_tensor()
output_data = output.data

# perform NMS
result_boxes, result_scores, result_class_names = nmr.nms(output_data[0])

# exit if no box found
if len(result_boxes) == 0:
    print("No boxes found")
    exit(0)

# print detection
print("TOTAL: ", len(result_boxes))
for i in range(len(result_boxes)):
    print("Bounding box: ", result_boxes[i])
    print("Scores: ", result_scores[i])
    print("Classes: ", result_class_names[i])

# load and
img_pred = Image.open(IMAGE_PATH)
img_pred = nmr.draw_boxes(img_pred, result_boxes, result_scores, result_class_names)
img_pred.save('result-runtime.png')


"""
    #  @ModuleName: task
    #  @Function:
    #  @Author: Ljx
    #  @Time: 2020/12/9 20:32
"""
import base64
import uuid
from celery import shared_task
import logging
import requests
import os
import time
from .common.sdk_subprocess import sdk_subprocess
from algoSdk.common.iter_files import iter_files
from .common.sdk_function import xml_create, txt_create, clear_dirs
from .common.argsCmd import url_image, url_video, algo_sdk_dir, ori_files_dir, res_files_dir

logger = logging.getLogger(__name__)

@shared_task
def algo_ias_files(container_id, file_name, port, args):
    """
    后台进行 ias 运行算法得到结果
    :param args:
    :param random_str:
    :param ori_files_dir: 数据集目录
    :param self: 更新自己获取当前状态
    :param res_files_dir: 数据集运行结果目录
    :param file_name: 文件名称
    :param port: 端口
    :return:
    """

    random_str = ''.join([each for each in str(uuid.uuid1()).split('-')])
    res_dir = res_files_dir % random_str
    ori_dir = ori_files_dir % random_str
    if not os.path.exists(ori_dir) or not os.path.exists(res_dir):
        try:
            os.makedirs(res_dir)
            os.makedirs(ori_dir)
        except Exception as e:
            logging.error(e)
            return False
    try:
        # 解压文件 删除下载文件
        os.system(f"unzip {file_name} -d {ori_dir}")
        os.system(f"rm -f {file_name}")
    except Exception as e:
        logging.error(e)
        return False
    # 返回文件列表
    filesname = iter_files(ori_dir, file_type="algoRunRes")
    # 获取文件全路径列表
    files_with_dir = filesname["files"]
    err_files = filesname["err_file"]
    # 计算有效文件数目
    file_nums = len(files_with_dir) - len(err_files)
    # 初始化运行文件数目
    res_files_count = 0
    cmd = f"netstat -aptn |grep {port}"
    status, res = sdk_subprocess(cmd)
    if not status:
        logging.error(status)
        return False
    # 需要判断端口是否启动成功之后才能继续往下调用算法, 不然算法没有启动车就就会导致算法运行失败
    while "LISTEN" not in res:
        status, res = sdk_subprocess(cmd)
    time.sleep(2)
    for file_with_dir in files_with_dir:
        # 原文件名称 文件路径
        file_dir, file = os.path.split(file_with_dir)
        # 调用IAS
        try:
            if file.lower().endswith("avi") or file.lower().endswith("mp4") or file.lower().endswith("flv"):
                data = {
                    'video': (file, open(file_with_dir, 'rb')),
                    "args": args
                }
                res_base64 = requests.post(url_video % port, files=data).json()
            else:
                data = {
                    'image': (file, open(file_with_dir, 'rb')),
                    "args": args
                }
                res_base64 = requests.post(url_image % port, files=data).json()
        except Exception as e:
            logging.exception(e)
            return {'current': 100, 'total': 100, 'status': '算法调用失败', 'result': "-1", "error_files": err_files,
                    "ori_files_dir": ori_dir, "res_files_dir": res_dir, "container_id": container_id}
        res = res_base64.get('buffer')
        if res_base64.get("code") != 0:
            logging.exception(res)
            return {'current': 100, 'total': 100, 'status': '算法调用结果异常', 'result': "-1", "error_files": err_files,
                    "ori_files_dir": ori_dir, "res_files_dir": res_dir, "container_id": container_id}
        try:
            algo_res_json = res_base64.get("result")
        except Exception as e:
            logging.exception(e)
            return {'current': 100, 'total': 100, 'status': '获取算法json结果失败', 'result': "-1",
                    "error_files": err_files,
                    "ori_files_dir": ori_dir, "res_files_dir": res_dir, "container_id": container_id}
        res = base64.decodebytes(res.encode('ascii'))
        # 结果文件路径
        res_file_dir = file_dir.replace(f"ori_{random_str}", f"res_{random_str}").replace("algoFilesdir", "algoFileResdir")
        res_file_dir_txt = os.path.join(res_file_dir, "res.txt")
        res_file_name = os.path.join(res_file_dir, file)
        if not os.path.exists(res_file_dir):
            os.makedirs(res_file_dir)
        with open(res_file_name, 'wb') as f:
            f.write(res)
        res_file_name = res_file_name.split('/')[-1]
        with open(res_file_dir_txt, 'a') as f:
            f.write(str(res_file_name) + '\n')
            f.write(str(algo_res_json) + '\n')
        res_files_count += 1
        process = int((res_files_count / file_nums) * 100)
    algo_ias_files.update_state(state='PROGRESS', meta={'current': res_files_count, 'total': file_nums, 'status': process})
    try:
        os.system(f"cd {res_dir};tar -cvf result.tar *")
        store_path = f"{res_dir}/result.tar"
    except Exception as e:
        logging.error(e)
        return False
    return {'current': 100, 'total': 100, 'status': 'Task completed!', 'result': store_path, "error_files": err_files,
            "ori_files_dir": ori_dir, "res_files_dir": res_dir, "container_id": container_id}

@shared_task
def run_files(ori_dir, port, tag_names, iou, args, alert_info):
    filenames = iter_files(ori_dir,  file_type="algoPerssion")
    xmls = filenames["xmls"]
    files = filenames["files"]
    total_files = len(files)
    file_count = 0
    cmd = f"netstat -aptn |grep {port}"
    status, res = sdk_subprocess(cmd)
    if not status:
        logging.error(status)
        return False
    time.sleep(5)
    for xml in xmls:
        xml_create(xml)
    for file in files:
        file_count += 1
        txt_create(file, port, tag_names, args, alert_info)
        process = int(file_count / total_files * 100)
        run_files.update_state(state='PROGRESS', meta={'current': file_count, 'total': total_files, 'status': process})
    main = os.path.join(algo_sdk_dir, "utils/sdk_precision/main.py")
    if iou is None:
        cmd = f"python3 {main}"
    else:
        cmd = f"python3 {main} -t {iou}"
    os.system(cmd)

    file_res = os.path.join(algo_sdk_dir, f"utils/sdk_precision/output/output.txt")
    with open(file_res, 'r') as f:
        res = f.read().splitlines()
        res = str(res).replace("'',", "\n")
    contain_stop = "docker ps |grep %s|awk '{print $1}'|xargs docker stop" % port
    status, _ = sdk_subprocess(contain_stop)
    os.system(f"rm -rf {ori_dir}")
    clear_dirs()
    return {'current': 100, 'total': 100, 'status': 'Task completed!', "result": res}


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap

from Perceptron import *

def train(X,y):
    model = Perceptron(eta=0.001,n_iter=400)
    res = model.fit(X, y)

    print("w=", res.w_)
    #print("errors=", res.errors_)
    #showAfterTrainingErrors(res.errors_)
    return model

def prePareData():
    M = 100  #nSamples
    N = 4    #nFeatures
    df = pd.read_csv(r'..\..\dataBase\Iris\iris.data')
    y = df.iloc[0:M, -1].values
    y = np.where(y == 'Iris-setosa', -1, 1)
    X = df.iloc[0:M, [0, 1]].values

    #print('X=',X)
    #print('y=',y)
    return X,y

def main():
    X,y = prePareData()
    model = train(X,y)

    #test four features
    #Value = [5.6, 2.9,3.8,1.5]
    #Value = [5.6, 3.8]
    #print(model.net_input(Value),model.predict(Value))

    ShowPrediction(X, y, model)

def showIrisData(df):
    y = df.iloc[0:100, 4].values
    y = np.where(y == 'Iris-setosa', -1, 1)
    X = df.iloc[0:100, [0, 2]].values

    plt.scatter(X[:50, 0], X[:50, 1],color='red', marker='o', label='setosa')
    plt.scatter(X[50:100, 0], X[50:100, 1],color='blue', marker='x', label='versicolor')
    plt.xlabel('petal length')
    plt.ylabel('sepal length')
    plt.legend(loc='upper left')
    plt.show()
    pass

def showAfterTrainingErrors(errors_):
    plt.plot(range(1, len(errors_) + 1), errors_,marker='o')
    plt.xlabel('Epochs')
    plt.ylabel('Number of misclassifications')
    plt.show()

def ShowPrediction(X, y, classifier, resolution=0.02):
    # setup marker generator and color map
    markers = ('s', 'x', 'o', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])

    # plot the decision surface
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
    np.arange(x2_min, x2_max, resolution))
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
    Z = Z.reshape(xx1.shape)
    plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())

    # plot class samples
    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1],
                    alpha=0.8, c=cmap(idx),
                    marker=markers[idx], label=cl)

    plt.xlabel('sepal length [cm]')
    plt.ylabel('petal length [cm]')
    plt.legend(loc='upper left')
    plt.show()

if __name__ == '__main__':
    main()


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

import os, sys, shutil, subprocess, time

def is_compressible_image_file(filename):
    filename_split_dot = filename.split('.')
    if len(filename_split_dot) < 2:
        return False
    if any([len(el.replace(' ',''))==0 for el in filename_split_dot[-2:]]):
        return False
    if filename_split_dot[-1] not in ['jpg', 'jpeg', 'png']:
        return False
    return True

def clean_filename(filename):
    filename_split_dot = filename.split('.')
    return '.'.join(filename_split_dot[0:-1]).replace("'",'').replace('.','_').replace('/','_').replace(' ','') + '.' + filename_split_dot[-1]

def compress_file(filename, filename_out=None, comp_ratio=20, verbose=0):

    #check inputs
    assert isinstance(comp_ratio, int)
    assert comp_ratio > 1
    filename = os.path.abspath(filename)
    assert os.path.exists(filename)
    if not is_compressible_image_file(filename):
        print('file %s does not appear to be a compressible image'%filename)
        return
    if filename_out is not None:
        filename_out = os.path.abspath(filename_out)
        assert is_compressible_image_file(filename_out)
        assert filename_out.split('.')[-1] == filename.split('.')[-1], 'output file cannot have a different extension than input file'
    else:
        filename_out = '%s_compressed%d.%s'%('.'.join(filename.split('.')[0:-1]), comp_ratio, filename.split('.')[-1])
    assert filename_out != filename, 'input and output files cannot be the same'

    #make output directory if necessary
    os.makedirs(os.path.dirname(os.path.abspath(filename_out)), exist_ok=True) #make output folder if it does not exist

    subprocess.call('unset LD_LIBRARY_PATH; ffmpeg -loglevel panic -nostats -i "%s" -q:v %d "%s"'%(filename, comp_ratio, filename_out), shell=True)

    if verbose > 0:
        print('%s -> %s (compressed by ratio %d)'%(filename, filename_out, comp_ratio))

def shell_search_files(input_folder, keyword=None):
    cmd = "find %s -type f"%input_folder.replace(' ','\ ').replace('(','\(').replace(')','\)')
    if keyword is not None:
        cmd += " -iname '%s'"%keyword
    files_found = subprocess.check_output(cmd, shell=True).decode('utf-8').split('\n')
    files_found = [os.path.abspath(el) for el in files_found if os.path.exists(el)]
    return files_found

def compress_files_in_folder(input_folder, compressed_folder=None, comp_ratio=20, min_size_on_disk_for_compression=None, duplicate_non_compressible_files=False):

    if min_size_on_disk_for_compression is None:
        min_size_on_disk_for_compression = 0.

    input_folder = os.path.abspath(input_folder)
    if compressed_folder is None:
        compressed_folder = input_folder + '_compressed_images'
    compressed_folder = os.path.abspath(compressed_folder)
    os.makedirs(compressed_folder, exist_ok=True)
    if len(os.listdir(compressed_folder)):
        raise Exception('output folder is not empty, aborting...')

    input_files = shell_search_files(input_folder)
    for input_file in input_files:
        output_file = input_file.replace(input_folder, compressed_folder)
        if is_compressible_image_file(input_file):
            if os.path.getsize(input_file)/1.e6 >= min_size_on_disk_for_compression:
                try:
                    compress_file(input_file, filename_out=output_file, comp_ratio=comp_ratio, verbose=1)
                except:
                    raise
                    print('Compression failed for file %s, copying it to %s instead of compressing it'%(input_file, output_file))
                    shutil.copy(input_file, output_file)
                continue
        if duplicate_non_compressible_files:
            os.makedirs(os.path.dirname(os.path.abspath(output_file)), exist_ok=True)
            shutil.copy(input_file, output_file)

if __name__ == '__main__':

    import argparse
    parser = argparse.ArgumentParser(description="compress jpeg images using ffmpeg", formatter_class=argparse.RawTextHelpFormatter)
    parser.add_argument("--input", type=str, required=True, help="input path")
    parser.add_argument("--output", type=str, help="output path")
    parser.add_argument("--compression_ratio", type=int, default=20, help="ffmpeg compression ratio (default is 20).")
    parser.add_argument("--min_size_on_disk_for_compression", type=float, help='minimum image size to activate compression in MB. ' + \
        'This is to avoid recompressing already compressed images.')
    parser.add_argument("--duplicate_non_compressible_files", action='store_true', help='if input is folder, than make a complete copy of input folder by duplicating ' + \
        'non image file instad of just generating outputs for image files.')
    args = parser.parse_args()

    if os.path.isdir(args.input):
        compress_files_in_folder(args.input, compressed_folder=args.output, comp_ratio=args.compression_ratio, \
            min_size_on_disk_for_compression=args.min_size_on_disk_for_compression, duplicate_non_compressible_files=args.duplicate_non_compressible_files)
    else:
        compress_file(args.input, filename_out=args.output, comp_ratio=args.compression_ratio)


import json
import xml.etree.ElementTree as et

# Factory Pattern
class Person:

    def __init__(self, first_name, last_name, age):
        self.first_name = first_name
        self.age = age
        self.last_name =last_name

class PersonDetails:

    # Factory Method
    # this is the application code that depends on an interface to complete its task.
    # here the application delegates the decision to the get_serializer method.
    def serialize(self, person, format):
        serializer = get_serializer(format)
        return serializer(person)

# The creator component. yeh btata hay k knsa concrete implementaion method run huga.
def get_serializer(format):
    if format == 'JSON':
        return _serialize_to_json
    elif format == 'XML':
        return _serialize_to_xml
    else:
        raise ValueError(format)

# method of concrete implementation
def _serialize_to_json(person):

    person_info = {
        'first_name': person.first_name,
        'last_name': person.last_name,
        'age': person.age,
    }
    return json.dumps(person_info)

# method of concrete implementation
def _serialize_to_xml(person):

    person_info = et.Element('person', attrib={'first_name': person.first_name})

    title = et.SubElement(person_info, 'last_name')
    title.text = person.last_name

    artist = et.SubElement(person_info, 'age')
    artist.text = person.age

    return et.tostring(person_info, encoding='unicode')

obj = Person('Maaz', 'Sabahuddin', '20')
print(PersonDetails().serialize(obj, 'JSON'))


# filename: field_current_tr.py
#
# The following helper functions provide the calculation of magnetic fields and associated currents,
# using a cubic model for the relation between the current and magnetic field (and vice versa).
#
# Author: Maxwell Guerne-Kieferndorf (QZabre)
#            gmaxwell at student.ethz.ch
#
# Date: 09.10.2020
# latest update: 06.01.2021

########## Standard library imports ##########
import math
import pickle

import joblib
import numpy as np
import pandas as pd
from sklearn import linear_model
from sklearn.preprocessing import PolynomialFeatures

# Lookup table for current/magnetic field values
# LookupTable = {}
# filepathLUT = r'data_sets\linearization_matrices\20_11_16_180159-86LUT.csv'
# def buildLUT(path=filepathLUT):
#     global LookupTable

#     dataLUT = pd.read_csv(path).to_numpy()
#     directionsB = dataLUT[:,0:3]
#     currentConfigs = dataLUT[:,3:6]

#     for i in range(len(directionsB)):
#         unit = np.around(directionsB[i]/20, 3)
#         unitCurrents = np.around(currentConfigs[i]/20, 3)

#         LookupTable[f'direction {i+1}'] = (unit.tolist(), unitCurrents.tolist())

def read_fitting_parameters(filepath):
    """Extract fitting paramters A from file."""
    # extract data and convert to ndarray
    A = pd.read_csv(filepath).to_numpy().T

    return A

def evaluate_fit(A, xdata):
    """
    Given the paramters A, estimate the outputs for the provided xdata.

    Args:
        A (ndarray of shape (k,3)): fitting paramters for the three components individually.
                                    The size k of the first dimension depends on the fitting degree.
                                    Currently implemented are k=3,9,19 only.
        xdata (ndarray of shape (N,3)): Input data for which the corresponding output data should be computed.

    Returns:
        ndarray of shape (N,3): Estimated outputs based on the inputs and fitting paramters
    """
    # initialize array for fits
    fits = np.zeros_like(xdata)

    # linear fit
    if A.shape[1] == 3:
        for i in range(len(xdata)):
            fits[i] = A @ xdata[i]

    elif A.shape[1] == 9:
        # estimate expected fields based on fits

        for i in range(len(xdata)):
            # linear part
            fits[i] = A[:, :3] @ xdata[i]

            # quadratic part
            fits_quadratic = np.zeros(3)
            for component in range(3):
                A_tri = np.zeros((3, 3))
                A_tri[np.triu_indices(3)] = A[component, 3:]
                fits_quadratic[component] = xdata[i].reshape(1, 3) @ A_tri @ xdata[i].reshape(3, 1)

            fits[i] += fits_quadratic

    # cubic fit including cross terms
    elif A.shape[1] == 19:
        for i in range(len(xdata)):
            # linear part
            fits[i] = A[:, :3] @ xdata[i]

            # quadratic part
            fits_quadratic = np.zeros(3)
            for component in range(3):
                A_tri = np.zeros((3, 3))
                A_tri[np.triu_indices(3)] = A[component, 3:9]
                fits_quadratic[component] = xdata[i].reshape(1, 3) @ A_tri @ xdata[i].reshape(3, 1)
            fits[i] += fits_quadratic

            # cubic part
            combis = np.array([[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 1, 1], [0, 1, 2],
                               [0, 2, 2], [1, 1, 1], [1, 1, 2], [1, 2, 2], [2, 2, 2]])
            fits_cubic = np.zeros(3)
            for component in range(3):
                for k in range(10):
                    fits_cubic[component] += A[component, k + 9] * xdata[i, combis[k, 0]] * \
                        xdata[i, combis[k, 1]] *   \
                        xdata[i, combis[k, 2]]
            fits[i] += fits_cubic

    return fits

def computeMagneticFieldVector(magnitude: float, theta: float, phi: float):
    """
    Compute the cartesian coordinates of a magnetic field with an arbitrary direction
    and an arbitrary magnitude, given the spherical coordinates.

    Args:
        magnitude: of the B-field, units: [mT]
        theta: polar angle, between desired field direction and z axis
        phi: azimuthal angle (angle measured counter clockwise from the x axis)

    Returns:
        Vector of 3 B field components (Bx,By,Bz), as a np.array, units: [mT]
    """

    x = math.sin(math.radians(theta)) * math.cos(math.radians(phi))
    y = math.sin(math.radians(theta)) * math.sin(math.radians(phi))
    z = math.cos(math.radians(theta))

    unitVector = np.array((x, y, z))
    unitVector = unitVector / np.linalg.norm(unitVector)

    return np.around(unitVector * magnitude, 3)

def computeCoilCurrents(B_fieldVector, linear_model=True):
    """
    Compute coil currents (in mA) required to generate the desired magnetic field vector.
    Actuation matrix derived from simulations so far

    Args:
        B_fieldVector: np.array containing the B-field, in cartesian coordinates, magnitude units: [mT]

    Returns:
        Vector of 3 current values, as a np.array, units: [A]
    """
    if linear_model:
        filename = r'fitting_parameters\model_QSM_poly1_nooffset_B2I.sav'

    else:
        filename = r'fitting_parameters\model_QSM_poly3_nooffset_B2I.sav'

    # load the model from disk
    [loaded_model, loaded_poly] = pickle.load(open(filename, 'rb'))
    # preprocess test vectors, st. they have correct shape for model
    B_fieldVector_reshape = B_fieldVector.reshape((1, 3))
    test_vectors_ = loaded_poly.fit_transform(B_fieldVector_reshape)
    # estimate prediction
    currVector = loaded_model.predict(test_vectors_)
    currVector = currVector.reshape(3)  # in amps
    currVector = np.round(currVector, 3)  # round to nearest milliamp

    return currVector

def computeMagField(currVector, linear_model=True):
    """
    Compute magnetic field vector generated by the currents. Uses cubic regression model.

    Args:
        currVector: Vector of 3 current values, as a np.array, units: [A]

    Returns:
        Vector of 3 B field components (Bx,By,Bz), as a np.array, units: [mT]
    """
    if linear_model:
        filename = r'fitting_parameters\model_QSM_poly1_nooffset_I2B.sav'

    else:
        filename = r'fitting_parameters\model_QSM_poly3_nooffset_I2B.sav'

    # load the model from disk
    [loaded_model, loaded_poly] = pickle.load(open(filename, 'rb'))
    # preprocess test vectors, st. they have correct shape for model
    currVector = currVector  # in amps
    currVector_reshape = currVector.reshape((1, 3))
    test_vectors_ = loaded_poly.fit_transform(currVector_reshape)
    # estimate prediction
    B_fieldVector = loaded_model.predict(test_vectors_)

    return np.round(B_fieldVector.reshape(3), 3)

def rotationMatrix(inVector=np.array([1, 0, 0]),
                   theta: float = 90, psi: float = 0, alpha: float = 10.1):
    """
    Rotate a vector around any axis (defined by angles psi and theta), rotation around axis given by alpha

    Args:
        inVector: arbitrary cartesian R^3 vector
        psi: azimuthal angle, in degrees
        theta: polar angle (measured downward from z axis), in degrees
        alpha: counterclockwise rotation amount around the specified axis, in degrees

    Returns:
        Vector of 3 B field components (Bx,By,Bz), as a np.array, units: [mT]
    """

    a_x = math.sin(math.radians(theta)) * math.cos(math.radians(psi))
    a_y = math.sin(math.radians(theta)) * math.sin(math.radians(psi))
    a_z = math.cos(math.radians(theta))

    axis = np.array([a_x, a_y, a_z])
    #a_unit = a_unit / np.linalg.norm(a_unit)

    #print('Axis of rotation (Cartesian) : \n ', a_unit)

    rot_matrix = np.zeros((3, 3))
    rot_matrix[0, 0] = math.cos(math.radians(
        alpha)) + ((axis[0] ** 2) * (1 - math.cos(math.radians(alpha))))
    rot_matrix[1, 0] = axis[1] * axis[0] * \
        (1 - math.cos(math.radians(alpha))) + \
        a_z * math.sin(math.radians(alpha))
    rot_matrix[2, 0] = axis[2] * axis[0] * (1 - math.cos(math.radians(alpha))) - axis[1] * math.sin(
        math.radians(alpha))

    rot_matrix[0, 1] = axis[0] * axis[1] * \
        (1 - math.cos(math.radians(alpha))) - \
        a_z * math.sin(math.radians(alpha))
    rot_matrix[1, 1] = math.cos(math.radians(
        alpha)) + ((axis[1] ** 2) * (1 - math.cos(math.radians(alpha))))
    rot_matrix[2, 1] = axis[2] * axis[1] * (1 - math.cos(math.radians(alpha))) + axis[0] * math.sin(
        math.radians(alpha))

    rot_matrix[0, 2] = axis[0] * axis[2] * (1 - math.cos(math.radians(alpha))) + axis[1] * math.sin(
        math.radians(alpha))
    rot_matrix[1, 2] = axis[1] * axis[2] * (1 - math.cos(math.radians(alpha))) - axis[0] * math.sin(
        math.radians(alpha))
    rot_matrix[2, 2] = math.cos(math.radians(
        alpha)) + ((axis[2] ** 2) * (1 - math.cos(math.radians(alpha))))

    return np.around(rot_matrix.dot(inVector), 3)

if __name__ == '__main__':
    # ------------------------Testing area--------------------------
    #
    # test the transformation functions
    # buildLUT()
    # print('Lookup table:')
    # for key in LookupTable:
    #     print(f'{key} = {LookupTable[key]}')
    B1 = computeMagneticFieldVector(theta=90, phi=90, magnitude=50)
    # B1 = np.array([-46.7, -11, 23])
    print(f'Bx = {B1[0]}mT, By = {B1[1]}mT, Bz = {B1[2]}mT')
    currents = computeCoilCurrents(B1, True)
    print(f'I1 = {currents[0]}A, I2 = {currents[1]}A, I3 = {currents[2]}A')
    B2 = computeMagField(currents, True)
    print(f'Bx = {B2[0]:.3f}mT, By = {B2[1]:.3f}mT, Bz = {B2[2]:.3f}mT')


#import matplotlib.pyplot as plt
import pandas as pd
#import seaborn as sns
import plotly.express as px
from plotly import graph_objects as go
from plotly.subplots import make_subplots
#Before the analysis, I am wondering whether there's a inequlaity between gender and income. Surprisely, women's income is higher that men's.
#Therefore, the second analysis is aim to explain the result. No matter in which education level, the population of women is bigger than men.

def EDA():
    data1 = pd.read_csv("data/Wei/ICE_MARRY_INCOME_EDU.csv", engine='python',on_bad_lines='skip')
    #data1.columns =['CASEID','ICE', 'GOVT','INCOME','AGE','SEX' ,'MARRY', 'EDUC']
    data1['INCOME'] = pd.to_numeric(data1['INCOME'], errors='coerce')

    data1['INCOME2']=data1.loc[:,['INCOME']].round(-4)
    data1['INCOME2']=data1.loc[:,['INCOME2']].clip(upper=100000.0)
    #print(data1.head())
    fig1 = make_subplots(rows=2, cols=1,  subplot_titles=("Male", "Female"))

    fig1.append_trace(go.Histogram(x=data1['INCOME2'].mask(data1['SEX']=='1'),histnorm='percent'), row=1, col=1)
    fig1.append_trace(go.Histogram(x=data1['INCOME2'].mask(data1['SEX']=='2'),histnorm='percent'), row=2, col=1)
    fig1.update_xaxes(title_text="Income", row=1, col=1)
    fig1.update_xaxes(title_text="Income", row=2, col=1)
    fig1.update_yaxes(title_text="Percentage", row=1, col=1)
    fig1.update_yaxes(title_text="Percentage", row=2, col=1)
    #fig1.show()

    fig2 = make_subplots(rows=2, cols=3,subplot_titles=("Grade 0-8 no hs diploma", "Grade 9-12 no hs diploma", "Grade 0-12 w/ hs diploma", "Grade 13-17 no col degree", "Grade 13-16 w/ col degree", "Grade 17 W/ col degree"))

    fig2.append_trace(go.Histogram(x=data1['SEX'].mask(data1["EDUC"]=='1'),histnorm='percent'), row=1, col=1)
    fig2.append_trace(go.Histogram(x=data1['SEX'].mask(data1["EDUC"]=='2'),histnorm='percent'), row=1, col=2)
    fig2.append_trace(go.Histogram(x=data1['SEX'].mask(data1["EDUC"]=='3'),histnorm='percent'), row=1, col=3)
    fig2.append_trace(go.Histogram(x=data1['SEX'].mask(data1["EDUC"]=='4'),histnorm='percent'), row=2, col=1)
    fig2.append_trace(go.Histogram(x=data1['SEX'].mask(data1["EDUC"]=='5'),histnorm='percent'), row=2, col=2)
    fig2.append_trace(go.Histogram(x=data1['SEX'].mask(data1["EDUC"]=='6'),histnorm='percent'), row=2, col=3)
    fig2.update_xaxes(title_text="SEX", row=1, col=1)
    fig2.update_xaxes(title_text="SEX", row=2, col=1)
    fig2.update_xaxes(title_text="SEX", row=1, col=2)
    fig2.update_xaxes(title_text="SEX", row=2, col=2)
    fig2.update_xaxes(title_text="SEX", row=1, col=3)
    fig2.update_xaxes(title_text="SEX", row=2, col=3)
    fig2.update_yaxes(title_text="percentage", row=1, col=1)
    fig2.update_yaxes(title_text="percentage", row=2, col=1)
    fig2.update_yaxes(title_text="percentage", row=1, col=2)
    fig2.update_yaxes(title_text="percentage", row=2, col=2)
    fig2.update_yaxes(title_text="percentage", row=1, col=3)
    fig2.update_yaxes(title_text="percentage", row=2, col=3)

    return [(fig1,'Relationship between Gender and Income'),(fig2,'Relationship between Gender and EDU')]


from collections import defaultdict

def singleNumber(nums):
    record = defaultdict(int)
    for n in nums:
        record[n] += 1

    for key, value in record.items():
        if value == 1:
            return key

print(singleNumber([1,3,3,4,4]))


import pylab as pl
import numpy as np
from scipy.integrate import odeint

def logistique(y, t):
    dydt = a * y[0] * (1.0 - y[0] / N)
    ydot = [dydt]
    return ydot

# Paramètres
a = 1.0
N = 1.0
t_min = 0.0
t_max = 2.0
n_points = 100
t = np.linspace(t_min, t_max, n_points)

#
pl.figure(figsize=(3.0, 1.5))
y0 = [0.5]
y = odeint(logistique, y0, t)
pl.plot(t, y[:, 0], "-")
pl.plot(t, np.ones(n_points), "k-")
pl.plot(t, np.zeros(n_points), "k-")
pl.xlabel(u"$t$")
pl.ylabel(u"$y$")
pl.title(u"Modèle logistique.")

# Plusieurs conditions initiales
pl.figure(figsize=(3.0, 1.5))
for y_initial in np.linspace(-0.05, 1.5, 5):
    y0 = [y_initial]
    y = odeint(logistique, y0, t)
    pl.plot(t, y[:, 0], "-")
pl.plot(t, np.ones(n_points), "k-")
pl.plot(t, np.zeros(n_points), "k-")
pl.xlabel(u"$t$")
pl.ylabel(u"$y$")
pl.title(u"Modèle logistique")
pl.savefig("logistique-dynamique.pdf", bbox_inches="tight")

# Vector field
n_points = 10
t_range = np.linspace(t_min, t_max, 10)
y_range = np.linspace(-0.5, 1.5, 10)
T, Y = np.meshgrid(t_range, y_range)
dtdt = np.ones(T.shape)
dydt = a * Y * (1.0 - Y / N)
# Normalize arrows
s = np.sqrt(dtdt ** 2 + dydt ** 2)
dtdt = dtdt / s
dydt = dydt / s

#
pl.figure(figsize=(2.5, 1.5))
pl.title(u"Modèle logistique")
pl.xlabel(u"$t$")
pl.ylabel(u"$y$")
pl.quiver(T, Y, dtdt, dydt, angles="xy")
t = np.linspace(t_min, t_max, n_points)
for y_initial in np.linspace(-0.05, 1.5, 5):
    y0 = [y_initial]
    y = odeint(logistique, y0, t)
    pl.plot(t, y[:, 0], "-")
pl.plot(t, np.ones(n_points), "k-")
pl.plot(t, np.zeros(n_points), "k-")
pl.savefig("logistique-champ.pdf", bbox_inches="tight")


def count_ice_cells(N, M, grid):
    def is_ice(x, y):
        return 0 <= x < N and 0 <= y < M and grid[x][y] == '.'  # 修正

    def move(x, y, dx, dy):
        count = 0
        while is_ice(x + dx, y + dy):
            x += dx
            y += dy
            count += 1
        return x, y, count

    visited = set()
    stack = [(1, 1)]  # 初期位置を(1, 1)に修正
    visited.add((1, 1))  # 初期位置を(1, 1)に修正
    count = 0  # 初期値を0に修正

    while stack:
        x, y = stack.pop()
        neighbors = [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]

        for nx, ny in neighbors:
            if (nx, ny) not in visited and is_ice(nx, ny):
                stack.append((nx, ny))
                visited.add((nx, ny))
                x, y, cnt = move(nx, ny, nx - x, ny - y)
                count += cnt + 1  # プレイヤーが氷の上で停止できるので+1

    return count

# 入力を受け取る
N, M = map(int, input().split())
grid = [input() for _ in range(N)]

# 出力
result = count_ice_cells(N, M, grid)
print(result)


#!/usr/bin/python3

# Order of domains for plotting
order = {"data-driven": ["MEMORY", "REWARD", "COGNITION",
						 "VISION", "MANIPULATION", "LANGUAGE"],
		 "rdoc": ["NEGATIVE_VALENCE", "POSITIVE_VALENCE", "AROUSAL_REGULATION",
				  "SOCIAL_PROCESSES", "COGNITIVE_SYSTEMS", "SENSORIMOTOR_SYSTEMS"],
		 "dsm": ["DEPRESSIVE", "ANXIETY", "TRAUMA_STRESSOR",
		 		 "OBSESSIVE_COMPULSIVE", "DISRUPTIVE", "SUBSTANCE",
		 		 "DEVELOPMENTAL", "PSYCHOTIC", "BIPOLAR"]}

def make_cmap(hex, name="colormap"):

	# Adapted from http://schubert.atmos.colostate.edu/~cslocum/custom_cmap.html

	import matplotlib as mpl
	import numpy as np

	if len(hex) != 7:
		raise Exception("Pass a color in hex (#EAEAEA) format")

	rgb_hex = [hex[x:x+2] for x in [1, 3, 5]]
	rgb = [int(hex_value, 16) for hex_value in rgb_hex]
	rgb = [min([255, max([0, i])]) / 255.0 for i in rgb]

	colors = []
	for brightness_offset in np.linspace(1,-0.7,18):
		colors.append(tuple([rgb_value + brightness_offset for rgb_value in rgb]))

	bit_rgb = np.linspace(0,1,256)

	position = np.linspace(0,1,len(colors))
	cdict = {"red":[], "green":[], "blue":[]}
	for pos, color in zip(position, colors):
		cdict["red"].append((pos, color[0], color[0]))
		cdict["green"].append((pos, color[1], color[1]))
		cdict["blue"].append((pos, color[2], color[2]))

	cmap = mpl.colors.LinearSegmentedColormap(name, cdict, 256)
	return cmap

# Font for plotting
font = "../style/Arial Unicode.ttf"

# Hex color mappings
c = {"magenta": "#AA436A", "red": "#CA4F52", "vermillion": "#C16137", "brown": "#AC835B", "orange": "#E8B586",
	 "gold": "#D19A17", "yellow": "#DCC447", "chartreuse": "#D9DC77", "lime": "#82B858", "green": "#43A971",
	 "teal": "#48A4A8", "blue": "#5B81BD", "indigo": "#7275B9", "purple": "#924DA0", "lavendar": "#D599DD"}

# Prespecified color order for each framework
fw2c = {"data-driven": ["blue", "vermillion", "yellow", "purple", "green", "gold"],
	    "rdoc": ["teal", "red", "chartreuse", "lavendar", "lime", "orange"],
	    "dsm": ["teal", "red", "chartreuse", "lavendar", "lime", "orange", "indigo", "magenta", "brown"]}

# Palettes for general plotting
palettes = {fw: [c[color] for color in colors] for fw, colors in fw2c.items()}

# Colormaps for plotting brains
colormaps = {fw: [make_cmap(c[color], name=fw) for color in colors] for fw, colors in fw2c.items()}

# Marker shapes for MDS plots
shapes = ["o", "v", "^", ">", "<", "s", "X", "D", "p"]

# Nudges for plotting modularity means
mod_dx = {"data-driven_lr": [0.34, 0.355, 0.38, 0.32, 0.34, 0.34],
		  "data-driven_nn": [0.34, 0.36, 0.37, 0.31, 0.34, 0.34],
	  	  "rdoc": [0.3, 0.34, 0.35, 0.35, 0.35, 0.34],
	  	  "dsm": [0.34, 0.36, 0.38, 0.33, 0.34, 0.33, 0.32, 0.32, 0.3]}

# Nudges for plotting generalizability means
gen_dx = {"data-driven_lr": [0.39, 0.39, 0.37, 0.39, 0.39, 0.38],
		  "data-driven_nn": [0.38, 0.37, 0.37, 0.37, 0.37, 0.36],
	  	  "rdoc": [0.3, 0.35, 0.36, 0.37, 0.35, 0.36],
	  	  "dsm": [0.37, 0.37, 0.31, 0.37, 0.34, 0.37, 0.35, 0.35, 0.34]}


#!/bin/python
with open('input') as f:
    grid = f.read().split('\n')

x = 0
c = 0

for line in grid[:-1]:  # last line empty
    if line[x] == '#':
        c += 1
    x += 3
    x %= len(line)

print(c)


"""
Misc module
***********
"""
import os
import sys
import time
import warnings
import inspect
import numpy as np
from matplotlib import pyplot as plt
import matplotlib.backends.backend_pdf
from pathos.multiprocessing import cpu_count
from .nested_pool import NestedPool

__all__ = ['NestedPool', 'cpu_system', 'save_show', 'multi_eval']

def cpu_system():
    """Determine the number of CPU of system."""
    try:
        n_cpu_system = cpu_count()
    except NotImplementedError:
        n_cpu_system = os.sysconf('SC_NPROCESSORS_ONLN')
    return 1 if n_cpu_system == 0 or n_cpu_system is None else n_cpu_system

class ProgressBar:
    """Print progress bar in console."""

    def __init__(self, total):
        """Create a bar.

        :param int total: number of iterations
        """
        self.total = total
        self.calls = 1
        self.progress = 0.

        sys.stdout.write("Progress | " +
                         " " * 50 +
                         " |" + "0.0% ")

        self.init_time = time.time()

    def __call__(self):
        """Update bar."""
        self.progress = (self.calls) / float(self.total) * 100

        eta, vel = self.compute_eta()
        self.show_progress(eta, vel)

        self.calls += 1

    def compute_eta(self):
        """Compute ETA.

        Compare current time with init_time.

        :return: eta, vel
        :rtype: str
        """
        end_time = time.time()
        iter_time = (end_time - self.init_time) / self.calls

        eta = (self.total - self.calls) * iter_time
        eta = time.strftime("%H:%M:%S", time.gmtime(eta))

        vel = str(1. / iter_time)

        return eta, vel

    def show_progress(self, eta=None, vel=None):
        """Print bar and ETA if relevant.

        :param str eta: ETA in H:M:S
        :param str vel: iteration/second
        """
        p_bar = int(np.floor(self.progress / 2))
        sys.stdout.write("\rProgress | " +
                         "-" * (p_bar - 1) + "~" +
                         " " * (50 - p_bar - 1) +
                         " |" + str(self.progress) + "% ")

        if self.progress == 100:
            sys.stdout.write('\n')
            del self
        elif eta and vel:
            sys.stdout.write("| ETA: " + eta + " (at " + vel + " it/s) ")

        sys.stdout.flush()

def save_show(fname, figures, **kwargs):
    """Either show or save the figure[s].

    If :attr:`fname` is `None` the figure will show.

    :param str fname: whether to export to filename or display the figures.
    :param list(Matplotlib figure instance) figures: Figures to handle.
    """
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        for fig in figures:
            try:
                fig.tight_layout()
            except ValueError:
                pass

    if fname is not None:
        pdf = matplotlib.backends.backend_pdf.PdfPages(fname)
        for fig in figures:
            pdf.savefig(fig, transparent=True, bbox_inches='tight', **kwargs)
        pdf.close()
    else:
        plt.show()
    plt.close('all')

def multi_eval(fun):
    """Detect space or unique point.

    Return the evaluation with shape (n_samples, n_features).
    """
    def wrapper_fun(self, x_n, *args, **kwargs):
        """Get evaluation from space or point.

        If the function is a Kriging instance, get and returns the variance.

        :return: function evaluation(s) [sigma(s)]
        :rtype: np.array([n_eval], n_feature)
        """
        x_n = np.atleast_2d(x_n)
        shape_eval = (len(x_n), -1)

        full = kwargs['full'] if 'full' in kwargs else False

        feval = [fun(self, x_i, *args, **kwargs) for x_i in x_n]

        if any(method in inspect.getmodule(fun).__name__
               for method in ['kriging', 'multifidelity']) or full:
            feval, sigma = zip(*feval)
            feval = np.array(feval).reshape(shape_eval)
            sigma = np.array(sigma).reshape(shape_eval)
            return feval, sigma
        feval = np.array(feval).reshape(shape_eval)
        return feval
    return wrapper_fun


matrix = [[x for x in input().split()] for _ in range(5)]
my_x, my_y = 0, 0
targets_count = 0
shotted_targets = []
for row in range(5):
    for col in range(len(matrix[row])):
        if matrix[row][col] == 'A':
            my_x, my_y = row, col
        elif matrix[row][col] == 'x':
            targets_count += 1
number_of_commands = int(input())
for _ in range(number_of_commands):
    command_arg = input().split()
    command, side = command_arg[0], command_arg[1]
    if command_arg[0] == 'move':
        steps = int(command_arg[2])
        if steps < 1:
            continue
        else:
            next_x, next_y = my_x, my_y
            if side == 'right':
                next_y += steps
            elif side == 'left':
                next_y -= steps
            elif side == 'up':
                next_x -= steps
            elif side == 'down':
                next_x += steps
            if 0 <= next_x < 5 and 0 <= next_y < 5 and (not matrix[next_x][next_y] == 'x'):
                my_x, my_y = next_x, next_y
    else:
        is_target = False
        target_x, target_y = my_x, my_y
        if side == 'right':
            for col in range(my_y, 5):
                if matrix[my_x][col] == 'x':
                    target_y = col
                    is_target = True
                    break
        elif side == 'left':
            for col in range(my_y, -1, -1):
                if matrix[my_x][col] == 'x':
                    target_y = col
                    is_target = True
                    break
        elif side == 'up':
            for row in range(my_x, -1, -1):
                if matrix[row][my_y] == 'x':
                    target_x = row
                    is_target = True
                    break
        elif side == 'down':
            for row in range(my_x, 5):
                if matrix[row][my_y] == 'x':
                    target_x = row
                    is_target = True
                    break
        if is_target:
            targets_count -= 1
            shotted_targets.append([target_x, target_y])
            matrix[target_x][target_y] = '.'
        if targets_count < 1:
            break
if targets_count > 0:
    print(f'Training not completed! {targets_count} targets left.')
else:
    print(f'Training completed! All {len(shotted_targets)} targets hit.')
[print(target) for target in shotted_targets]

Python_Advanced/Multidimensional Lists - Exercise part 2/06. Range Day.py