import torch
import torchvision
import gym

import random
import torch.nn as nn
import torch
from torch.autograd import Variable
import torch.autograd as autograd
import torch.nn.functional as F
import gym
import random
import heapq

from gym.envs.registration import register

register(
    id='FrozenLakeNotSlippery-v0',
    entry_point='gym.envs.toy_text:FrozenLakeEnv',
    kwargs={'map_name': '4x4', 'is_slippery': False},
    max_episode_steps=100,
    reward_threshold=0.78,  # optimum = .8196
)

# env = gym.make('FrozenLake8x8-v0')
# env = gym.make('FrozenLake-v0')
env = gym.make('FrozenLakeNotSlippery-v0')
env.render()

use_cuda = torch.cuda.is_available()
FloatTensor = torch.cuda.FloatTensor if use_cuda else torch.FloatTensor
LongTensor = torch.cuda.LongTensor if use_cuda else torch.LongTensor
ByteTensor = torch.cuda.ByteTensor if use_cuda else torch.ByteTensor
Tensor = FloatTensor

class value_net(nn.Module):
    def __init__(self):
        super(value_net, self).__init__()
        bias_on = True
        self.linear1 = nn.Linear(16, 20, bias=bias_on)
        self.linear2 = nn.Linear(20, 40, bias=bias_on)
        self.linear3 = nn.Linear(40, 1, bias=bias_on)
        # self.dropout = nn.Dropout(p=0.5)

    def forward(self, x):
        # --- 0000 ---- 0000 >>>  z-score normalization
        x = self.linear1(x)

        x_avg = torch.sum(x) / 20
        x_minus_x_avg = x - x_avg
        x_std = torch.sum(torch.pow(x_minus_x_avg, 2)) / 20
        epsilon = 0.0000001
        x_norm = (x_minus_x_avg) / (torch.sqrt(x_std) + epsilon)
        x = torch.tanh(x_norm)

        x = self.linear2(x)

        # x_avg = torch.sum(x) / 40
        # x_minus_x_avg = x - x_avg
        # x_std = torch.sum(torch.pow(x_minus_x_avg, 2)) / 40
        # x_norm = (x_minus_x_avg) / (torch.sqrt(x_std) + epsilon)
        x = torch.tanh(x)
        x = self.linear3(x)

        return x.view(-1, 1)

class policy_net(nn.Module):
    def __init__(self):
        super(policy_net, self).__init__()
        bias_on = True
        self.linear1 = nn.Linear(16, 20, bias=bias_on)
        self.linear2 = nn.Linear(20, 40, bias=bias_on)
        self.linear3 = nn.Linear(40, 4, bias=bias_on)
        # self.dropout = nn.Dropout(p=0.5)

    def forward(self, x):
        # --- 0000 ---- 0000 >>>  z-score normalization
        x = self.linear1(x)

        x_avg = torch.sum(x) / 20
        x_minus_x_avg = x - x_avg
        x_std = torch.sum(torch.pow(x_minus_x_avg, 2)) / 20
        epsilon = 0.0000001
        x_norm = (x_minus_x_avg) / (torch.sqrt(x_std) + epsilon)
        x = torch.tanh(x_norm)

        x = self.linear2(x)

        # x_avg = torch.sum(x) / 40
        # x_minus_x_avg = x - x_avg
        # x_std = torch.sum(torch.pow(x_minus_x_avg, 2)) / 40
        # x_norm = (x_minus_x_avg) / (torch.sqrt(x_std) + epsilon)
        x = torch.tanh(x)
        x = self.linear3(x)
        return x.view(-1, 4)

from collections import namedtuple

Transition = namedtuple('Transition',
                        ('state', 'action', 'log_prob', 'action_prob', 'log_action_prob', 'next_state', 'reward',
                         'entropy_impact', 'done'))

class ReplayMemory(object):

    def __init__(self, capacity):
        self.capacity = capacity
        self.memory = []
        self.position = 0

    def push(self, *args):
        """Saves a transition."""
        if len(self.memory) < self.capacity:
            self.memory.append(None)
        self.memory[self.position] = Transition(*args)
        self.position = (self.position + 1) % self.capacity

    def sample(self, batch_size):
        return random.sample(self.memory, batch_size)

    def __len__(self):
        return len(self.memory)

class ReplayMemoryNoReplacement(object):

    def __init__(self, capacity):
        self.h = []

    def push(self, *args):
        random_index = random.random()
        heapq.heappush(self.h, (random_index, Transition(*args)))

    def sample(self, batch_size):
        result = []
        for i in range(batch_size):
            result.append(heapq.heappop(self.h)[1])

        return result

    def __len__(self):
        return len(self.h)

class ReplayMemoryNew(object):
    def __init__(self, capacity):
        self.h = []
        self.capacity = capacity

    def push(self, *args):
        tran = Transition(*args)
        self.push_transition(tran)

    def push_transition(self, tran):
        if self.capacity <= len(self.h):
            heapq.heappop(self.h)
        random_index = random.random()
        heapq.heappush(self.h, (random_index, tran))

    def sample(self, batch_size):
        result = []
        for i in range(batch_size):
            el = heapq.heappop(self.h)[1]
            result.append(el)
            heapq.heappush(self.h, (random.random(), el))
        return result

    def __len__(self):
        return len(self.h)

def print_v_table():
    for i in range(16):
        # st = np.array(get_state_repr(i))
        # st = np.expand_dims(st, axis=0)
        st = get_state_repr(i)
        v_net.eval()
        action_probs = v_net(FloatTensor(st))
        # action_probs = F.softmax(action_probs, dim=1)
        outp = " state (" + str(i) + ") "
        n = 0
        for tensr in action_probs:
            for cell in tensr:
                outp = outp + " A[" + str(n) + "]:(" + str(cell.item()) + ")"
                n += 1
        print(outp)

def print_pi_table():
    for i in range(16):
        # st = np.array(get_state_repr(i))
        # st = np.expand_dims(st, axis=0)
        st = get_state_repr(i)
        pi_net.eval()
        action_probs = pi_net(FloatTensor(st))
        action_probs = F.softmax(action_probs, dim=1)
        outp = " state (" + str(i) + ") "
        n = 0
        for tensr in action_probs:
            for cell in tensr:
                outp = outp + " A[" + str(n) + "]:(" + str(cell.item()) + ")"
                n += 1
        print(outp)

# def get_state_repr(state_idx):
#     return state_idx * 13

import gym
import numpy as np
import torch.optim as optim
from torch.distributions import Categorical
import random

random.seed(1999)
import math
import torch
from torch.optim.lr_scheduler import StepLR

# custom weights initialization
def weights_init(m):
    classname = m.__class__.__name__
    # print classname
    # print q_net
    if classname.find('Linear') != -1:
        m.weight.data.normal_(0.0, 0.02)
        if not m.bias is None:
            m.bias.data.normal_(0.0, 0.02)

def get_state_repr(state_idx):
    state = np.zeros(16)
    state[state_idx] = 1
    return state

def get_index_repr(state):
    return np.argwhere(state==1).item()

# if gpu is to be used
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

BATCH_SIZE = 300
GAMMA = 0.99
TARGET_UPDATE = 1000
PRINT_OUT_TIMES = 1000
ENTROPY_REDUCTION_STEPS = 100000.0
NUM_EPISODES = 10000000
# NUM_STEPS_VALUE_FUNCTION_LEARNS = NUM_EPISODES
#NUM_STEPS_VALUE_FUNCTION_LEARNS = (ENTROPY_REDUCTION_STEPS * 1)
NUM_STEPS_VALUE_FUNCTION_LEARNS = 1

v_net = value_net()
v_net.apply(weights_init)
v_net.to(device)
target_v_net = value_net()
target_v_net.load_state_dict(v_net.state_dict())
target_v_net.to(device)
pi_net = policy_net()
pi_net.apply(weights_init).to(device)

# prepare for optimizer, merge both networks parameters

# parameters = set()
# for net_ in [v_net, pi_net]:
#     parameters |= set(net_.parameters())

# optimizer = optim.RMSprop(online_net.parameters(), lr=0.001)

# optimizer = optim.Adam(parameters, lr=0.0001)

v_optimizer = optim.Adam(v_net.parameters(), lr=0.0001)
pi_optimizer = optim.Adam(pi_net.parameters(), lr=0.00001)

# scheduler = StepLR(v_optimizer, step_size=10000, gamma=0.5)

MEMORY_SIZE = 2000
# memory = ReplayMemoryNoReplacement(MEMORY_SIZE)
memory = ReplayMemoryNew(MEMORY_SIZE)
# memory = ReplayMemory(MEMORY_SIZE)

value_loss_cum = []

def optimize(k):
    if len(memory) < BATCH_SIZE:
        return

    transitions = memory.sample(BATCH_SIZE)
    # Transpose the batch (see http://stackoverflow.com/a/19343/3343043 for
    # detailed explanation).
    batch = Transition(*zip(*transitions))

    # Compute a mask of non-final states and concatenate the batch elements
    # final_mask = torch.tensor(tuple(map(lambda d: d is True,batch.done)), device=device, dtype=torch.bool).unsqueeze(1)
    # final_mask_list = [d for d in batch.done if d is True]
    final_mask = torch.tensor(tuple(map(lambda d: get_index_repr(d) in [5,7,11,12], batch.next_state)), device=device, dtype=torch.bool).unsqueeze(1)
    final_mask_list = [d for d in batch.done if get_index_repr(d) in [5,7,11,12]]
    # Compute states that are final.
    #     next_state_final_mask = torch.tensor(tuple(map(lambda d: (d) in [5,7,11,12,15],
    #                                           batch.next_state)), device=device, dtype=torch.uint8).unsqueeze(1)
    #     next_state_finak_list = [d for d in batch.next_state if d in [5,7,11,12,15] ]

    # Unpack the parameters from the memory

    state_batch = FloatTensor(batch.state)
    state_batch = state_batch.view(BATCH_SIZE, 16)
    next_state_batch = FloatTensor(batch.next_state)
    next_state_batch = next_state_batch.view(BATCH_SIZE, 16)
    action_batch = LongTensor(batch.action).view(BATCH_SIZE, 1)
    reward_batch = Tensor(batch.reward).view(BATCH_SIZE, 1)
    entropy_impact_batch = FloatTensor(batch.entropy_impact).view(BATCH_SIZE, 1)
    # log_prob_batch = torch.cat(batch.log_prob).view(BATCH_SIZE, 1)
    # action_probs_batch = torch.cat(batch.action_prob).view(BATCH_SIZE,4)
    # log_action_probs_batch = torch.cat(batch.log_action_prob).view(BATCH_SIZE,4)

    # FIRST , calculate V(next_state)and backpropagate MSE on V

    target_v_net.eval()
    v_next = target_v_net(next_state_batch).detach()
    # v_next[next_state_final_mask] = torch.zeros(len(next_state_finak_list), device=device).view(len(next_state_finak_list))
    v_next[final_mask] = torch.zeros(len(final_mask_list), device=device).view(len(final_mask_list))

    ##HACK FIXING expected value
    #     v_current_fixed = [get_expected_value_fixed(_st) for _st in batch.state]
    #     v_current_fixed = FloatTensor(v_current_fixed).view(BATCH_SIZE,1)
    ##HACK FIXING expected value

    ##HACK FIXING current value
    #     v_next_fixed = [get_expected_value_fixed(_st) for _st in batch.next_state]
    #     v_next_fixed = FloatTensor(v_next_fixed).view(BATCH_SIZE,1)
    # v_next = v_next_fixed
    ##HACK FIXING current value

    expected_value = reward_batch + v_next * GAMMA

    ##HACK FIXING expected value
    # expected_value = expected_value_fixed
    ##HACK FIXING expected value

    # calculate V(current_state)
    #if k <= NUM_STEPS_VALUE_FUNCTION_LEARNS:
    #    v_net.train()
    #else:
    #    v_net.eval()
    v_net.train()

    v_current = v_net(state_batch)

    # backpropagate:
    value_loss = torch.sum((expected_value - v_current) ** 2)

    v_optimizer.zero_grad()
    value_loss.backward()  # keep graph for policy net optimizer
    v_optimizer.step()

    # if k <= NUM_STEPS_VALUE_FUNCTION_LEARNS:
    #     v_optimizer.zero_grad()
    #     # value_loss.backward(retain_graph=True) # keep graph for policy net optimizer
    #     value_loss.backward()  # keep graph for policy net optimizer
    #     v_optimizer.step()
        # scheduler.step()

    value_loss_cum.append(value_loss.item())

    v_current = v_current.detach()

    ##HACK FIXING expected value
    # v_current = v_current_fixed
    ##HACK FIXING expected value

    # SECOND, calculate gradient loss:
    # H(X) = P(X) log ( P(X) )

    # calculate the action probability
    actions_distr = pi_net(state_batch)
    actions_prob_batch = torch.softmax(actions_distr, dim=1)
    log_actions_prob_batch = torch.log_softmax(actions_distr, dim=1)

    action_batch = action_batch
    action_mask = FloatTensor(BATCH_SIZE, 4).zero_()
    action_mask.scatter_(1, action_batch, 1)  # This will have shape (BATCH_SIZE, 4), and its contents will be
    # like : [[0,0,1,0],[1,0,0,0],...]
    # log_prob_batch = log_actions_prob_batch.gather(1,action_batch)
    log_prob_batch = torch.sum(log_actions_prob_batch * action_mask, dim=1).view(BATCH_SIZE,
                                                                                1)  # sum up across rows (ending tensor is shape (BATCH_SIZE, 1))

    entropy = entropy_impact_batch * torch.sum(actions_prob_batch * log_actions_prob_batch)

    #policy_loss = torch.sum(-log_prob_batch * (expected_value - v_current) + entropy)
    policy_loss = torch.sum(-log_prob_batch * (expected_value - v_current))

    pi_optimizer.zero_grad()
    policy_loss.backward()
    pi_optimizer.step()

    return policy_loss.item(), value_loss.item()

score = []
times_trained = 0
times_reach_goal = 0
steps_done = 0

policy_loss_avg = [1.0]
v_loss_avg = [1.0]

TARGET_UPDATE = 1000

for k in range(NUM_EPISODES):
    done = False
    observation = env.reset()
    # observation, reward, done, info = env.step(env.action_space.sample()) # take a random action
    reward = 0
    episode_step = 0
    # print("b")
    I = 1.0
    # entropy_impact = (ENTROPY_REDUCTION_STEPS - k) / ENTROPY_REDUCTION_STEPS
    if k == 0:
        entropy_impact = 1.0
    else:
        entropy_impact = min(1, (1 / (k * 0.005)))

    if k > ENTROPY_REDUCTION_STEPS:
        entropy_impact = 0.0

    # test entropy always 0
    # entropy_impact = 0.0

    # entropy_impact = 0.0
    # if entropy_impact < 0.0:
    #    entropy_impact = 0
    while not done:
        # print("c")
        steps_done += 1

        # Get action from pi
        # np_observation = np.array(get_state_repr(observation))
        # np_observation = np.expand_dims(np_observation, axis=0)
        np_observation = get_state_repr(observation)
        # print(np_observation)
        observation_tensor = FloatTensor(np_observation)

        # action distribution
        pi_net.eval()
        action_distr = pi_net(observation_tensor)
        action_probs = torch.softmax(action_distr, dim=1)
        log_action_probs = 0
        # log_action_probs = F.log_softmax(action_distr, dim=1)
        # Decide on an action based on the distribution
        m = Categorical(action_probs)
        action = m.sample()

        log_prob = m.log_prob(action).unsqueeze(1)

        # break
        # Execute action in environment.
        old_state = observation

        observation, reward, done, info = env.step(action.item())
        new_state = observation

        if k % 5000 == 0:
            # print("old_state != new_state")
            # print(old_state != new_state)
            # print("oldstate " + str(old_state) + " newstate " + str(new_state))
            print("action_dist ")
            print(action_probs)
            print("On state=" + str(old_state) + ", selected action=" + str(action.item()))
            print("new state=" + str(new_state) + ", done=" + str(done) + \
                  ". Reward: " + str(reward))

        # Perform one step of the optimization
        #         policy_loss, value_loss = optimize_model(I, \
        #                                                  old_state, \
        #                                                  log_prob, \
        #                                                  log_actions_probs, \
        #                                                  action_probs, \
        #                                                  reward, \
        #                                                  new_state, \
        #                                                  entropy_impact, \
        #                                                  done)

        #         I = I * GAMMA
        # if (not done) or (done and new_state in [5,7,11,12,15]):
        memory.push(get_state_repr(old_state), action.item(), log_prob, action_probs, log_action_probs,
                    get_state_repr(new_state), reward, entropy_impact, done)

        if len(memory) >= MEMORY_SIZE:
            policy_loss, value_loss = optimize(k)
            if len(policy_loss_avg) < PRINT_OUT_TIMES:
                policy_loss_avg.append(policy_loss)
                v_loss_avg.append(value_loss)
            else:
                policy_loss_avg[episode_step % PRINT_OUT_TIMES] = policy_loss
                v_loss_avg[episode_step % PRINT_OUT_TIMES] = value_loss

        times_trained = times_trained + 1

        episode_step += 1
        # env.render()

    if k % PRINT_OUT_TIMES == 0:
        print_pi_table()
        print_v_table()

    if len(score) < 100:
        score.append(reward)
    else:
        score[k % 100] = reward

    if k % TARGET_UPDATE == 0:
        target_v_net.load_state_dict(v_net.state_dict())

    if k % PRINT_OUT_TIMES == 0:
        print("Episode {} finished after {} . Running score: {}. Policy_loss: {}, Value_loss: {}. Times trained: \
              {}. Times reached goal: {}. \
              Steps done: {}.".format(k, episode_step, np.mean(score), np.mean(policy_loss_avg), np.mean(v_loss_avg), times_trained,times_reach_goal, steps_done))
        # print("policy_loss_avg")
        # print(policy_loss_avg)
        # print("value_loss_avg")
        # print(v_loss_avg)
        #         print("times_reach_goal")
        #         print(times_reach_goal)
        times_trained = 0
        times_reach_goal = 0
        # print("Game finished. " + "-" * 5)
        # print(len(episode_series))
    #         for param in net.parameters():
    #             print(param.data)

    if reward > 0.0:
        times_reach_goal = times_reach_goal + 1


import os
import json
import numpy as np
from ortools.sat.python import cp_model

def solve(all_block, wafer_width, wafer_height):
    ### wafer sampling
    # Number of blocks
    n = len(all_block)

    # wafer Variables
    all_wafer_x_st, all_wafer_y_st, all_wafer_x_ed, all_wafer_y_ed, sampled = [], [], [], [], []
    for i, block in enumerate(all_block):
        if block['x'] == None:
            all_wafer_x_st.append(model.NewIntVar(0, wafer_width - block['w'], f"wafer_x{i}"))
        else:
            all_wafer_x_st.append(model.NewIntVar(block['x'], block['x'], f"wafer_x{i}"))
        all_wafer_x_ed.append(model.NewIntVar(-wafer_width, wafer_width, f"wafer_x_end{i}"))

        if block['y'] == None:
            all_wafer_y_st.append(model.NewIntVar(0, wafer_height - block['h'], f"wafer_y{i}"))
        else:
            all_wafer_y_st.append(model.NewIntVar(block['y'], block['y'], f"wafer_y{i}"))
        all_wafer_y_ed.append(model.NewIntVar(-wafer_height, wafer_height, f"wafer_y_end{i}"))

        if block['x'] == None and block['y'] == None:
            sampled.append(model.NewBoolVar(f"sampled_{i}"))
        else:
            sampled.append(model.NewConstant(1))

    # wafer width & height constraints
    for i, block in enumerate(all_block):
        model.Add(all_wafer_x_ed[i] == all_wafer_x_st[i] + block['w']).OnlyEnforceIf(sampled[i])
        model.Add(all_wafer_y_ed[i] == all_wafer_y_st[i] + block['h']).OnlyEnforceIf(sampled[i])
        model.Add(all_wafer_x_ed[i] <= wafer_width).OnlyEnforceIf(sampled[i])
        model.Add(all_wafer_y_ed[i] <= wafer_height).OnlyEnforceIf(sampled[i])

    # wafer Non-overlapping constraints
    for i in range(n):
        for j in range(i + 1, n):
            wafer_bx_ij = model.NewBoolVar(f"wafer_bx_{i}_{j}")
            wafer_bx_ji = model.NewBoolVar(f"wafer_bx_{j}_{i}")
            wafer_by_ij = model.NewBoolVar(f"wafer_by_{i}_{j}")
            wafer_by_ji = model.NewBoolVar(f"wafer_by_{j}_{i}")

            model.Add(all_wafer_x_ed[i] <= all_wafer_x_st[j] + wafer_width * wafer_bx_ij)
            model.Add(all_wafer_x_ed[j] <= all_wafer_x_st[i] + wafer_width * wafer_bx_ji)
            model.Add(all_wafer_y_ed[i] <= all_wafer_y_st[j] + wafer_height * wafer_by_ij)
            model.Add(all_wafer_y_ed[j] <= all_wafer_y_st[i] + wafer_height * wafer_by_ji)

            model.AddBoolOr([wafer_bx_ij.Not(), wafer_bx_ji.Not(),
                            wafer_by_ij.Not(), wafer_by_ji.Not()])

    ### place to sample panel
    panel_width = 6
    panel_height = 6
    # panel Variables
    all_panel_x_st, all_panel_y_st, all_panel_x_ed, all_panel_y_ed, on_panel = [], [], [], [], []
    for i, block in enumerate(all_block):
        all_panel_x_st.append(model.NewIntVar(0, panel_width - block['w'], f"panel_x{i}"))
        all_panel_x_ed.append(model.NewIntVar(-panel_width, panel_width, f"panel_x_end{i}"))
        all_panel_y_st.append(model.NewIntVar(0, panel_height - block['h'], f"panel_y{i}"))
        all_panel_y_ed.append(model.NewIntVar(-panel_height, panel_height, f"panel_y_end{i}"))
        # on_panel.append(model.NewBoolVar(f"on_panel_{i}"))

    # panel width & height constraints
    for i, block in enumerate(all_block):
        model.Add(all_panel_x_ed[i] == all_panel_x_st[i] + block['w']).OnlyEnforceIf(sampled[i])
        model.Add(all_panel_y_ed[i] == all_panel_y_st[i] + block['h']).OnlyEnforceIf(sampled[i])
        model.Add(all_panel_x_ed[i] <= panel_width).OnlyEnforceIf(sampled[i])
        model.Add(all_panel_y_ed[i] <= panel_height).OnlyEnforceIf(sampled[i])

    # panel Non-overlapping constraints
    for i in range(n):
        for j in range(i + 1, n):
            panel_bx_ij = model.NewBoolVar(f"panel_bx_{i}_{j}")
            panel_bx_ji = model.NewBoolVar(f"panel_bx_{j}_{i}")
            panel_by_ij = model.NewBoolVar(f"panel_by_{i}_{j}")
            panel_by_ji = model.NewBoolVar(f"panel_by_{j}_{i}")

            model.Add(all_panel_x_ed[i] <= all_panel_x_st[j] + panel_width * panel_bx_ij)
            model.Add(all_panel_x_ed[j] <= all_panel_x_st[i] + panel_width * panel_bx_ji)
            model.Add(all_panel_y_ed[i] <= all_panel_y_st[j] + panel_height * panel_by_ij)
            model.Add(all_panel_y_ed[j] <= all_panel_y_st[i] + panel_height * panel_by_ji)

            model.AddBoolOr([panel_bx_ij.Not(), panel_bx_ji.Not(),
                            panel_by_ij.Not(), panel_by_ji.Not()])

    # panel must be filled by blocks
    model.Add(sum(sampled[i] * block['w'] * block['h'] for i, block in enumerate(all_block)) == panel_width * panel_height)

    # Objective function
    wafer_area = wafer_width * wafer_height
    blocks_area = model.NewIntVar(0, wafer_area, "blocks_area")
    model.Add(
        blocks_area == sum(
            sampled[i] *
            block['w'] *
            block['h'] for i, block in enumerate(all_block)))
    num_blocks_sampled = model.NewIntVar(0, n, "num_blocks_sampled")
    model.Add(num_blocks_sampled == sum(sampled[i] for i, block in enumerate(all_block)))

    scale = 1000000
    # wafer_coverage
    wafer_coverage = model.NewIntVar(0, 1 * scale, "wafer_coverage")
    model.AddDivisionEquality(wafer_coverage, blocks_area * scale, wafer_area)

    # block utilization
    block_utilization = model.NewIntVar(0, 1 * scale, "block_utilization")
    model.AddDivisionEquality(
        block_utilization,
        num_blocks_sampled * scale,
        n)

    # model.Maximize(wafer_coverage * (1 / scale) -
    #                block_utilization * (1 / scale))
    # model.Maximize(wafer_coverage * (1 / scale))
    model.Maximize(-block_utilization * (1 / scale))

    # Solve the model
    solver = cp_model.CpSolver()
    status = solver.Solve(model)

    # Print
    if status == cp_model.OPTIMAL:
        wafer_positions = [(solver.Value(all_wafer_x_st[i]), solver.Value(all_wafer_y_st[i]))
                     for i in range(n)]
        panel_positions = [(solver.Value(all_panel_x_st[i]), solver.Value(all_panel_y_st[i]))
                     for i in range(n)]
        print(f"wafer_positions: {wafer_positions}\n"
              f"panel_positions: {panel_positions}\n"
              f"num_blocks_sampled: {solver.Value(num_blocks_sampled)}\n"
              f"sampled: {[solver.Value(sampled[i]) for i in range(n)]}\n"
              f"wafer_coverage: {solver.Value(wafer_coverage) / scale}\n"
              f"block_utilization: {solver.Value(block_utilization) / scale}\n"
              f"objective: {solver.ObjectiveValue()}")
        all_block_sampled = []
        for i, block in enumerate(all_block):
            if not solver.Value(sampled[i]):
                continue
            block['x'] = solver.Value(all_wafer_x_st[i])
            block['y'] = solver.Value(all_wafer_y_st[i])
            all_block_sampled.append(block)
        result = {}
        result['width'] = wafer_width
        result['height'] = wafer_height
        result["block"] = all_block_sampled
        with open(os.path.join(result_path, file_name), 'w') as fp:
            json.dump(result, fp, indent=4)
    elif cp_model.INFEASIBLE:
        print("INFEASIBLE")

if __name__ == "__main__":
    data_path = "block_data"
    result_path = "result"
    # file_name = "0004.json"
    file_name = "0005.json"
    # file_name = "0001_d=10.json"
    # Create the model
    model = cp_model.CpModel()
    with open(os.path.join(data_path, file_name), 'r') as fp:
        data = json.load(fp)
    wafer_width = data["width"]
    wafer_height = data["height"]
    all_block = data["block"]
    solve(all_block, wafer_width, wafer_height)


from QAgent import QAgent
import random
import tensorflow as tf
import numpy as np

class NStepQAgent(QAgent):
    """
    Asynchronous Methods for Deep Reinforcement Learning

    Args:
        _model (function): necessary,
            return: 1. q func output op, output's dim should be equal with num of actions
                    2. vars list
        _env (Env): necessary, env to learn, should be rewritten from Env
        _is_train (bool): default True
        _optimizer (chainer.optimizers): not necessary, if not then func won't be updated
        _replay (Replay): necessary for training
        _gpu (bool): whether to use gpu
        _gamma (float): reward decay
        _batch_size (int): how much tuples to pull from replay
        _step_len (int): how much step to do in agent.step()
        _epsilon (float): init epsilon, p for choosing randomly
        _epsilon_decay (float): epsilon *= epsilon_decay
        _epsilon_underline (float): epsilon = max(epsilon_underline, epsilon)
        _grad_clip (float): clip grad, 0 is no clip
    """

    def __init__(self, _model, _env, _is_train=True,
                 _optimizer=None, _global_step=None, _replay=None,
                 _gpu=False, _gamma=0.99, _batch_size=32, _step_len=5,
                 _epsilon=0.5, _epsilon_decay=0.995, _epsilon_underline=0.01,
                 _err_clip=None, _grad_clip=None, _epoch_show_log=1e3):

        super(NStepQAgent, self).__init__(
            _model, _env, _is_train,
            _optimizer, _global_step, _replay,
            _gpu, _gamma, _batch_size,
            _epsilon, _epsilon_decay, _epsilon_underline,
            _err_clip, _grad_clip, _epoch_show_log)

        self.config.step_len = _step_len

    def step(self):
        """
        Returns:
            still in game or not
        """
        return super(NStepQAgent, self).nstep(self.q_func)

    def grad(self, _cur_x, _next_output, _next_action, _batch_tuples, _weights):
        with tf.device(self.config.device):
            # get action data (one hot)
            action_data = self.getActionData(
                self.q_func.get_shape().as_list()[1], _batch_tuples)
            # get target data
            target_data = self.getNStepQTargetData(
                _next_output, _next_action, _batch_tuples)
            # get weight data
            weight_data = self.getWeightData(_weights, _batch_tuples)

            # get err list [0] and grads [1:]
            ret = self.sess.run(
                [self.err_list_op] + self.grads_op,
                feed_dict={
                    self.x_place: _cur_x,
                    self.action_place: action_data,
                    self.target_place: target_data,
                    self.weight_place: weight_data,
                }
            )
            # set grads data
            self.grads_data = ret[1:]
        # return err_list
        return ret[0]


from collections import deque

class Cell:
    def __init__(self, x: int, y: int):
        self.x = x
        self.y = y

class Node:
    def __init__(self, pt: Cell, dist: int):
        self.pt = pt
        self.dist = dist

def is_valid(r, c, tr, tc):
    return (r >= 0) and (r < tr) and (c >= 0) and (c < tc)

def shortest_path(maze, src, dest, r, c):
    if maze[src.x][src.y] != 0 or maze[dest.x][dest.y] != 0:
        return -1

    visited = [[False for i in range(c)] for j in range(r)]
    visited[src.x][src.y] = True
    q = deque()
    s = Node(src, 0)
    q.append(s)

    while q:
        current = q.popleft()
        pt = current.pt
        if pt.x == dest.x and pt.y == dest.y:
            return current.dist

        for i in [[1, 0], [-1, 0], [0, -1], [0, 1]]:
            row, col = pt.x + i[0], pt.y + i[1]

            if is_valid(row, col, r, c) and maze[row][col] == 0 and not visited[row][col]:
                visited[row][col] = True
                neighbor = Node(Cell(row, col), current.dist + 1)
                q.append(neighbor)

    return -1

def main():
    maze = [[0, 1, 1, 0], [0, 0, 0, 1], [1, 1, 0, 0], [1, 1, 1, 0]]
    source = Cell(0, 0)
    dest = Cell(3, 3)

    dist = shortest_path(maze, source, dest, len(maze), len(maze[0]))

    if dist != -1:
        print("Shortest Path:", dist)
    else:
        print("No path exists")

main()


from flask import Flask
from flask import request, jsonify
import json, os, util, pickle
app = Flask(__name__)
SIMULATION_RESULT_PATH = './sim_result'

from flask_cors import CORS
CORS(app)

def load(path):
    with open(path, 'rb') as f:
        obj = pickle.load(f)
    return obj

@app.route("/")
def hello_world():
    return "
InterSim Beta Server is running.
"

@app.route('/vis', methods=['GET', 'POST'])
def visualization_get():
    sim_name = request.args.get('sim')
    scene_id = request.args.get('sceneid')
    file_id = request.args.get('fileid')
    if request.method == 'GET':
        with open(f"sim_result/{sim_name}/json/{file_id}.json", "r") as json_file:
            my_dict = json.load(json_file)
            keys = list(my_dict.keys())
            my_dict['selected_scene_index'] = keys.index(scene_id)
        return jsonify(my_dict)

@app.route('/list_scenarios')
def get_simulations():
    return summary_simulations()

@app.route('/list_simulation_selection')
def get_simulation_selection():
    dataset = request.args.get('dataset')
    return list_simulation_selection(dataset=dataset)

@app.route('/list_senarios')
def get_scenarios_list():
    simulation_name = request.args.get('simulation')
    return list_scenarios(simulation_name)

def check_path_valid(path):
    if not os.path.isdir(path):
        return False
    if not os.path.exists(os.path.join(path, 'sim.info')):
        return False
    return True

def summary_simulations(path=SIMULATION_RESULT_PATH):
    html_str = ""
    # loop all simulations and load their info and add to the html table
    for each_path in os.listdir(path):
        if not check_path_valid(os.path.join(path, each_path)):
            continue
        sim_info = load(os.path.join(path, each_path, 'sim.info'))
        # dataset_with_map = '-' + sim_info['map_info'] if 'map_info' in sim_info and sim_info['map_info'] is not None else ''
        # dataset_with_map = sim_info['dataset'] + dataset_with_map
        dataset_with_map = sim_info['dataset']
        html_str += f"
{sim_info['name']}	" \
                    f"{sim_info['task']}	" \
                    f"{dataset_with_map}	" \
                    f"{sim_info['planner']}	" \
                    f"{sim_info['predictor']}	" \
                    f"{sim_info['status']}	" \
                    f"{sim_info['starting_time']}	"
        html_str += f"{sim_info['ending_time']}	" if sim_info['ending_time'] is not None else "-	"
        # add action drop
        html_str += f'''

                Detail

          '''
        html_str += "
"
    return html_str

def list_simulation_selection(dataset=None, path=SIMULATION_RESULT_PATH):
    if dataset is None:
        return
    html_str = ""
    for each_path in os.listdir(path):
        if not check_path_valid(os.path.join(path, each_path)):
            continue
        if dataset not in each_path:
            continue
        html_str += f"<option value=\"{each_path}\">{each_path}</option>"
    return html_str

def list_scenarios(simulation_name=None):
    if simulation_name is None:
        return
    simulation_path = os.path.join(SIMULATION_RESULT_PATH, simulation_name)
    if not os.path.exists(simulation_path):
        return
    html_str = """

          Scenario id
          Collsion Rate
          Progress (m)

      """
    for each_playback_path in os.listdir(os.path.join(simulation_path,  'playback')):
        loaded_playback = load(os.path.join(simulation_path, 'playback', each_playback_path))
        for each_scenario_id in loaded_playback:
            html_str += "
"
            metric_rst = loaded_playback[each_scenario_id]['metrics']
            task = loaded_playback[each_scenario_id]['info']['task']
            dataset = loaded_playback[each_scenario_id]['info']['dataset']
            collision_rate = len(metric_rst['collided_pairs'])
            progress = metric_rst['progress']
            # jerk = "N/A"  # metric_rst['jerk']
            html_str += f"""
            {each_scenario_id}
            {collision_rate}
            {progress}
            """
            file_name = each_playback_path.split('.playback')[0]
            html_str += f"""

                        Visualize

                """
    html_str += """

"""

    return html_str


"""
Serialize data to/from JSON
"""

# Avoid shadowing the standard library json module
from __future__ import absolute_import
from __future__ import unicode_literals

import datetime
import decimal
import json
import sys

from theory.core.serializers.base import DeserializationError
from theory.core.serializers.python import Serializer as PythonSerializer
from theory.core.serializers.python import Deserializer as PythonDeserializer
from theory.utils import six
from theory.utils.timezone import isAware

class Serializer(PythonSerializer):
  """
  Convert a queryset to JSON.
  """
  internalUseOnly = False

  def startSerialization(self):
    if json.__version__.split('.') >= ['2', '1', '3']:
      # Use JS strings to represent Python Decimal instances (ticket #16850)
      self.options.update({'useDecimal': False})
    self._current = None
    self.jsonKwargs = self.options.copy()
    self.jsonKwargs.pop('stream', None)
    self.jsonKwargs.pop('fields', None)
    if self.options.get('indent'):
      # Prevent trailing spaces
      self.jsonKwargs['separators'] = (',', ': ')
    self.stream.write("[")

  def endSerialization(self):
    if self.options.get("indent"):
      self.stream.write("\n")
    self.stream.write("]")
    if self.options.get("indent"):
      self.stream.write("\n")

  def endObject(self, obj):
    # self._current has the field data
    indent = self.options.get("indent")
    if not self.first:
      self.stream.write(",")
      if not indent:
        self.stream.write(" ")
    if indent:
      self.stream.write("\n")
    json.dump(self.getDumpObject(obj), self.stream,
         cls=TheoryJSONEncoder, **self.jsonKwargs)
    self._current = None

  def getvalue(self):
    # Grand-parent super
    return super(PythonSerializer, self).getvalue()

def Deserializer(streamOrString, **options):
  """
  Deserialize a stream or string of JSON data.
  """
  if not isinstance(streamOrString, (bytes, six.stringTypes)):
    streamOrString = streamOrString.read()
  if isinstance(streamOrString, bytes):
    streamOrString = streamOrString.decode('utf-8')
  try:
    objects = json.loads(streamOrString)
    for obj in PythonDeserializer(objects, **options):
      yield obj
  except GeneratorExit:
    raise
  except Exception as e:
    # Map to deserializer error
    six.reraise(DeserializationError, DeserializationError(e), sys.exc_info()[2])

class TheoryJSONEncoder(json.JSONEncoder):
  """
  JSONEncoder subclass that knows how to encode date/time and decimal types.
  """
  def default(self, o):
    # See "Date Time String Format" in the ECMA-262 specification.
    if isinstance(o, datetime.datetime):
      r = o.isoformat()
      if o.microsecond:
        r = r[:23] + r[26:]
      if r.endswith('+00:00'):
        r = r[:-6] + 'Z'
      return r
    elif isinstance(o, datetime.date):
      return o.isoformat()
    elif isinstance(o, datetime.time):
      if isAware(o):
        raise ValueError("JSON can't represent timezone-aware times.")
      r = o.isoformat()
      if o.microsecond:
        r = r[:12]
      return r
    elif isinstance(o, decimal.Decimal):
      return str(o)
    else:
      return super(TheoryJSONEncoder, self).default(o)

# Older, deprecated class name (for backwards compatibility purposes).
DateTimeAwareJSONEncoder = TheoryJSONEncoder


from scitools.std import *
import ODESolver

def f(u, t):
    return -u

solver = ODESolver.ForwardEuler(f)
solver.set_initial_condition(1.0)
t_points = linspace(0, 3, 31)
u, t = solver.solve(t_points)
plot(t, u)

# Test various dt values and plot
figure()
T = 3
for dt in 2.0, 1.0, 0.5, 0.1:
    n = int(round(T/dt))
    solver = ODESolver.ForwardEuler(f)
    solver.set_initial_condition(1)
    u, t = solver.solve(linspace(0, T, n+1))
    plot(t, u, legend='dt=%g' % dt)
    hold('on')
plot(t, exp(-t), 'bo', legend='exact')
savefig('tmp_decay1.eps')

# Test ForwardEuler vs RungeKutta4
T = 3
dt = 0.5
n = int(round(T/dt))
t_points = linspace(0, T, n+1)
figure()
for solver_class in ODESolver.RungeKutta4, ODESolver.ForwardEuler:
    solver = solver_class(f)
    solver.set_initial_condition(1)
    u, t = solver.solve(t_points)
    plot(t, u, legend='%s' % solver_class.__name__)
    hold('on')
plot(t, exp(-t), 'bo', legend='exact')
savefig('tmp_decay2.eps')

# Test various dt values for RungeKutta4
figure()
T = 3
for dt in 2.0, 1.0, 0.5, 0.1:
    n = int(round(T/dt))
    solver = ODESolver.RungeKutta4(f)
    solver.set_initial_condition(1)
    u, t = solver.solve(linspace(0, T, n+1))
    plot(t, u, legend='dt=%g' % dt)
    hold('on')
plot(t, exp(-t), 'bo', legend='exact')
savefig('tmp_decay3.eps')

show()


import tensorflow as tf
import re

INITIALIZER_FULLY = tf.contrib.layers.xavier_initializer()
INITIALIZER_CON2D = tf.contrib.layers.xavier_initializer_conv2d()
BATCH_SIZE = 128

IMAGE_SIZE = 224
NUM_CLASSES = 10
NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN = 50000
NUM_EXAMPLES_PER_EPOCH_FOR_EVAL = 10000

MOVING_AVERAGE_DECAY = 0.9999
NUM_EPOCHS_PER_DECAY = 350.0
LEARNING_RATE_DECAY_FACTOR = 0.1
INITIAL_LEARNING_RATE = 0.1

TOWER_NAME = 'tower'

def _activation_summary(x):
    tensor_name = re.sub('%s_[0-9]*/' % TOWER_NAME, '', x.op.name)
    tf.summary.histogram(tensor_name + '/activations', x)
    tf.summary.scalar(tensor_name + '/sparsity',
                      tf.nn.zero_fraction(x))

def _variable_on_cpu(name, shape, initializer):
    with tf.device('/cpu:0'):
        dtype = tf.float32
        var = tf.get_variable(name, shape, initializer=initializer, dtype=dtype)
    return var

def _variable_with_weight_decay(name, shape, initializer, wd):
    var = _variable_on_cpu(name, shape, initializer)
    if wd is not None:
        weight_decay = tf.multiply(tf.nn.l2_loss(var), wd, name='weight_loss')
        tf.add_to_collection('losses', weight_decay)
    return var

def conv_op(x, name, n_out, training, useBN, kh=3, kw=3, dh=1, dw=1, padding="SAME", activation=tf.nn.relu):
    n_in = x.get_shape()[-1].value
    with tf.name_scope(name) as scope:
        w = tf.get_variable(scope + "w", shape=[kh, kw, n_in, n_out], dtype=tf.float32,
                            initializer=INITIALIZER_CON2D)
        b = tf.get_variable(scope + "b", shape=[n_out], dtype=tf.float32,
                            initializer=tf.constant_initializer(0.01))
        conv = tf.nn.conv2d(x, w, [1, dh, dw, 1], padding=padding)
        z = tf.nn.bias_add(conv, b)
        if useBN:
            z = tf.layers.batch_normalization(z, trainable=training)
        if activation:
            z = activation(z)

        _activation_summary(z)
    return z

def res_block_layers(x, name, n_out_list, change_dimension=False, block_stride=1):
    if change_dimension:
        short_cut_conv = conv_op(x, name + "_ShortcutConv", n_out_list[1], training=True, useBN=True, kh=1, kw=1,
                                 dh=block_stride, dw=block_stride,
                                 padding="SAME", activation=None)
    else:
        short_cut_conv = x

    block_conv_1 = conv_op(x, name + "_lovalConv1", n_out_list[0], training=True, useBN=True, kh=1, kw=1,
                           dh=block_stride, dw=block_stride,
                           padding="SAME", activation=tf.nn.relu)

    block_conv_2 = conv_op(block_conv_1, name + "_lovalConv2", n_out_list[0], training=True, useBN=True, kh=3, kw=3,
                           dh=1, dw=1,
                           padding="SAME", activation=tf.nn.relu)

    block_conv_3 = conv_op(block_conv_2, name + "_lovalConv3", n_out_list[1], training=True, useBN=True, kh=1, kw=1,
                           dh=1, dw=1,
                           padding="SAME", activation=None)

    block_res = tf.add(short_cut_conv, block_conv_3)
    res = tf.nn.relu(block_res)
    return res

def max_pool_op(x, name, kh=2, kw=2, dh=2, dw=2,padding="SAME"):
    return tf.nn.max_pool(x,ksize=[1, kh, kw, 1],
                          strides=[1, dh, dw, 1],
                          padding=padding,
                          name=name)

def avg_pool_op(x, name, kh=2, kw=2, dh=2, dw=2,padding="SAME"):
    return tf.nn.avg_pool(x,
                          ksize=[1, kh, kw, 1],
                          strides=[1, dh, dw, 1],
                          padding=padding,
                          name=name)

def fc_op(x, name, n_out):
    n_in = x.get_shape()[-1].value
    with tf.name_scope(name) as scope:
        w = tf.get_variable(scope + "w", shape=[n_in, n_out],
                            dtype=tf.float32,
                            initializer=INITIALIZER_FULLY)
        b = tf.get_variable(scope + "b", shape=[n_out], dtype=tf.float32,
                            initializer=tf.constant_initializer(0.01))

        fc = tf.matmul(x, w) + b

        _activation_summary(fc)

    return fc

def inference(X):

    # ResNet

    usBN = True
    training = True
    conv1 = conv_op(X, "conv1", 64, training, usBN, 3, 3, 1, 1)
    pool1 = max_pool_op(conv1, "pool1", kh=3, kw=3)

    block1_1 = res_block_layers(pool1, "block1_1", [64, 256], True, 1)
    block1_2 = res_block_layers(block1_1, "block1_2", [64, 256], False, 1)
    block1_3 = res_block_layers(block1_2, "block1_3", [64, 256], False, 1)

    block2_1 = res_block_layers(block1_3, "block2_1", [128, 512], True, 2)
    block2_2 = res_block_layers(block2_1, "block2_2", [128, 512], False, 1)
    block2_3 = res_block_layers(block2_2, "block2_3", [128, 512], False, 1)
    block2_4 = res_block_layers(block2_3, "block2_4", [128, 512], False, 1)

    block3_1 = res_block_layers(block2_4, "block3_1", [256, 1024], True, 2)
    block3_2 = res_block_layers(block3_1, "block3_2", [256, 1024], False, 1)
    block3_3 = res_block_layers(block3_2, "block3_3", [256, 1024], False, 1)
    block3_4 = res_block_layers(block3_3, "block3_4", [256, 1024], False, 1)
    block3_5 = res_block_layers(block3_4, "block3_5", [256, 1024], False, 1)
    block3_6 = res_block_layers(block3_5, "block3_6", [256, 1024], False, 1)

    block4_1 = res_block_layers(block3_6, "block4_1", [512, 2048], True, 2)
    block4_2 = res_block_layers(block4_1, "block4_2", [512, 2048], False, 1)
    block4_3 = res_block_layers(block4_2, "block4_3", [512, 2048], False, 1)

    pool2 = avg_pool_op(block4_3, "pool2", kh=7, kw=7, dh=1, dw=1, padding="SAME")
    shape = pool2.get_shape()
    fc_in = tf.reshape(pool2, [-1, shape[1].value * shape[2].value * shape[3].value])
    logits = fc_op(fc_in, "fc1", NUM_CLASSES)

    return logits

    # CNN

    # with tf.variable_scope('conv1') as scope:
    #     kernel = _variable_with_weight_decay('weights',
    #                                          shape=[5, 5, 3, 64],
    #                                          initializer=INITIALIZER_CON2D,
    #                                          wd=None)
    #     conv = tf.nn.conv2d(X, kernel, [1, 1, 1, 1], padding='SAME')
    #     biases = _variable_on_cpu('biases', [64], tf.constant_initializer(0.0))
    #     pre_activation = tf.nn.bias_add(conv, biases)
    #     conv1 = tf.nn.relu(pre_activation, name=scope.name)
    #     _activation_summary(conv1)
    #
    # pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
    #                        padding='SAME', name='pool1')
    #
    # norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75,
    #                   name='norm1')
    #
    # with tf.variable_scope('conv2') as scope:
    #     kernel = _variable_with_weight_decay('weights',
    #                                          shape=[5, 5, 64, 64],
    #                                          initializer=INITIALIZER_CON2D,
    #                                          wd=None)
    #     conv = tf.nn.conv2d(norm1, kernel, [1, 1, 1, 1], padding='SAME')
    #     biases = _variable_on_cpu('biases', [64], tf.constant_initializer(0.1))
    #     pre_activation = tf.nn.bias_add(conv, biases)
    #     conv2 = tf.nn.relu(pre_activation, name=scope.name)
    #     _activation_summary(conv2)
    #
    # norm2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75,
    #                   name='norm2')
    #
    # pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1],
    #                        strides=[1, 2, 2, 1], padding='SAME', name='pool2')
    #
    # with tf.variable_scope('local3') as scope:
    #     reshape = tf.reshape(pool2, [X.get_shape().as_list()[0], -1])
    #     dim = reshape.get_shape()[1].value
    #     weights = _variable_with_weight_decay('weights', shape=[dim, 384],
    #                                           initializer=INITIALIZER_FULLY, wd=0.004)
    #     biases = _variable_on_cpu('biases', [384], tf.constant_initializer(0.1))
    #     local3 = tf.nn.relu(tf.matmul(reshape, weights) + biases, name=scope.name)
    #     _activation_summary(local3)
    #
    # with tf.variable_scope('local4') as scope:
    #     weights = _variable_with_weight_decay('weights', shape=[384, 192],
    #                                           initializer=INITIALIZER_FULLY, wd=0.004)
    #     biases = _variable_on_cpu('biases', [192], tf.constant_initializer(0.1))
    #     local4 = tf.nn.relu(tf.matmul(local3, weights) + biases, name=scope.name)
    #     _activation_summary(local4)
    #
    # with tf.variable_scope('softmax_linear') as scope:
    #     weights = _variable_with_weight_decay('weights', [192, NUM_CLASSES],
    #                                           initializer=INITIALIZER_FULLY, wd=None)
    #     biases = _variable_on_cpu('biases', [NUM_CLASSES],
    #                               tf.constant_initializer(0.0))
    #     softmax_linear = tf.add(tf.matmul(local4, weights), biases, name=scope.name)
    #     _activation_summary(softmax_linear)
    #
    # return softmax_linear

def loss(logits, labels):
    labels = tf.cast(labels, tf.int64)
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
        labels=labels, logits=logits, name='cross_entropy_per_example')
    cross_entropy_mean = tf.reduce_mean(cross_entropy, name='cross_entropy')
    tf.add_to_collection('losses', cross_entropy_mean)

    return tf.add_n(tf.get_collection('losses'), name='total_loss')

def _add_loss_summaries(total_loss):
    loss_averages = tf.train.ExponentialMovingAverage(0.9, name='avg')
    losses = tf.get_collection('losses')
    loss_averages_op = loss_averages.apply(losses + [total_loss])

    for l in losses + [total_loss]:
        tf.summary.scalar(l.op.name + ' (raw)', l)
        tf.summary.scalar(l.op.name, loss_averages.average(l))

    return loss_averages_op

def train(total_loss, global_step):
    num_batches_per_epoch = NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN / BATCH_SIZE
    decay_steps = int(num_batches_per_epoch * NUM_EPOCHS_PER_DECAY)

    lr = tf.train.exponential_decay(INITIAL_LEARNING_RATE,
                                    global_step,
                                    decay_steps,
                                    LEARNING_RATE_DECAY_FACTOR,
                                    staircase=True)
    tf.summary.scalar('learning_rate', lr)

    loss_averages_op = _add_loss_summaries(total_loss)

    with tf.control_dependencies([loss_averages_op]):
        opt = tf.train.AdamOptimizer(lr)
        grads = opt.compute_gradients(total_loss)

    apply_gradient_op = opt.apply_gradients(grads, global_step=global_step)

    for var in tf.trainable_variables():
        tf.summary.histogram(var.op.name, var)

    for grad, var in grads:
        if grad is not None:
            tf.summary.histogram(var.op.name + '/gradients', grad)

    variable_averages = tf.train.ExponentialMovingAverage(
        MOVING_AVERAGE_DECAY, global_step)
    with tf.control_dependencies([apply_gradient_op]):
        variables_averages_op = variable_averages.apply(tf.trainable_variables())

    return variables_averages_op

def evaluation(logits, labels):
    correct = tf.nn.in_top_k(logits, labels, k=1)
    return tf.reduce_mean(tf.cast(correct, tf.float32), name='accuracy')


"""
https://leetcode.com/problems/powx-n/

Implement pow(x, n), which calculates x raised to the power n (xn).

Example 1:

Input: 2.00000, 10
Output: 1024.00000
Example 2:

Input: 2.10000, 3
Output: 9.26100
Example 3:

Input: 2.00000, -2
Output: 0.25000
Explanation: 2-2 = 1/22 = 1/4 = 0.25

Note:
-100.0 < x < 100.0
n is a 32-bit signed integer, within the range [−231, 231 − 1]

"""

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if n < 0:
            x = 1 / x
            n = -n

        ans = 1
        tmp = x

        while n != 0:
            if n % 2 == 1:
                ans *= tmp
            tmp *= tmp
            n //= 2
        return ans


import unittest
import warnings
from concurrent.futures import Future

from lte.protos.mconfig.mconfigs_pb2 import PipelineD
from magma.pipelined.app.arp import ArpController
from magma.pipelined.bridge_util import BridgeTools
from magma.pipelined.openflow.registers import DIRECTION_REG, Direction
from magma.pipelined.tests.app.packet_builder import ARPPacketBuilder
from magma.pipelined.tests.app.packet_injector import ScapyPacketInjector
from magma.pipelined.tests.app.start_pipelined import (
    PipelinedController,
    TestSetup,
)
from magma.pipelined.tests.app.table_isolation import (
    RyuDirectTableIsolator,
    RyuForwardFlowArgsBuilder,
)
from magma.pipelined.tests.pipelined_test_util import (
    SnapshotVerifier,
    create_service_manager,
    start_ryu_app_thread,
    stop_ryu_app_thread,
    wait_after_send,
)

def _pkt_total(stats):
    return sum(n.packets for n in stats)

class ArpTableTest(unittest.TestCase):
    BRIDGE = 'testing_br'
    IFACE = 'testing_br'
    MAC_DEST = "5e:cc:cc:b1:49:4b"
    BRIDGE_IP = '192.168.128.1'
    UE_BLOCK = '192.168.128.0/24'
    UE_MAC = '5e:cc:cc:b1:49:4b'
    UE_IP = '192.168.128.22'
    OTHER_MAC = '0a:00:27:00:00:02'
    OTHER_IP = '1.2.3.4'

    @classmethod
    @unittest.mock.patch(
        'netifaces.ifaddresses',
        return_value={0: [{'addr': '00:11:22:33:44:55'}]},
    )
    @unittest.mock.patch('netifaces.AF_LINK', 0)
    def setUpClass(cls, *_):
        """
        Starts the thread which launches ryu apps

        Create a testing bridge, add a port, setup the port interfaces. Then
        launch the ryu apps for testing pipelined. Gets the references
        to apps launched by using futures.
        """
        super(ArpTableTest, cls).setUpClass()
        warnings.simplefilter('ignore')
        cls.service_manager = create_service_manager([], ['arpd'])
        cls._tbl_num = cls.service_manager.get_table_num(ArpController.APP_NAME)

        arp_controller_reference = Future()
        testing_controller_reference = Future()
        test_setup = TestSetup(
            apps=[
                PipelinedController.Arp,
                PipelinedController.Testing,
                PipelinedController.StartupFlows,
            ],
            references={
                PipelinedController.Arp:
                    arp_controller_reference,
                PipelinedController.Testing:
                    testing_controller_reference,
                PipelinedController.StartupFlows:
                    Future(),
            },
            config={
                'setup_type': 'LTE',
                'allow_unknown_arps': False,
                'bridge_name': cls.BRIDGE,
                'bridge_ip_address': cls.BRIDGE_IP,
                'ovs_gtp_port_number': 32768,
                'virtual_interface': cls.BRIDGE,
                'local_ue_eth_addr': True,
                'quota_check_ip': '1.2.3.4',
                'clean_restart': True,
                'enable_nat': True,
            },
            mconfig=PipelineD(
                ue_ip_block=cls.UE_BLOCK,
            ),
            loop=None,
            service_manager=cls.service_manager,
            integ_test=False,
        )

        BridgeTools.create_bridge(cls.BRIDGE, cls.IFACE)

        cls.thread = start_ryu_app_thread(test_setup)
        cls.arp_controller = arp_controller_reference.result()
        cls.testing_controller = testing_controller_reference.result()

    @classmethod
    def tearDownClass(cls):
        stop_ryu_app_thread(cls.thread)
        BridgeTools.destroy_bridge(cls.BRIDGE)

    def test_uplink_to_ue_arp(self):
        """
        Verify that a UPLINK->UE arp request is properly matched
        """
        pkt_sender = ScapyPacketInjector(self.IFACE)
        arp_packet = ARPPacketBuilder() \
            .set_ether_layer(self.UE_MAC, self.OTHER_MAC) \
            .set_arp_layer(self.UE_IP) \
            .set_arp_hwdst(self.UE_MAC) \
            .set_arp_src(self.OTHER_MAC, self.OTHER_IP) \
            .build()

        dlink_args = RyuForwardFlowArgsBuilder(self._tbl_num) \
            .set_eth_match(eth_dst=self.UE_MAC, eth_src=self.OTHER_MAC) \
            .set_reg_value(DIRECTION_REG, Direction.IN) \
            .build_requests()
        isolator = RyuDirectTableIsolator(dlink_args, self.testing_controller)

        snapshot_verifier = SnapshotVerifier(
            self, self.BRIDGE,
            self.service_manager,
        )

        with isolator, snapshot_verifier:
            pkt_sender.send(arp_packet)
            wait_after_send(self.testing_controller)

    def test_ue_to_uplink_arp(self):
        """
        Verify that a UE->UPLINK arp request is properly matched
        """
        pkt_sender = ScapyPacketInjector(self.IFACE)
        arp_packet = ARPPacketBuilder() \
            .set_ether_layer(self.OTHER_MAC, self.UE_MAC) \
            .set_arp_layer(self.OTHER_IP) \
            .set_arp_hwdst(self.OTHER_MAC) \
            .set_arp_src(self.UE_MAC, self.UE_IP) \
            .build()

        uplink_args = RyuForwardFlowArgsBuilder(self._tbl_num) \
            .set_eth_match(eth_src=self.UE_MAC, eth_dst=self.OTHER_MAC) \
            .set_reg_value(DIRECTION_REG, Direction.OUT) \
            .build_requests()
        isolator = RyuDirectTableIsolator(uplink_args, self.testing_controller)

        snapshot_verifier = SnapshotVerifier(
            self, self.BRIDGE,
            self.service_manager,
        )

        with isolator, snapshot_verifier:
            pkt_sender.send(arp_packet)
            wait_after_send(self.testing_controller)

    def test_stray_arp_drop(self):
        """
        Verify that an arp that neither UE->UPLINK nor UPLINK->UE is dropped
        """
        pkt_sender = ScapyPacketInjector(self.IFACE)
        arp_packet = ARPPacketBuilder() \
            .set_ether_layer('11:11:11:11:11:1', self.OTHER_MAC) \
            .set_arp_layer(self.OTHER_IP) \
            .set_arp_hwdst(self.OTHER_MAC) \
            .set_arp_src('22:22:22:22:22:22', '1.1.1.1') \
            .build()

        uplink_args = RyuForwardFlowArgsBuilder(self._tbl_num) \
            .set_eth_match(eth_dst='11:11:11:11:11:1', eth_src=self.OTHER_MAC) \
            .set_reg_value(DIRECTION_REG, Direction.OUT) \
            .build_requests()
        isolator = RyuDirectTableIsolator(uplink_args, self.testing_controller)

        snapshot_verifier = SnapshotVerifier(
            self, self.BRIDGE,
            self.service_manager,
        )

        with isolator, snapshot_verifier:
            pkt_sender.send(arp_packet)
            wait_after_send(self.testing_controller)

if __name__ == "__main__":
    unittest.main()


from numpy import squeeze, real, mean, pi, float16, array, float16, reshape, float32
from scipy import ndimage as ndi
from skimage.filters import gabor_kernel
from skimage.feature import hog
from skimage import feature
import cv2
import numpy as np
from skimage.transform import rescale, resize, downscale_local_mean
import pywt

def hogFeature(normalizedIrisPatch, regions):
    # regions: [(x1, x2), (x3, x4), (x5, x6), ...]
    upperCutHeight = 10
    # HOG Features
    hogFea = []
    for reg in regions:
        croppedImage = normalizedIrisPatch[upperCutHeight:, reg[0]:reg[1]]
        hog_cur = hog(croppedImage, orientations=6, pixels_per_cell=(32, 32), cells_per_block=(1, 1))
        hog_cur = array(hog_cur, float32)
        hogFea.append(hog_cur)

    hogFea = array(hogFea, dtype=float32)
    hogFea = reshape(hogFea, (hogFea.shape[0] * hogFea.shape[1],1))
    hogFea = hogFea.tolist()

    return hogFea

def lbpFeature(normalizedIrisPatch, regions):

    # regions: [(x1, x2), (x3, x4), (x5, x6), ...]
    P = 16
    upperCutHeight = 10
    # LBP Features
    lbpFea = []
    for reg in regions:
        croppedImage = normalizedIrisPatch[upperCutHeight:, reg[0]:reg[1]]
        lbp = feature.local_binary_pattern(croppedImage, 16, 2, method='uniform')
        hist, _ = np.histogram(lbp, normed=True, bins=P + 2, range=(0, P + 2))
        lbpFea.append(hist)

    lbpFea = array(lbpFea, dtype=float32)
    lbpFea = reshape(lbpFea, (lbpFea.shape[0] * lbpFea.shape[1],1))
    lbpFea = lbpFea.tolist()

    return lbpFea

def gaborFeature(normalizedIrisPatch, regions):
    # regions: [(x1, x2), (x3, x4), (x5, x6), ...]
    upperCutHeight = 10
    # Gabor Features
    kernels = []
    freqs = [0.1, 0.2, 0.3, 0.4, 0.5]
    nTheta = 8
    for theta in range(nTheta):
        theta = theta / float16(nTheta) * pi
        sigma = 1
        for frequency in freqs:
            kernel = real(gabor_kernel(frequency, theta=theta, sigma_x=sigma, sigma_y=sigma))
            kernels.append(kernel)

    gaborFea = []

    for reg in regions:
        croppedImage = normalizedIrisPatch[upperCutHeight:, reg[0]:reg[1]]
        gaborFea_cur = []
        for k, kernel in enumerate(kernels):
            filteredIris = ndi.convolve(croppedImage, kernel, mode='wrap')
            gaborFea_cur.append(mean(filteredIris * filteredIris))
        gaborFea_cur = array(gaborFea_cur, float32)
        gaborFea.append(gaborFea_cur)

    gaborFea = array(gaborFea, dtype=float32)
    gaborFea = reshape(gaborFea, (gaborFea.shape[0] * gaborFea.shape[1],1))
    gaborFea =gaborFea.tolist()

    return gaborFea

def extract_image_feature(image, regions, downSampleSize):
    # regions: [(x1, x2), (x3, x4), (x5, x6), ...]
    upperCutHeight = 10
    # Pixel Features
    pixelFea = []
    for reg in regions:
        croppedImage    = image[upperCutHeight:, reg[0]:reg[1]]
        downSampledReg  = rescale(croppedImage, 1.0 / float16(downSampleSize), preserve_range=True)
        pixelFea.append(reshape(downSampledReg, (downSampledReg.shape[0]*downSampledReg.shape[1],)))

    pixelFea = array(pixelFea, dtype=float32)
    pixelFea = reshape(pixelFea, (pixelFea.shape[0]*pixelFea.shape[1], 1))
    pixelFea = pixelFea.tolist()

    return pixelFea


#
# GaussSum (http://gausssum.sf.net)
# Copyright (C) 2006-2013 Noel O'Boyle <baoilleach@gmail.com>
#
# This program is free software; you can redistribute and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.

import os
import sys
import math

# from Tkinter import *
from .plot import DisplayPlot
from .mpl import MPLPlot

def GeoOpt(root, screen, logfile, numpts):

    screen.write("Starting GeoOpt.py\n")

    deviation = []
    for i in range(len(logfile.geovalues)):
        dev = 0
        for j in range(len(logfile.geotargets)):
            if abs(logfile.geovalues[i][j]) > logfile.geotargets[j]:
                dev += math.log(abs(logfile.geovalues[i][j]) / logfile.geotargets[j])
        deviation.append(dev)

    if len(logfile.scfenergies) >= numpts+2: # If there are two points to plot

        g = MPLPlot()
        g.setlabels("Optimisation Step", "Energy")
        data = list(zip(range(len(logfile.scfenergies)-numpts), logfile.scfenergies[numpts:]))
        g.data(data)
        g.data(data, lines=False)

        DisplayPlot(root, g, "Geometry optimisation")

        if len(deviation) >= numpts+2:

            h = MPLPlot()
            h.setlabels("Optimisation Step", "Deviation from targets")
            data = list(zip(range(len(deviation)-numpts), deviation[numpts:]))
            h.data(data)
            h.data(data, lines=False)
            h.subplot.set_ylim(bottom=0)

            DisplayPlot(root, h, "Deviation from targets")

    else:
        screen.write("I need at least two points to plot\n")

    screen.write("Finishing GeoOpt.py\n")


# coding=utf-8
#
# /**************************************************************************
# ***
# ***	File Author: Dell, 2018年 09月 18日 星期二 16:28:12 CST
# ***
# **************************************************************************/
#

import os
import sys
import logging
import argparse

import model

parser = argparse.ArgumentParser(description='Train Image Classificer Model')

parser.add_argument(
    '-root-dir',
    type=str,
    default=model.DEFAULT_TRAIN_DATA_ROOT_DIR,
    help='train data root directory, default: ' +
    model.DEFAULT_TRAIN_DATA_ROOT_DIR)
parser.add_argument(
    '-epochs',
    type=int,
    default=32,
    help='number of epochs for train, default: 32')
parser.add_argument(
    '-batch-size',
    type=int,
    default=64,
    help='batch size for training, default: 64')
parser.add_argument(
    '-device',
    type=str,
    default="cuda:0",
    help='cuda:0 or cpu, default: cuda:0')

def makedirs():
    for d in ["logs", "model"]:
        if not os.path.exists(d):
            os.mkdir(d)
        if not os.path.isdir(d):
            logging.error(
                "Please create dir 'logs' or 'model' under current directory.")
            raise Exception("logs or model is not directory.")

if __name__ == '__main__':
    args = parser.parse_args()

    if (not os.path.exists(args.root_dir)) or (not os.path.isdir(
            args.root_dir)):
        logging.error(args.root_dir + ' is not director or not exists.')
        sys.exit(-1)

    makedirs()

    data = model.train_data_loader(args.root_dir, args.batch_size)
    net = model.load_model(args.device, model.DEFAULT_MODEL)
    model.train_model(args.device, net, data, args.epochs)


import pandas as pd

"""
# read in LABR.csv as a dataframe
df_labr = pd.read_csv('LABR.csv', usecols=['OVERALL', 'PICK', 'PLAYER', 'MLB', 'POS', 'BID', 'TEAM', 'OWNER'])

# read in IDMAP.csv as a dataframe
df_idmap = pd.read_csv('IDMAP.csv', usecols=['FANTPROSNAME', 'IDFANGRAPHS'])

# merge the two dataframes on the 'PLAYER' and 'FANTPROSNAME' columns
df_merged = pd.merge(df_labr, df_idmap, left_on='PLAYER', right_on='FANTPROSNAME', how='left')

# create the 'PlayerId' column by filling missing values with an empty string
df_merged['PlayerId'] = df_merged['IDFANGRAPHS'].fillna('')

# drop the 'FANTPROSNAME' and 'IDFANGRAPHS' columns
df_general = df_merged.drop(['FANTPROSNAME', 'IDFANGRAPHS'], axis=1)

# ensure the 'PlayerId' column is of type string
df_general['PlayerId'] = df_general['PlayerId'].astype(str)

df_general.to_csv('list2.csv')

"""

# read in list.csv as a dataframe
df_general = pd.read_csv('list.csv')

# read in hitters.csv as a dataframe
df_hitters = pd.read_csv('hitters.csv', usecols=['PlayerId', 'H', 'AB', 'R', 'HR', 'RBI', 'SB'])

# read in pitchers.csv as a dataframe
df_pitchers = pd.read_csv('pitchers.csv', usecols=['PlayerId', 'ER', 'IP', 'H', 'BB', 'W', 'SV', 'SO'])

# merge 'df_general' with 'df_hitters' on 'PlayerId' column
df_merged = pd.merge(df_general, df_hitters, on='PlayerId', how='left')

# replace missing values in 'H', 'AB', 'R', 'HR', 'RBI', and 'SB' columns with 0
df_merged[['H', 'AB', 'R', 'HR', 'RBI', 'SB']] = df_merged[['H', 'AB', 'R', 'HR', 'RBI', 'SB']].fillna(0)

# merge the resulting dataframe with 'df_pitchers' on 'PlayerId' column
df_final = pd.merge(df_merged, df_pitchers, on='PlayerId', how='left')

# replace missing values in 'ER', 'IP', 'H_y', 'BB', 'W', 'SV', and 'SO' columns with 0
df_final[['ER', 'IP', 'H_y', 'BB', 'W', 'SV', 'SO']] = df_final[['ER', 'IP', 'H_y', 'BB', 'W', 'SV', 'SO']].fillna(0)

# ensure all numeric columns are of type float
df_final[['H_x', 'AB', 'R', 'HR', 'RBI', 'SB', 'ER', 'IP', 'H_y', 'BB', 'W', 'SV', 'SO']] = df_final[['H_x', 'AB', 'R', 'HR', 'RBI', 'SB', 'ER', 'IP', 'H_y', 'BB', 'W', 'SV', 'SO']].astype(float)

# ensure 'PlayerId' column is of type string
df_final['PlayerId'] = df_final['PlayerId'].astype(str)

# rename columns to remove '_x' and '_y' suffixes
df_final = df_final.rename(columns={'H_x': 'H', 'H_y': 'H_pitched'})

# assign the new dataframe to 'df_general'
df_general = df_final
df_general[['ER', 'IP', 'H_pitched', 'BB', 'W', 'SV', 'SO']] = df_general[['ER', 'IP', 'H_pitched', 'BB', 'W', 'SV', 'SO']].fillna(0)

# create a new dataframe that groups by the 'TEAM' column and sums all columns
grouped_df = df_general.groupby(['TEAM']).sum()

# save the grouped dataframe to a csv file called 'ranked.csv'
grouped_df.to_csv('ranked.csv', index=True)

grouped_df['AVG'] = grouped_df['H']/grouped_df['AB']
grouped_df['WHIP'] = (grouped_df['BB'] + grouped_df['H_pitched'])/grouped_df['IP']
grouped_df['ERA'] = (grouped_df['ER']*9)/grouped_df['IP']

# add ranking columns for R, HR, RBI, SB, AVG, W, SV, and SO
cols_to_rank = ['R', 'HR', 'RBI', 'SB', 'AVG', 'W', 'SV', 'SO']
for col in cols_to_rank:
    grouped_df[f'{col}_ranked'] = grouped_df[col].rank(method='max', ascending=True)

# add ranking columns for ERA and WHIP
cols_to_rank = ['ERA', 'WHIP']
for col in cols_to_rank:
    grouped_df[f'{col}_ranked'] = grouped_df[col].rank(method='min', ascending=False)

grouped_df = grouped_df.loc[:, [ 'R', 'HR', 'RBI', 'SB', 'AVG', 'W', 'SO', 'SV', 'WHIP', 'ERA','R_ranked', 'HR_ranked', 'RBI_ranked', 'SB_ranked', 'AVG_ranked', 'W_ranked', 'SO_ranked', 'SV_ranked', 'WHIP_ranked', 'ERA_ranked' ]]
cols = ['R_ranked', 'HR_ranked', 'RBI_ranked', 'SB_ranked', 'AVG_ranked', 'W_ranked', 'SO_ranked', 'SV_ranked', 'WHIP_ranked', 'ERA_ranked']

grouped_df['TOTAL'] = grouped_df[cols].sum(axis=1)

temp_cols=grouped_df.columns.tolist()
new_cols=temp_cols[-1:] + temp_cols[1:]
new_cols=new_cols[0:1] + new_cols[10:20] + new_cols[0:1] + temp_cols[0:1] + new_cols[1:10]
grouped_df=grouped_df[new_cols]

# save the updated dataframe to a new file called 'ranked_ranked.csv'
grouped_df.to_csv('ranked_ranked.csv')


def hamiltonianoVA(g, sol, sol_f, nodo):
    if len(g) + 1 == len(sol) and nodo == sol[0]:
        sol_f.append(sol.copy())
    else:
        for ady in g[nodo]:
            if  ady not in sol or (ady == sol[0] and len(sol) == len(g)):
                sol.append(ady)
                sol_f = hamiltonianoVA(g, sol, sol_f,  ady)
                sol.pop()
    return sol_f

if __name__ == '__main__':

    N,M = map(int,input().strip().split())

    g =[[] for _ in range(N)]

    for _ in range(M):
        a,b = map(int,input().strip().split())
        g[a].append(b)
        g[b].append(a)

    sol = hamiltonianoVA(g, [0], [], 0)
    print(sol)
    print(len(sol))


"""Module for parse svg file and return the
position of different elements"""

# Global variables ------------------------------------------------------------

GRAPH_PATH = "../ressources/graphes/"

# Imports ---------------------------------------------------------------------

import os
import random
import xml.etree.ElementTree as ET
from .node import Node, Arrow

# Classes ---------------------------------------------------------------------

class Parser:
    """Class for get node's and arrow's coordinates
    Also give the minimum size for the canvas"""
    def __init__(self, window, path=None):
        self.__select_file(path)
        self.parser = ET.parse(self.path)
        self.root = self.parser.getroot()
        self.window_size = window
        self.graph_width = self.root.attrib['width'].replace('pt', '')
        self.graph_height = self.root.attrib['height'].replace('pt', '')

    def get_nodes(self):
        """Return all nodes in the svg file"""
        nodes = list()
        for child in self.root[0]:
            if 'node' in child.attrib.values():
                for element in child:
                    if 'title' in element.tag:
                        current_name = element.text
                    elif 'ellipse' in element.tag:
                        if element.attrib['fill'] == "none":
                            poisoned = False
                        else:
                            poisoned = True
                        nodes.append(
                            Node(current_name,
                                 poisoned,
                                 (float(element.attrib['cx']),
                                  float(element.attrib['cy']) * -1)))
        return self.__create_dico(nodes)

    def get_arrows(self):
        """Return all edges in the svg file"""
        arrows = list()
        for child in self.root[0]:
            if 'edge' in child.attrib.values():
                current_points_line = list()
                current_points_sting = list()
                for element in child:
                    if 'title' in element.tag:
                        current_name = tuple(element.text.split("->"))
                    elif 'path' in element.tag:
                        element.attrib['d'] = element.attrib['d'].replace('C', ' ')
                        coord_lines = element.attrib['d'].split(' ')
                        coord_lines[0] = coord_lines[0].replace('M', '')
                        coord_lines = coord_lines[::3]
                        for points in coord_lines:
                            points = points.split(',')
                            for point in points:
                                current_points_line.append(point)
                    elif 'polygon' in element.tag:
                        current_points_sting = element.attrib['points'].replace(" ", ",").split(",")
                        self.__formalize_number(current_points_line, current_points_sting)
                        arrows.append(
                            Arrow(current_name,
                                  current_points_line,
                                  current_points_sting))
        return arrows

    def __formalize_number(self, line, sting):
        """Convert negative number for avoid weird result on render

        Arguments:
            line {List} -- list of point for line
            sting {List} -- list of point for sting
        """
        for i, value in enumerate(line):
            if float(value) < 0:
                line[i] = self.window_size - (-1 * float(value))
        for i, value in enumerate(sting):
            if float(value) < 0:
                sting[i] = self.window_size - (-1 * float(value))

    def __create_dico(self, nodes):
        """Convert the nodes list to a dictionary for improve the
        complexity of the program

        Arguments:
            nodes {List} -- The list to convert

        Returns:
            Dict -- The dictionary
        """
        dic = dict()
        for node in nodes:
            dic[node.id_node] = node
        return dic

    def __select_file(self, file):
        """Select the file to parse data in other word select
        the graph for play if None select a random file

        Arguments:
            file {string} -- the name of the file
        """
        files = os.listdir(GRAPH_PATH)
        selected = str()
        if not file:
            selected = GRAPH_PATH + random.choice(files)
        else:
            assert file in files
            selected = GRAPH_PATH + file
        self.path = selected


import apace as ap
import matplotlib.pyplot as plt
import numpy as np
from fodo import make_fodo

from master_thesis import figure_path

angles = [0, np.pi / 8, np.pi / 4]
fodo = make_fodo(angle=angles[1])
d1, b1, q1, q2 = (fodo[name] for name in ("d1", "b1", "q1", "q2"))
twiss = ap.Twiss(fodo)

steps = 1000
lengths = [0.5, 1.0, 1.5]
n_rows, n_cols = len(lengths) + 1, len(angles)
fig, axs = plt.subplots(
    nrows=n_rows,
    ncols=n_cols,
    figsize=(4 * n_cols, 2.5 * n_rows),
    gridspec_kw={"height_ratios": [0.01, 1, 1, 1]},
)

for ax, angle in zip(axs[0], angles):
    ax.axis("off")
    ax.set_title(
        f"Dipole angle ({np.degrees(angle)}° per cell)", fontweight="bold", pad=0
    )

for column, angle in zip(axs[1:].T, angles):
    b1.angle = angle
    b1.e1 = b1.e2 = 0.5 * angle

    for ax, length in zip(column, lengths):
        d1.length = length
        # breakpoint()
        extent = 0, 2, 0, -2
        results = np.empty((steps, steps))
        for i, q1.k1 in enumerate(np.linspace(*extent[:2], steps)):
            for j, q2.k1 in enumerate(np.linspace(*extent[2:], steps)):
                try:
                    results[i, j] = np.mean(twiss.beta_x) + np.mean(twiss.beta_y)
                except ap.UnstableLatticeError:
                    results[i, j] = np.nan
        image = ax.imshow(
            results.T, extent=extent, origin="lower", vmin=0, vmax=30, cmap="cool"
        )
        ax.set_xlabel(f"$k_\\mathrm{{{q1.name}}}$ / m$^{{-2}}$")
        ax.set_ylabel(f"$k_\\mathrm{{{q2.name}}}$ / m$^{{-2}}$")
        ax.set_title(f"cell length: {fodo.length} m")
        colorbar = fig.colorbar(image, ax=ax)
        colorbar.ax.set_title(r"$\beta_\mathrm{mean}$", fontsize=12, pad=10)

plt.tight_layout()
plt.savefig(figure_path / "necktie-plot.svg")


import numpy as np
import pandas as pd
import os
import seq_sample

#对一支股的数据进行字段筛选,排序
def clean_stock_data(stock_data):
  cols = ['close', 'open', 'high', 'low',
          'turnover', 'volume']
  stock_data.index = pd.to_datetime(stock_data['date'])
  stock_data = stock_data[cols]
  stock_data = stock_data.sort_index(ascending=True)
  return stock_data

# get stocks dict
# key: stock code
# value: stock data frame
def fetch_group_stocks_from_fs(path):
  files = os.listdir(path)
  stocks = {}
  for f in files:
    code = f.split('.')[0]
    f = path+f
    df = pd.read_csv(f)
    df = clean_stock_data(df)
    stocks[code] = df
  return stocks

def normalize_seq(x):
  # normalized
  x = (x-x.mean())/x.std()
  return x

# 计算一支股票数据框的收益率
def get_rate_of_return(stock_data):
  s = stock_data['close']
  return (s[-1]-s[0])/s[0]

# 从一支股票的数据stock_data中抽取时间序列样本
# stock_data是股票的数据框
def get_stock_samples(stock_data, n_feats=30, n_labels=5):
  feats = []
  labels = []

  # 从选择的股票中提取样本特征feat和样本标签label
  for feat,label in seq_sample.get_feats_labels(stock_data, n_feats, n_labels):
    feat = normalize_seq(feat)
    feats.append(feat)
    labels.append(get_rate_of_return(label))

  feats = np.stack(feats)
  labels = np.stack(labels)
  labels = labels.reshape((labels.shape[0],1))

  return (feats,labels)

# 在一组股票中预测一支股票的收益率
# stocks是股一组股票的dict
# chosen_code是被预测股票的代码
# 建立一个特征长度为n_feats,标签长度为n_labels的数据的数据集
# 将股票数据逐次提取定长样本序列
# 并分为特征集feats和标签集labels
def get_group_stock_sample(stocks, chosen_code,n_feats=30,n_labels=5):
  chosen_stock_df = stocks[chosen_code]

  feats = []
  labels = []

  # 从选择的股票中提取样本特征x和样本标签y
  for x,y in seq_sample.get_feats_labels(chosen_stock_df,n_feats,n_labels):
    # 从股票组stocks中的其它股票中按x,y的时间来提取样本
    # 并用被选股票的标签y替换掉这些股票的样本标签feat
    for code in stocks:
      #if code == chosen_code:
      #  continue

      stock = stocks[code]
      feat = stock[min(x.index):max(x.index)]
      label = stock[min(y.index):max(y.index)]
      if len(x) == len(feat) and len(y) == len(label) :
        #y = normalize_seq(y)
        feat = normalize_seq(feat)
        feats.append(feat)
        labels.append(get_rate_of_return(y))

  feats = np.stack(feats)
  labels = np.stack(labels)
  labels = labels.reshape((labels.shape[0],1))

  return (feats, labels)

# 将feats和labels重组成适合RNN的样本张量
def rearange_stock_samples(feats,labels,batch_size):
  (feats,labels) = seq_sample.shufflelists([feats,labels])
  feats = seq_sample.get_seq_batch(feats,batch_size)
  feats = seq_sample.get_rnn_batchs(feats)

  labels = seq_sample.get_seq_batch(labels,batch_size)
  return feats,labels