# coding: utf-8
"""
============
PyTplot Demo
============

Written by Julie Barnum and Elysia Lucas.
The purpose of this demo is to show off some of the capabilities of PyTplot.
"""
import urllib

import pytplot

##############################################################################
# Loading data into memory
# ------------------------
# The pytplot package comes with a sample IDL tplot save file which will be used for the following tutorial,
# located in PyTplot Github (https://github.com/MAVENSDC/PyTplot) under pytplot/pytplot/sampledata.
# This file was generated in IDL, and therefore can be loaded into tplot if you wish to compare the
# IDL and python versions.
# Download the test file from the PyTplot Github acct
url = 'https://github.com/MAVENSDC/PyTplot/raw/master/docs/test_data.tplot'

urllib.request.urlretrieve(url, "./test_data.tplot")

##############################################################################
# To load this data into pytplot, type in the following command:
pytplot.tplot_restore(r'test_data.tplot')
print(pytplot.tplot_names())

##############################################################################
# Storing data
# ------------
# pytplot works by interacting with global variables (called tplot variables) that contain information necessary for
# creating one panel (or even one portion of a panel) of a plot, that can be accessed from the main level or
# within any Python routine. Before anything can be plotted, tplot variables must be loaded into memory.
# Single line Plot: to store data to plot a single line, the 'y' data will be a single list of data
# that will correspond to the points that will make up the line.
# Multi-line Plot: to store data to plot a multi-line plot, the 'y' data will be a list of lists.
# Each column of the "matrix" created is the data for one line. So if you had a list with four lists in it
# and three elements in each list [[1,2,3],[4,5,6],[7,8,9],[10,11,12]] three lines with four data points each
# will be plotted.
# Spectrogram Plot: to store data to plot for a spectrogram, 'v' data will be a list of bins for the data,
# and the 'y' data will be a matrix of values with dimensions of the length of "x" time the length of "v"
# Map Plot: to store data to plot for a latitude/longitude plot, 'x' will contain a list of latitudes
# and a list of longitudes, for example 'x':[[15,30,45],[30,60,90]], and the 'y' data will be a list of values
# that correspond to those latitude/longitude points
# Combining Two Plots: store_data('new_name', ['old_name1', 'old_name2'])
# to combine multiple existing tplot variables ('old_name1' and 'old_name2') into one new tplot variable
# ('new_name'). 'new_name' will have all data from the existing tplot variables entered in one new tplot variable.

##############################################################################
# Pytplot variables
# -----------------
# pytplot.tplot_names() will print the numbers and names of the tplot variables currently in memory.
# When using any routines that require the name of the tplot variable, the user can use either
# the name of the variable or the corresponding number.

pytplot.tplot_names()

##############################################################################
# Options
# -------
# pytplot.options('tplot_var', 'option', 'option_value') can be used to change plotting options
# corresponding to specific tplot variables. All options currently implemented are described in
# the pytplot documentation, but here are some examples to get you started.

# Line Thickness
pytplot.options('swia_vel', 'thick', 4)
# Y-axis Label
pytplot.options('swia_vel', 'ytitle', 'speed (km/s)')
# Vertical Plot Bounds
pytplot.options('SEP_1_ION', 'yrange', [5, 5000])
# Panel Size
pytplot.options(['mag', 'swia_den', 'swia_vel'], 'panel_size', 0.5)

##############################################################################
# Tplot Options
# -------------
# pytplot.tplot_options('option', 'option_value') can be used to change plotting options for the tplot routine.
# These control options affect all panels in a plot.

# Title
pytplot.tplot_options('title', 'All Plots')
# Window Size
pytplot.tplot_options('wsize', [800, 800])

# Adding a region of interest (ROI)
# pytplot will add a ROI (indicated by two vertical red lines, with grey shading in between)
# to all plot via specifying the 'roi' option
pytplot.tplot_options('roi', ['2016-06-20 11:12:24', '2016-06-20 14:12:00'])

# Another option available in tplot_options is to specify the number of seconds with consecutive nan
# values allowed before no interpolation should occur
pytplot.tplot_options('data_gap', 80)

##############################################################################
# Displaying data using tplot
# ---------------------------
# Single Panel Plot
pytplot.tplot('swia_vel')  # or, pytplot.tplot(6)

# Multiple Panel Plot
pytplot.tplot(['swia_counts', 'swia_vel', 'mag'])  # or, pytplot.tplot([4,6,7])

##############################################################################
# Interacting with Data Plots
# ---------------------------
# There are several ways to interact with the data plots. There is command line interaction
# that follows the same pattern of functions IDL utilizes. Pytplot additionally has interactivity
# built into the viewing window in the form of "tools".

# Moving forward and backward in time
# The Pan tool allows the user to click and drag the mouse on the plot to move along the x- or y-axis.

# Zooming in and out
# The Box Zoom tool allows the user to click and drag the mouse on the plot to specify
# their desired x-axis range.

# Show data points
# The Hover Tool displays the data of a given point when the user hovers their mouse over the line.

# Add crosshairs to plot window
# The Crosshairs Tool displays a set of crosshairs that follow the location of the mouse on the plot.
# Crosshairs can be modified to be not displayed...

pytplot.tplot_options('crosshair', False)
pytplot.tplot('swia_counts')

# and crosshair names can be modified.
pytplot.tplot_options('crosshair', True)  # Just re-adding the crosshairs
pytplot.options('swia_counts', 'crosshair_x', 'XXX')
pytplot.options('swia_counts', 'crosshair_y', 'YYY')
pytplot.options('swia_counts', 'crosshair_z', 'ZZZ')
pytplot.tplot('swia_counts')

# Adding timebars
# To place a vertical line at a specific time on all panels:
# pytplot.timebar('2016-06-20 01:15:32', thick=3, color='green') will add a vertical black line to all plots
# at the time entered. Further settings related to this routine are described in the pytplot documentation.

pytplot.timebar('2016-06-20 01:15:32', thick=3, color='green')

##############################################################################
# Interacting with spectrogram plots
# ----------------------------------
# pytplot also has the ability to interact directly with spectrograms.
# If you supply the interactive=True keyword to a pytplot.tplot command,
# a plot will appear next to the spectrogram that reads out "slices" of the plot when you hover the mouse over it.
# Additionally, you can set options in pytplot to include 'static_tavg', 'static', and 't_average',
# which creates a separate plot with the average over a specified time period,
# creates a separate plot with a single specified time period,
# and specifies a time period (in seconds, based on the mouse's current location)
# over which time should be averaged for the window which pops up when 'interactive=true' is specified, respectively.
# You can also log axes in both the spectrogram plots ('xlog' and 'zlog' options),
# and the interactive plots ('xlog_interactive' and 'ylog_interactive' options).

pytplot.options('swia_counts', 'ylog', 1)  # setting to 0 would make the y-axis linear
pytplot.options('swia_counts', 'zlog', 1)  # setting ot 0 would make the z-axis linear
pytplot.options('swia_counts', 'xlog_interactive', True)  # Setting to False would make the x-axis linear
pytplot.options('swia_counts', 'ylog_interactive', True)  # Setting to False would make the y-axis linear
pytplot.options('swia_counts', 'static_tavg', ['2016-06-20 12:00:00', '2016-06-20 13:00:00'])
pytplot.options('swia_counts', 'static', '2016-06-20 01:00:57')
pytplot.options('swia_counts', 't_average', 1200)
pytplot.tplot('swia_counts')

##############################################################################
# Saving output
# -------------
# pytplot plots have the ability to be saved via 'Save PNG' option from the plot window, or you can specify
# that you want to save a plot ahead of time via the 'save_png' option
# (e.g., pytplot.tplot('swia_counts', save_png = '/path/to/png/PNG.png')

##############################################################################
# Displaying in bokeh
# -------------------
# pytplot allows you to use bokeh for visualizing data (bokeh is a Python library that allows interactive plots
# to be visualized via a web browser window), via the 'bokeh' option
# (e.g., pytplot.tplot('swia_counts', bokeh=True)


import sys

sys.stdin = open("Ladder2.txt", "r")

T = int(input())
for tc in range(1, T + 1):
    ladder = [0] * 100
    for i in range(100):
        ladder[i] = list(map(int, input().split()))

    # 시작점 찾기
    minlen = 10000000
    idx = 0
    for j in range(100):
        if ladder[0][j] == 0: continue
        # 시작이 1. 시작할 수 있는 점부터 차례대로 출발
        # print("열 {} 출발합니다!".format(j))
        # 밑으로 내려가면서 높이가 99가 되면 끝나게
        h, w, count = 1, j, 1
        right = left = False
        while h < 99:
            # print("#{} -  현재 h:{}행 w:{}열까지의 거리는 :{}".format(j, h, w, count))
            # print("right:{} left:{}".format(right, left))
            # w == 0일 때
            if w == 0: left = False;
            if w == 99: right = False;

            # 오른쪽부터 살피기

            if ladder[h][w + 1] == 1 and w + 1 < 100:
                if left == False: right = True
                if left == False and right == True:
                    # print("오른쪽으로 이동했습니다.")
                    count += 1
                    w += 1
                    continue

            # 그다음 왼쪽
            if ladder[h][w - 1] == 1 and w - 1 > 0:
                if right == False: left = True
                # if left == right: left = True; right = False
                if left == True and right == False:
                    # print("왼쪽으로 이동했습니다.")
                    count += 1
                    w -= 1
                    continue

            right = left = False
            # 마지막으로 아래로
            if left == right and ladder[h + 1][w] == 1:
                # print("아래로 이동했습니다.")
                count += 1
                h += 1
                continue

        # print(" {}출발점의 도착까지의 길이는 {}이며 최종 도착지는 {}이고 지금 높이는 {}입니다. ".format(j, count, w, h))

        if minlen > count:
            # print("원래 minlen:{} 였는데 {}으로 바뀌었습니다. 출발점 : {}".format(minlen, count, j))
            minlen = count
            idx = j

        # print("현재 최소 길이는 : {}, 출발점은 :{} 최소길이를 가지는 출발점은 :{} 입니다. ".format(count, j, idx))
    print("#{} {}".format(tc, idx))


import numpy as np
from maf import Map
import networkx as nx
import pdb
import matplotlib.pyplot as plt

class BrickMap(Map):
    def __init__(self,grid:np.ndarray,num_directions:int):
        '''
        input: grid: numpy array
        num_directions: only 4
        '''
        assert num_directions==4, "Brick and Mortar is 4 connected only"
        super().__init__(grid,num_directions)
        #keeps track of which agent visited the cell last time
        self.visited_map=np.ones((self.m,self.n))*-1
        self.wall_cell=-1
        self.explored_cell=1
        #keeps count of how many cells have been marked visited
        self.visited=0
        #north,east,south,west
        self.default_neighbors=[[-1,0],[0,1],[1,0],[0,-1]]
        self.default_directions=[0,1,2,3]
        self.order_neighbor=self.perm_to_dict(self.permutations(self.default_neighbors))
        self.order_direction=self.perm_to_dict(self.permutations(self.default_directions))
        self.graph=self.makegraph(self.map)

    def permutations(self,x:list):
        '''
        x: a list
        return: all permutations of the elements inside dictionary
        '''
        if len(x)==1:
            return [x]
        else:
            ans=[]
            for i in range(len(x)):
                for p in self.permutations(x[:i]+x[i+1:]):
                    ans.append([x[i]]+p)
            return ans

    def perm_to_dict(self,x:list):
        '''
        x: a list
        return: list to dictionary
        '''
        d={}
        for i,a in enumerate(x):
            d[i]=a[:]
        return d

    def grid(self,x:int,y:int):
        '''
        returns the value of x,y coordinate in grid
        '''
        if x>=0 and y>=0 and x<self.n and y<self.m:
            #x,y=self.convert(x,y)
            return self.map[x,y]
        else:
            return None

    def fov(self,x:int,y:int,view:int):
        '''
        x: numpy x coordinate of agent
        y: numpy y coordinate of agent
        view: field of view
        return: the view of the agent located at x,y
        '''
        #x,y=self.convert(x,y)
        return self.map[max(0,x-view):min(self.m-1,x+view+1),max(0,y-view):min(self.n-1,y+view+1)]

    def makegraph(self,array:np.ndarray):
        '''
        arrey: 2d numpy array representation of map
        return: nx.Graph object
        '''
        #l is length, b is breadth
        l,b=array.shape
        g = nx.Graph()
        #add one node for each cell in graph object
        for i in range(l*b):
            g.add_node(i,explored=0)
        for i in range(l*b):
            #convert 1d coordinate of graph to 2d coordinate of grid
            x=i//b
            y=i%b
            if array[x,y]!=self.wall_cell:
                if x-1>=0 and array[x-1,y]!=self.wall_cell:
                    g.add_edge(x*b+y,(x-1)*b+y)
                if x+1<l and array[x+1,y]!=self.wall_cell:
                    g.add_edge(x*b+y,(x+1)*b+y)
                if y-1>=0 and array[x,y-1]!=self.wall_cell:
                    g.add_edge(x*b+y,x*b+y-1)
                if y+1<b and array[x,y+1]!=self.wall_cell:
                    g.add_edge(x*b+y,x*b+y+1)
        #remove all the node with degree 1
        for i in range(l*b):
            if g.degree(i)==0:
                g.remove_node(i)
        return g

    def visit_permission(self,crds:np.ndarray,agent:int,view:int):
        '''
        crds: cartesian coordinates of all agets
        agent: id of agent
        view: field of view of agent
        return: if we're allowed to mark cell as visited
        '''
        #l and b are length and breadth of grid
        oned=crds[agent]
        xl,yl=self.get_size()
        x,y=oned//xl,oned%xl
        grid=self.fov(x,y,view)
        l,b=grid.shape
        lx=min(view,x)
        ly=min(view,y)
        cellid=lx*b+ly
        graph=self.makegraph(grid)
        if np.sum(crds==crds[agent])==1:
            ap=set(nx.articulation_points(graph))
            return not cellid in ap
        return False

    def global_visit_permission(self,crds:np.ndarray,agent:int):
        '''
        crds: cartesian coordinates of all agets
        agent: id of agent
        return: if we're allowed to mark cell as visited
        '''
        #l and b are length and breadth of grid
        oned=crds[agent]
        if  np.sum(crds==crds[agent])==1:
            if self.graph.degree(oned)==1:
                return True
            else:
                #mx,my=self.convert(x,y)
                ap=set(nx.articulation_points(self.graph))
                return not oned in ap

    def mark(self,crds:np.ndarray,agent:int,view:int):
        '''
        crds: cartesian coordinates of all agents
        agent: id of agent
        view: field of view of agent
        returns: marks a cell visited or explored
        '''
        oned=crds[agent]
        xl,yl=self.get_size()
        x,y=oned//yl,oned%yl
        #mx,my=self.convert(x,y)
        if self.map[x,y]==self.wall_cell:
            raise NameError('Trying to visit a marked cell')
        elif self.map[x,y]!=self.explored_cell:
            self.explored+=1
            self.map[x,y]=self.explored_cell
        if self.visit_permission(crds,agent,view):
            self.map[x,y]=self.wall_cell
            self.graph.remove_node(oned)
            self.visited+=1
            return True
        return False

    def global_mark(self,crds:np.ndarray,agent:int):
        '''
        crds: cartesian coordinates of all agents
        agent: id of agent
        view: field of view of agent
        returns: marks a cell visited or explored
        '''
        oned=crds[agent]
        xl,yl=self.get_size()
        x,y=oned//xl,oned%xl
        #mx,my=self.convert(x,y)

        if self.global_visit_permission(crds,agent):
            self.map[x,y]=self.wall_cell
            self.graph.remove_node(oned)
            self.visited+=1
            return True
        return False

    def marked_visited(self):
        '''
        return: fraction of map marked visited
        '''
        return self.visited/self.explorable

    def get_direction(self,crds:np.ndarray,agent:int,view:int):
        '''
        crds: cartesian coordinates of all agents
        agent: id of agent
        view: fielf of view of agent
        return: the directions for the agent to move and and actions
        '''
        unexplored=[]
        unexplored_directions=[]
        explored=[]
        explored_directions=[]
        oned=crds[agent]
        xl,yl=self.get_size()
        x,y=oned//yl,oned%yl
        #mx,my=self.convert(x,y)
        #american spelling, not british one
        #directions north, east,south, west
        neighbors=self.order_neighbor[agent%24]
        directions=self.order_direction[agent%24]
        for neighbor,d in zip(neighbors,directions):
            a,b=neighbor[0],neighbor[1]
            if x+a>=0 and y+b>=0 and x+a<self.m and y+b<self.n:
                #cell is unexplored
                if self.map[x+a,y+b]==0:
                    value=3-self.graph.degree(xl*(x+a)+y+b)
                    unexplored_directions.append(d)
                    unexplored.append(value)
                elif self.map[x+a,y+b]==self.explored_cell and self.map[x+a,y+b]!=self.wall_cell:
                    explored.append([x+a,y+b])
                    explored_directions.append(d)
        if unexplored:
            return unexplored,unexplored_directions,'unexplored'
        elif explored:
            return explored,explored_directions,'explored'
        else:
            return [],[],'terminate'

    def get_order(self,id:int):
        '''
        id: id of agent
        returns: it's default order
        '''
        return self.order_direction[id%24]

class BNMAgent:
    def __init__(self,x:int,y:int,id:int,map_object:BrickMap):
        '''
        input: x and y coordinates of agents
        order: between 0 and 23 (including both) which defines default preferences of an agent
        map_object: The map agents will explore
        '''
        self.startx=x
        self.starty=y
        self.x=x
        self.y=y
        self.last=[x,y]
        self.id=id
        self.order=self.id%24
        self.terminate=False
        self.map=map_object
        self.fov=1
        sizey,sizex=self.map.get_size()
        self.l,self.b=sizey,sizex
        self.visit=np.ones_like((self.map.map))*-1
        #self.indir=np.ones_like((self.map.map))*-1
        #self.outdir=np.ones((sizex,sizey))*-1
        #four phases 0: loop detection, 1: loop control,
        # 2: loop closing, 3: loop cleaning
        self.phase=0
        self.loop_detected=False
        self.visited=0
        self.explored=0

    def move(self,crds:np.ndarray,directions:list):
        '''
        crds: coordinates of all the agents
        direction: direction to move into
        returns: move the agent in direction and update it's x,y coordinates in cartesian
        '''
        #keep track of cells marked explored and visited by agent
        if self.map.grid(self.x,self.y)!=self.map.explored_cell:
            self.explored+=1
        if self.map.mark(crds,self.id,self.fov) or (self.visit[self.x,self.y]!=-1 and self.map.global_mark(crds,self.id)):
            self.visited+=1

        #record outdirection
        #mx,my=self.map.convert(self.x,self.y)
        self.visit[self.x,self.y]+=1
        #top
        #[[-1,0],[0,1],[1,0],[0,-1]]
        i=0
        while directions and i<len(directions):
            direction=directions[i]
            if direction==0 and self.x-1>=0 and ([self.x-1,self.y]!=self.last or len(directions)==1):
                self.last=[self.x,self.y]
                self.x-=1
                if self.map.grid(self.x,self.y)==self.map.wall_cell:
                    self.x+=1
                    return False
                else:
                    return True
            #right
            elif direction==1 and self.y+1<self.map.get_size()[1] and ([self.x,self.y+1]!=self.last or len(directions)==1):
                self.last=[self.x,self.y]
                self.y+=1
                if self.map.grid(self.x,self.y)==self.map.wall_cell:
                    self.y-=1
                    return False
                else:
                    return True
            #bottom
            elif direction==2 and self.x+1<self.map.get_size()[0] and ([self.x+1,self.y]!=self.last or len(directions)==1):
                self.last=[self.x,self.y]
                self.x+=1
                if self.map.grid(self.x,self.y)==self.map.wall_cell:
                    self.x-=1
                    return False
                else:
                    return True
            #left
            elif direction==3 and self.y-1>=0 and ([self.x,self.y-1]!=self.last or len(directions)==1):
                self.last=[self.x,self.y]
                self.y-=1
                if self.map.grid(self.x,self.y)==self.map.wall_cell:
                    self.y+=1
                    return False
                else:
                    return True
            i+=1
        raise NameError('Invalid direction input!!')

    def next(self,crds:np.ndarray):
        '''
        crds: cartesian coordinates of all the agents
        return: new coordinates of agent,
        if the agent terminates it returns its count of cells it marked visited
        '''
        #loop detection phase
        if self.phase==0:
            values,directions,action=self.map.get_direction(crds,self.id,self.fov)

            if action=='unexplored':
                dirs=[]
                while directions:
                    max_value=max(values)
                    idx=values.index(max_value)
                    values.pop(idx)
                    d=directions.pop(idx)
                    dirs.append(d)
                if not self.move(crds,dirs):
                    raise NameError("Moved into wall cell!!")

            elif action=='explored':
                i=0
                moved=False
                dirs=[]
                while i<4:
                    d=self.map.get_order(self.id)[i]
                    if d in directions:
                        dirs.append(d)
                    i+=1

                moved=self.move(crds,dirs)
                if not moved:
                    raise NameError("Moved into wall cell!!")
            elif action=='terminate':
                if len(self.map.graph)!=1:
                    raise NameError("trying to end early")
                self.terminate=True
                self.map.global_mark(crds,self.id)
                return -self.visited
            crds[self.id]=self.b*self.x+self.y
            '''if crds[self.id]==3861:
                print('stop')'''
            '''if self.visit[self.x,self.y]!=-1 and self.map.global_mark(crds,self.id):
                self.visited+=1'''
            #x,y=self.map.convert(self.x,self.y)
            return self.b*self.x+self.y

    def state(self):
        return not self.terminate

if __name__=='__main__':
    l,b=50,50
    grid=np.zeros((l,b))
    grid[int(l/2),:]=-1
    grid[int(l/2),int(b/2)]=0
    grid[int(l/2),int(b/2)+1]=0
    m=BrickMap(grid,4)
    agents=[]
    n=20
    crds=np.array([0]*n)
    for i in range(n):
        agents.append(BNMAgent(0,0,i,m))
    coverage_percentage=[]
    i=0
    while m.marked_visited()!=1:
        if agents[i%n].state():
            crds[i%n]=agents[i%n].next(crds)
        i+=1
        if i%n==0:
            print(i%n,m.covered(),end=' | ')
            coverage_percentage.append(m.covered())
    print(crds)


# If there are any issues, there might be a missing wx dependency.
# pip install wheel, pip install wxpython worked for me, but here are some things to try if you run into any issues:
# https://stackoverflow.com/questions/32284938/how-to-properly-install-wxpython

import wx
app = wx.App()  # Need to create an App instance before doing anything

# Inspired by: https://stackoverflow.com/a/10089645/4954277
def takeScreenshot():
    screen = wx.ScreenDC()
    size = screen.GetSize()
    bmp = wx.Bitmap(size[0], size[1])
    mem = wx.MemoryDC(bmp)
    mem.Blit(0, 0, size[0], size[1], screen, 0, 0)
    del mem  # Release bitmap
    bmp.SaveFile('screenshot.png', wx.BITMAP_TYPE_PNG)
    return 'screenshot.png'


import sys
import os
import PyPDF2
import fitz  # PyMuPDF
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QFileDialog, QVBoxLayout, QListWidget, QListWidgetItem, QLineEdit, QLabel, QScrollArea, QHBoxLayout
from PyQt5.QtGui import QPixmap

class PDFMergerApp(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.pdf_files = []

    def initUI(self):
        self.setWindowTitle('PDF Merger')
        self.setGeometry(100, 100, 800, 600)

        self.layout = QVBoxLayout()

        self.list_widget = QListWidget(self)
        self.layout.addWidget(self.list_widget)

        self.add_button = QPushButton('Agregar PDFs', self)
        self.add_button.clicked.connect(self.add_pdfs)
        self.layout.addWidget(self.add_button)

        self.remove_button = QPushButton('Eliminar PDF', self)
        self.remove_button.clicked.connect(self.remove_pdf)
        self.layout.addWidget(self.remove_button)

        self.output_label = QLabel('Nombre del archivo de salida:', self)
        self.layout.addWidget(self.output_label)

        self.output_name = QLineEdit(self)
        self.layout.addWidget(self.output_name)

        self.scroll_area = QScrollArea()
        self.scroll_area.setWidgetResizable(True)
        self.preview_widget = QWidget()
        self.preview_layout = QHBoxLayout(self.preview_widget)
        self.scroll_area.setWidget(self.preview_widget)
        self.layout.addWidget(self.scroll_area)

        self.merge_button = QPushButton('Unir PDFs', self)
        self.merge_button.clicked.connect(self.merge_pdfs)
        self.layout.addWidget(self.merge_button)

        self.setLayout(self.layout)

    def add_pdfs(self):
        options = QFileDialog.Options()
        file_names, _ = QFileDialog.getOpenFileNames(self, "Selecciona archivos PDF", "", "PDF Files (*.pdf)", options=options)

        if file_names:
            for file_name in file_names:
                item = QListWidgetItem(file_name)
                self.pdf_files.append(file_name)
                self.list_widget.addItem(item)
            self.update_preview()  # Actualizar la vista previa después de agregar archivos PDF

    def remove_pdf(self):
        selected_items = self.list_widget.selectedItems()
        for item in selected_items:
            file_name = item.text()
            self.pdf_files.remove(file_name)
            self.list_widget.takeItem(self.list_widget.row(item))
        self.update_preview()  # Actualizar la vista previa después de eliminar archivos PDF

    def render_pdf_preview(self, pdf_path):
        doc = fitz.open(pdf_path)
        page = doc.load_page(0)  # Mostrar la primera página como vista previa
        pixmap = QPixmap()
        pixmap.loadFromData(page.get_pixmap().tobytes("png"))
        return pixmap

    def update_preview(self):
        # Borrar todas las vistas previas anteriores
        for i in reversed(range(self.preview_layout.count())):
            widget = self.preview_layout.itemAt(i).widget()
            if widget is not None:
                widget.deleteLater()

        if self.pdf_files:
            for pdf_file in self.pdf_files:
                pixmap = self.render_pdf_preview(pdf_file)
                label = QLabel(self)
                label.setPixmap(pixmap)
                self.preview_layout.addWidget(label)

    def merge_pdfs(self):
        if not self.pdf_files:
            return

        output_file, _ = QFileDialog.getSaveFileName(self, "Guardar archivo PDF de salida", "", "PDF Files (*.pdf)")

        if output_file:
            if not output_file.endswith('.pdf'):
                output_file += '.pdf'

            merged_pdf = PyPDF2.PdfMerger()
            for file_name in self.pdf_files:
                merged_pdf.append(file_name)

            output_name = self.output_name.text()
            if not output_name:
                output_name = "merged.pdf"

            output_file = os.path.join(os.path.dirname(output_file), output_name)
            merged_pdf.write(output_file)
            merged_pdf.close()
            self.list_widget.clear()
            self.pdf_files = []
            self.list_widget.addItem('PDFs unidos y guardados en: ' + output_file)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = PDFMergerApp()
    window.show()
    sys.exit(app.exec_())


import tweet_topic_model
import numpy as np

dataset_name = 'dt'
dataset_path = '../data/davidson_icwsm17/labeled_data.csv'

# dataset_name = 'founta'
# dataset_path = '../data/founta_icwsm18/hatespeech_text_label_vote_RESTRICTED.csv'

num_topics = 5

tweets, vocabs, topics, likelihood = tweet_topic_model.get_tweet_topics(dataset_name, dataset_path, num_topics,
                                                                        min_num_words=3,
                                                                        min_tweet_frequency=5)
print(likelihood)
# print(vocabs)
print('Topwords:')
for z in range(num_topics):
    ids = list(np.argsort(topics[z])[-10:])
    ids.reverse()
    top_words = [vocabs[i] for i in ids]
    print('topic-%d: %s' % (z, ' '.join(top_words)))


import pickle
import timeit

import numpy as np

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
from sklearn.metrics import roc_auc_score, precision_score, recall_score, precision_recall_curve, auc, roc_curve

import csv
import os
import sys

"""BERT"""

def get_attn_pad_mask(seq):
    batch_size, seq_len = seq.size()
    pad_attn_mask = seq.data.eq(0).unsqueeze(1)  # [batch_size, 1, seq_len]
    pad_attn_mask_expand = pad_attn_mask.expand(batch_size, seq_len, seq_len)  # [batch_size, seq_len, seq_len]
    return pad_attn_mask_expand

class Embedding(nn.Module):
    def __init__(self):
        super(Embedding, self).__init__()
        self.tok_embed = nn.Embedding(vocab_size, d_model)  # token embedding (look-up table)
        self.pos_embed = nn.Embedding(max_len, d_model)  # position embedding
        self.norm = nn.LayerNorm(d_model)

    def forward(self, x):
        seq_len = x.size(1)  # x: [batch_size, seq_len]
        pos = torch.arange(seq_len, device=device, dtype=torch.long)  # [seq_len]
        pos = pos.unsqueeze(0).expand_as(x)  # [seq_len] -> [batch_size, seq_len]
        embedding = self.pos_embed(pos)
        embedding = embedding + self.tok_embed(x)
        embedding = self.norm(embedding)
        return embedding

class ScaledDotProductAttention(nn.Module):
    def __init__(self):
        super(ScaledDotProductAttention, self).__init__()

    def forward(self, Q, K, V, attn_mask):
        scores = torch.matmul(Q, K.transpose(-1, -2)) / np.sqrt(d_k)  # scores : [batch_size, n_head, seq_len, seq_len]
        scores.masked_fill_(attn_mask, -1e9)  # Fills elements of self tensor with value where mask is one.
        attn = nn.Softmax(dim=-1)(scores)  # [batch_size, n_head, seq_len, seq_len]
        context = torch.matmul(attn, V)  # [batch_size, n_head, seq_len, d_v]
        return context, attn

class MultiHeadAttention(nn.Module):
    def __init__(self):
        super(MultiHeadAttention, self).__init__()
        self.W_Q = nn.Linear(d_model, d_k * n_head)
        self.W_K = nn.Linear(d_model, d_k * n_head)
        self.W_V = nn.Linear(d_model, d_v * n_head)

        self.linear = nn.Linear(n_head * d_v, d_model)
        self.norm = nn.LayerNorm(d_model)

    def forward(self, Q, K, V, attn_mask):
        residual, batch_size = Q, Q.size(0)
        q_s = self.W_Q(Q).view(batch_size, -1, n_head, d_k).transpose(1, 2)  # q_s: [batch_size, n_head, seq_len, d_k]
        k_s = self.W_K(K).view(batch_size, -1, n_head, d_k).transpose(1, 2)  # k_s: [batch_size, n_head, seq_len, d_k]
        v_s = self.W_V(V).view(batch_size, -1, n_head, d_v).transpose(1, 2)  # v_s: [batch_size, n_head, seq_len, d_v]
        attn_mask = attn_mask.unsqueeze(1).repeat(1, n_head, 1, 1)
        context, attention_map = ScaledDotProductAttention()(q_s, k_s, v_s, attn_mask)
        context = context.transpose(1, 2).contiguous().view(batch_size, -1,
                                                            n_head * d_v)  # context: [batch_size, seq_len, n_head * d_v]
        output = self.linear(context)
        output = self.norm(output + residual)
        return output, attention_map

class PoswiseFeedForwardNet(nn.Module):
    def __init__(self):
        super(PoswiseFeedForwardNet, self).__init__()
        self.fc1 = nn.Linear(d_model, d_ff)
        self.fc2 = nn.Linear(d_ff, d_model)
        self.relu = nn.ReLU()

    def forward(self, x):
        # (batch_size, seq_len, d_model) -> (batch_size, seq_len, d_ff) -> (batch_size, seq_len, d_model)
        return self.fc2(self.relu(self.fc1(x)))

class EncoderLayer(nn.Module):
    def __init__(self):
        super(EncoderLayer, self).__init__()
        self.enc_self_attn = MultiHeadAttention()
        self.pos_ffn = PoswiseFeedForwardNet()
        self.attention_map = None

    def forward(self, enc_inputs, enc_self_attn_mask):
        enc_outputs, attention_map = self.enc_self_attn(enc_inputs, enc_inputs, enc_inputs,
                                                        enc_self_attn_mask)  # enc_inputs to same Q,K,V
        self.attention_map = attention_map
        enc_outputs = self.pos_ffn(enc_outputs)  # enc_outputs: [batch_size, seq_len, d_model]
        return enc_outputs

class BERT(nn.Module):
    def __init__(self):
        super(BERT, self).__init__()

        global max_len, n_layers, n_head, d_model, d_ff, d_k, d_v, vocab_size, device
        max_len = 2048
        n_layers = 3
        n_head = 8
        d_model = dim
        d_ff = 64
        d_k = 32
        d_v = 32
        vocab_size = n_word

        self.embedding = Embedding()
        self.layers = nn.ModuleList([EncoderLayer() for _ in range(n_layers)])
        self.fc_task = nn.Sequential(
            nn.Linear(d_model, d_model // 2),
            nn.Dropout(0.1),
            nn.ReLU(),
            nn.Linear(d_model // 2, 2),
        )
        self.classifier = nn.Linear(2, 2)

    def forward(self, input_ids):
        # input_ids[batch_size, seq_len] like[8,1975]
        output = self.embedding(input_ids)  # [batch_size, seq_len, d_model]
        enc_self_attn_mask = get_attn_pad_mask(input_ids)  # [batch_size, maxlen, maxlen]
        for layer in self.layers:
            output = layer(output, enc_self_attn_mask)

        return output

"""GNN"""

class GNN(nn.Module):
    def __init__(self):
        super(GNN, self).__init__()
        self.W_gnn = nn.ModuleList([nn.Linear(dim, dim) for _ in range(layer_gnn)])

    def forward(self, xs, A, layer):
        for i in range(layer):
            hs = torch.relu(self.W_gnn[i](xs))
            xs = xs + torch.matmul(A, hs)
        return torch.unsqueeze(torch.mean(xs, 0), 0)

"""AE2"""

class AENet(nn.Module):
    def __init__(self, inputDim, hiddenDim, prelr, totlr):
        super(AENet, self).__init__()

        self.enfc = nn.Linear(inputDim, hiddenDim)
        self.defc = nn.Linear(hiddenDim, inputDim)

    def encoder(self, x):
        return torch.sigmoid(self.enfc(x))

    def decoder(self, zHalf):
        return torch.sigmoid(self.defc(zHalf))

    def totolTrainOnce(self, trainDataList, g, lamda):
        g = torch.autograd.Variable(g, requires_grad=False)
        trainLoader = DataLoader(
            dataset=TensorDataset(trainDataList, g),
            batch_size=1,
            shuffle=True
        )
        for x, g in trainLoader:
            x = x.float()
            zHalf = self.encoder(x)
            z = self.decoder(zHalf)
        return z

class DGNet(nn.Module):
    def __init__(self, targetDim, hiddenDim, lr=0.001):
        super(DGNet, self).__init__()

        self.dgfc = nn.Linear(targetDim, hiddenDim)

    def degradation(self, h):
        return torch.sigmoid(self.dgfc(h))

    def totalTrainDgOnce(self, hList, zHalfList, lamda):
        hList = torch.autograd.Variable(hList, requires_grad=False)
        zHalfList = torch.autograd.Variable(zHalfList, requires_grad=False)
        trainLoader = DataLoader(
            dataset=TensorDataset(hList, zHalfList),
            batch_size=1,
            shuffle=True
        )
        for h, zHalf in trainLoader:
            g = self.degradation(h)
        return g

class Autoencoder(nn.Module):
    def __init__(self, dimList, targetDim, hiddenDim=100, preTrainLr=0.001,
                 aeTotleTrainLr=0.001, dgTotleTrainLr=0.001, lamda=1.0, HTrainLr=0.1):
        super(Autoencoder, self).__init__()

        self.viewNum = 0
        self.nSample = 1
        self.lamda = lamda
        self.HTrainLr = HTrainLr
        self.aeNetList = [AENet(d, hiddenDim, preTrainLr, aeTotleTrainLr).cuda() for d in dimList]
        self.dgNetList = [DGNet(targetDim, hiddenDim, dgTotleTrainLr).cuda() for d in dimList]
        self.H = nn.Parameter(torch.FloatTensor(np.random.uniform(0, 1, [self.nSample, targetDim])))

        self.input = []
        self.output = []

    def forward(self, trainDataList, nSample=1):
        # totleTrain
        self.nSample = nSample
        self.viewNum = len(trainDataList)  # 1
        # 1.Update aenets
        g = [dgnet.degradation(self.H) for dgnet in self.dgNetList]
        for v in range(self.viewNum):
            self.aeNetList[v].totolTrainOnce(trainDataList[v], g[v], self.lamda)

        # 2.Update dgnets&AE2
        for v in range(self.viewNum):
            zHalfList = self.aeNetList[v].encoder(trainDataList[v].float())
            # 2.1 Update denets
            self.dgNetList[v].totalTrainDgOnce(self.H, zHalfList, self.lamda)

            # 2.2 Update AE2
            tmpZHalfList = torch.autograd.Variable(zHalfList, requires_grad=False)
            trainLoader = DataLoader(
                dataset=TensorDataset(self.H, tmpZHalfList),
                batch_size=100,
                shuffle=True
            )
            for h, zHalf in trainLoader:
                self.input = zHalf
                self.output = self.dgNetList[v].degradation(h)

        return self.H, self.input, self.output

    def getH(self):
        return self.H

"""MDL-CPI model"""

class ABG(nn.Module):
    def __init__(self):
        super(ABG, self).__init__()

        self.Bert = BERT()
        self.GNN = GNN()
        self.Autoencoder = Autoencoder(dimList, dimOut)

        self.embed_fingerprint = nn.Embedding(n_fingerprint, dim)
        self.embed_word = nn.Embedding(n_word, dim)
        self.W_cnn = nn.ModuleList([nn.Conv2d(
            in_channels=1, out_channels=1, kernel_size=2 * window + 1,
            stride=1, padding=window) for _ in range(layer_cnn)])
        self.W_attention = nn.Linear(dim, dim)

        self.W_outChange = nn.ModuleList([nn.Linear(dimChange, dimChange)
                                          for _ in range(layer_output)])
        self.W_interactionChange = nn.Linear(dimChange, 2)

    def cnn(self, x, xs, layer):
        xs = torch.unsqueeze(torch.unsqueeze(xs, 0), 0)
        for i in range(layer):
            xs = torch.relu(self.W_cnn[i](xs))
        xs = torch.squeeze(torch.squeeze(xs, 0), 0)

        h = torch.relu(self.W_attention(x))
        hs = torch.relu(self.W_attention(xs))
        weights = torch.tanh(F.linear(h, hs))
        ys = torch.t(weights) * hs

        return torch.unsqueeze(torch.mean(ys, 0), 0)

    def forward(self, data, ifTrain=True):
        correct_interaction = data[-1]

        fingerprints, adjacency, words = data[:-1]

        """Compound vector with GNN."""
        fingerprint_vectors = self.embed_fingerprint(fingerprints)
        compound_vector = self.GNN(fingerprint_vectors, adjacency, layer_gnn)

        """update AE2"""
        fusion_vector, aeInput, aeOutput = self.Autoencoder([compound_vector])
        HTrainOptimizor = optim.Adam([self.Autoencoder.H], lr=lr_auto)
        loss = F.mse_loss(aeOutput, aeInput)
        HTrainOptimizor.zero_grad()
        loss = loss.requires_grad_()
        loss.backward()
        HTrainOptimizor.step()

        """Protein vector with BERT-CNN."""
        protein_vectors = self.Bert(words.unsqueeze(0))
        protein_vector = self.cnn(compound_vector, protein_vectors, layer_cnn)

        """update AE2"""
        fusion_vector, aeInput, aeOutput = self.Autoencoder([protein_vector])
        HTrainOptimizor = optim.Adam([self.Autoencoder.H], lr=lr_auto)
        loss = F.mse_loss(aeOutput, aeInput)
        HTrainOptimizor.zero_grad()
        loss = loss.requires_grad_()
        loss.backward()
        HTrainOptimizor.step()

        """Fusion vector with AE2."""
        # updated data
        with torch.no_grad():
            compound_vector = self.GNN(fingerprint_vectors, adjacency, layer_gnn)
            protein_vector = self.Bert(words.unsqueeze(0))
            fusion_vector = self.Autoencoder.getH()

        """Concatenate """
        cat_vector = torch.cat((compound_vector,
                                protein_vector, fusion_vector), 1)
        cat_vector = cat_vector.to(torch.float32)

        '''Predict Module'''
        for j in range(layer_output):
            cat_vector = torch.relu(self.W_outChange[j](cat_vector))
        interaction = self.W_interactionChange(cat_vector)

        if ifTrain:
            loss = F.cross_entropy(interaction, correct_interaction)
            return loss
        else:
            correct_labels = correct_interaction.to('cpu').data.numpy()
            ys = F.softmax(interaction, 1).to('cpu').data.numpy()
            predicted_labels = list(map(lambda x: np.argmax(x), ys))
            predicted_scores = list(map(lambda x: x[1], ys))
            return correct_labels, predicted_labels, predicted_scores

class Trainer(object):
    def __init__(self, model):
        self.model = model
        self.optimizer = optim.Adam(self.model.parameters(),
                                    lr=lr, weight_decay=weight_decay)

    def train(self, dataset):
        np.random.shuffle(dataset)
        N = len(dataset)
        loss_total = 0
        for data in dataset:
            loss = self.model(data)
            self.optimizer.zero_grad()
            loss = loss.requires_grad_()
            loss.backward()
            self.optimizer.step()
            loss_total += loss.to('cpu').data.numpy()

        return loss_total

class Tester(object):
    def __init__(self, model):
        self.model = model

    def test(self, dataset):
        N = len(dataset)
        T, Y, S = [], [], []
        with torch.no_grad():
            correct = 0
            total = 0
            for data in dataset:
                (correct_labels, predicted_labels,
                 predicted_scores) = self.model(data, False)
                correct += (predicted_labels == correct_labels).sum()
                total += len(correct_labels)
                T.append(correct_labels)
                Y.append(predicted_labels)
                S.append(predicted_scores)
            res = [T, Y, S]
            acc = correct / total
            AUC = roc_auc_score(T, S)
            precision = precision_score(T, Y)
            recall = recall_score(T, Y)
            tpr, fpr, _ = precision_recall_curve(T, S)
            PRC = auc(fpr, tpr)
        return AUC, PRC, precision, recall, acc, res

    def save_AUCs(self, AUCs, filename):
        with open(filename, 'a') as f:
            f.write('\t'.join(map(str, AUCs)) + '\n')

    def save_model(self, model, filename):
        torch.save(model.state_dict(), filename)

def load_tensor(file_name, dtype):
    return [dtype(d).to(device) for d in np.load(file_name + '.npy', allow_pickle=True)]

def load_datafile(file_name, ceng):
    csv_reader = csv.reader(open(file_name, encoding='utf-8'))
    newdata = []
    for row in csv_reader:
        newhang = []
        for d in row:
            newhang.append(float(d))
        x = []
        for i in range(ceng):
            x.append(newhang)
        newdata.append(x)

    tmp = np.array(newdata)
    return torch.from_numpy(tmp)

def load_npy_datalist(dir_input):
    compounds = load_tensor(dir_input + 'compounds', torch.LongTensor)
    adjacencies = load_tensor(dir_input + 'adjacencies', torch.FloatTensor)
    proteins = load_tensor(dir_input + 'proteins', torch.LongTensor)
    interactions = load_tensor(dir_input + 'interactions', torch.LongTensor)
    fingerprint_dict = load_pickle(dir_input + 'fingerprint_dict.pickle')
    word_dict = load_pickle(dir_input + 'word_dict.pickle')
    n_fingerprint = len(fingerprint_dict)
    n_word = len(word_dict)
    return compounds, adjacencies, proteins, interactions, \
           fingerprint_dict, word_dict, n_fingerprint, n_word

def load_pickle(file_name):
    with open(file_name, 'rb') as f:
        return pickle.load(f)

def shuffle_dataset(dataset, seed):
    np.random.seed(seed)
    np.random.shuffle(dataset)
    return dataset

def split_dataset(dataset, ratio):
    n = int(ratio * len(dataset))
    dataset_1, dataset_2 = dataset[:n], dataset[n:]
    return dataset_1, dataset_2

if __name__ == "__main__":

    """Hyperparameters."""
    (DATASET, radius, ngram, dim, layer_gnn, window, layer_cnn, layer_output,
     lr, lr_decay, decay_interval, weight_decay, iteration,
     setting) = sys.argv[1:]
    (dim, layer_gnn, window, layer_cnn, layer_output, decay_interval,
     iteration) = map(int, [dim, layer_gnn, window, layer_cnn, layer_output,
                            decay_interval, iteration])
    lr, lr_decay, weight_decay = map(float, [lr, lr_decay, weight_decay])

    dimList = [dim]
    global dimOut, lr_auto
    dimOut = 8
    lr_auto = 0.1
    dimChange = dim + dim + dimOut
    """ About """

    about = 'MDL-CPI'

    """CPU or GPU."""
    if torch.cuda.is_available():
        torch.cuda.set_device(0)
        print('|' + '\t' * 6 + 'torch.cuda.current_device:' + str(torch.cuda.current_device()))
        device = torch.device('cuda')
        print('|' + '\t' * 6 + 'The code uses GPU...')
    else:
        device = torch.device('cpu')
        print('|' + '\t' * 6 + 'The code uses CPU!!!')
    print('|' + '-' * 2 + 'MDL-CPI Hyperparameters setting OVER')

    """Load preprocessed data."""
    global n_word
    dir_input = 'xxxxxxxxxx/dataset/' + DATASET + '/input/radius2_ngram3/'
    compounds, adjacencies, proteins, interactions, \
    fingerprint_dict, word_dict, n_fingerprint, n_word = load_npy_datalist(dir_input)
    print('|' + '-' * 2 + 'MDL-CPI data load OVER')

    """Create a dataset and split it into train/dev/test..."""
    dataset = list(zip(compounds, adjacencies, proteins, interactions))
    dataset = shuffle_dataset(dataset, 1234)
    dataset_train, dataset_ = split_dataset(dataset, 0.8)
    dataset_dev, dataset_test = split_dataset(dataset_, 0.5)

    """Set a model."""
    torch.manual_seed(1234)
    model = ABG().to(device)
    trainer = Trainer(model)
    tester = Tester(model)

    """Output files."""
    file_AUCs = './output/result/'
    file_model = './output/model/'
    if not os.path.exists(file_AUCs):
        os.makedirs(file_AUCs)
    if not os.path.exists(file_model):
        os.makedirs(file_model)

    file_AUCs = './output/result/' + about + 'AUCs--' + setting + '.txt'
    file_model = './output/model/' + about + 'model_' + about + setting
    AUCs = 'Epoch\tTime(sec)\t\tLoss_train\t\t\tAUC_dev\t\t\tACC_dev\t\t\t' \
           'AUC\t\t\tPRC\t\t\tPrecision\t\t\tRecall\t\t\tACC'

    with open(file_AUCs, 'w') as f:
        f.write(AUCs + '\n')
    print('|' + '-' * 2 + 'MDL-CPI model setting OVER')

    """Start training."""
    print('|' + '-' * 2 + 'MDL-CPI train START')
    print('|' + '\t' * 6 + AUCs)
    start = timeit.default_timer()

    # TAO
    results = [[], [], []]
    for epoch in range(1, iteration):

        if epoch % decay_interval == 0:
            trainer.optimizer.param_groups[0]['lr'] *= lr_decay  # 在训练中动态的调整学习率

        loss_train = trainer.train(dataset_train)
        AUC_dev, PRC_dev, precision_dev, recall_dev, acc_dev, res = tester.test(dataset_dev)
        AUC_test, PRC_test, precision_test, recall_test, acc_test, res = tester.test(dataset_test)

        end = timeit.default_timer()
        time = end - start

        AUCs = [epoch, time, loss_train, AUC_dev, acc_dev,
                AUC_test, PRC_test, precision_test, recall_test, acc_test]

        tester.save_AUCs(AUCs, file_AUCs)
        tester.save_model(model, file_model)

        results[0].extend(res[0])
        results[1].extend(res[1])
        results[2].extend(res[2])

        print('|' + '\t' * 6 + '\t'.join(map(str, AUCs)))
    print('|' + '-' * 2 + 'MDL-CPI train END')

    print("results\n")
    print(results)

    print('|' + '-' * 2 + about + "ALL FINISH !!! ")


# -*- coding: utf-8 -*-
import urllib.request
import vlc,pafy
from bs4 import BeautifulSoup

def playVideo(str):
    textToSearch = str
    query = urllib.parse.quote(textToSearch)
    url = "https://www.youtube.com/results?search_query=" + query
    response = urllib.request.urlopen(url)
    html = response.read()
    soup = BeautifulSoup(html, 'html.parser')
    urls=[]
    for vid in soup.findAll(attrs={'class':'yt-uix-tile-link'}):
    #print('https://www.youtube.com' + vid['href'])
        urls.append('https://www.youtube.com' + vid['href'])

    url = urls[0]
    video = pafy.new(url)
    best = video.getbest()
    media= vlc.MediaPlayer(best.url)
    media.play()


"""Utility functions."""

from cgi import escape
import sys
import warnings

from zope.container.contained import notifyContainerModified
from zope.event import notify
from zope.lifecycleevent import ObjectMovedEvent

from Acquisition import aq_base, aq_inner, aq_parent
from App.Dialogs import MessageDialog
from OFS.event import ObjectWillBeMovedEvent
from OFS.CopySupport import sanity_check, CopyError
from ZODB.POSException import ConflictError

def unrestricted_move(self, ob):
    """Move an object from one container to another bypassing certain
    checks."""
    orig_id = ob.getId()
    if not ob.cb_isMoveable():
        raise CopyError('Not supported {}'.format(escape(orig_id)))

    try:
        ob._notifyOfCopyTo(self, op=1)
    except ConflictError:
        raise
    except:
        raise CopyError(MessageDialog(
            title="Move Error",
            message=sys.exc_info()[1],
            action='manage_main'))

    if not sanity_check(self, ob):
        raise CopyError("This object cannot be pasted into itself")

    orig_container = aq_parent(aq_inner(ob))
    if aq_base(orig_container) is aq_base(self):
        id = orig_id
    else:
        id = self._get_id(orig_id)

    notify(ObjectWillBeMovedEvent(ob, orig_container, orig_id,
                                  self, id))

    # try to make ownership explicit so that it gets carried
    # along to the new location if needed.
    ob.manage_changeOwnershipType(explicit=1)

    try:
        orig_container._delObject(orig_id, suppress_events=True)
    except TypeError:
        # BBB: removed in Zope 2.11
        orig_container._delObject(orig_id)
        warnings.warn(
            "%s._delObject without suppress_events is deprecated "
            "and will be removed in Zope 2.11." %
            orig_container.__class__.__name__, DeprecationWarning)
    ob = aq_base(ob)
    ob._setId(id)

    try:
        self._setObject(id, ob, set_owner=0, suppress_events=True)
    except TypeError:
        # BBB: removed in Zope 2.11
        self._setObject(id, ob, set_owner=0)
        warnings.warn(
            "%s._setObject without suppress_events is deprecated "
            "and will be removed in Zope 2.11." %
            self.__class__.__name__, DeprecationWarning)
    ob = self._getOb(id)

    notify(ObjectMovedEvent(ob, orig_container, orig_id, self, id))
    notifyContainerModified(orig_container)
    if aq_base(orig_container) is not aq_base(self):
        notifyContainerModified(self)

    ob._postCopy(self, op=1)
    # try to make ownership implicit if possible
    ob.manage_changeOwnershipType(explicit=0)

def getSavedAttrName(attrName):
    return '_old_%s' % attrName

def patch(context, originalAttrName, replacement):
    """ Default handler that preserves original method """
    OLD_NAME = getSavedAttrName(originalAttrName)
    if not hasattr(context, OLD_NAME):
        setattr(context, OLD_NAME, getattr(context, originalAttrName))
    setattr(context, originalAttrName, replacement)

def undoPatch(context, originalAttrName):
    OLD_NAME = getSavedAttrName(originalAttrName)
    setattr(context, originalAttrName, getattr(context, OLD_NAME))
    delattr(context, OLD_NAME)


import cv2
import face_recognition
import os
from keras.preprocessing import image

def load_image(image_path, grayscale=False, target_size=None):
    pil_image = image.load_img(image_path, grayscale, target_size)
    return image.img_to_array(pil_image)

def apply_offsets(face_coordinates, offsets):
    x, y, width, height = face_coordinates
    x_off, y_off = offsets
    return (x - x_off, x + width + x_off, y - y_off, y + height + y_off)

def output_text(men, women):
    if men == 1:
        print("1 man found")
    elif men > 1:
        print("%s men found" %(men))

    if women == 1:
        print("1 woman found")
    elif women > 1:
        print("%s women found" %(women))

def process_gallery(directory):

    encoded_faces = []
    file_paths = []

    # encodes face in each image of gallery
    for filename in os.listdir(directory):
        # checks for non_image files
        if filename.endswith(".jpg") or filename.endswith(".png"):
            try:
                #image = load_image(directory+'/'+filename)
                #image = image.astype('uint8')
                image = face_recognition.load_image_file(directory+'/'+filename)
                encoding = face_recognition.face_encodings(image)[0]
                encoded_faces.append(encoding)
                file_paths.append(filename)
                #print(filename, "processed")
            except:
                print("UNABLE TO PROCESS" , filename, "in gallery")
                continue
        else:
            print("UNABLE TO PROCESS", filename, "in gallery")

    return zip(file_paths, encoded_faces)

# returns CascadeClassifier object based on data from model_path (used for detection)
def load_detection_model(model_path):
    detection_model = cv2.CascadeClassifier(model_path)
    return detection_model

# uses CascadeClassifier object to detect faces
def detect_faces(detection_model, gray_image_array):
    return detection_model.detectMultiScale(gray_image_array, 1.3, 5)

# draws box on image using location of face; thickness of 2
def draw_bounding_box(face_coordinates, image_array, color):
    x, y, w, h = face_coordinates
    cv2.rectangle(image_array, (x, y), (x + w, y + h), color, 2)

def draw_text(coordinates, image_array, text, color, x_offset=0, y_offset=0,
                                                font_scale=2, thickness=2):
    x, y = coordinates[:2]
    cv2.putText(image_array, text, (x + x_offset, y + y_offset),
                cv2.FONT_HERSHEY_SIMPLEX,
                font_scale, color, thickness, cv2.LINE_AA)

def get_colors(num_classes):
    colors = plt.cm.hsv(np.linspace(0, 1, num_classes)).tolist()
    colors = np.asarray(colors) * 255
    return colors


"""Convenience functions for running common Picard utilities.
"""
import os

from bcbio.utils import curdir_tmpdir, file_exists
from bcbio.distributed.transaction import file_transaction

def picard_sort(picard, align_bam, sort_order="coordinate",
                out_file=None):
    """Sort a BAM file by coordinates.
    """
    base, ext = os.path.splitext(align_bam)
    if out_file is None:
        out_file = "%s-sort%s" % (base, ext)
    if not file_exists(out_file):
        with curdir_tmpdir() as tmp_dir:
            with file_transaction(out_file) as tx_out_file:
                opts = [("INPUT", align_bam),
                        ("OUTPUT", tx_out_file),
                        ("TMP_DIR", tmp_dir),
                        ("SORT_ORDER", sort_order)]
                picard.run("SortSam", opts)
    return out_file

def picard_merge(picard, in_files, out_file=None,
                 merge_seq_dicts=False):
    """Merge multiple BAM files together with Picard.
    """
    if out_file is None:
        out_file = "%smerge.bam" % os.path.commonprefix(in_files)
    if not file_exists(out_file):
        with curdir_tmpdir() as tmp_dir:
            with file_transaction(out_file) as tx_out_file:
                opts = [("OUTPUT", tx_out_file),
                        ("SORT_ORDER", "coordinate"),
                        ("MERGE_SEQUENCE_DICTIONARIES",
                         "true" if merge_seq_dicts else "false"),
                        ("TMP_DIR", tmp_dir)]
                for in_file in in_files:
                    opts.append(("INPUT", in_file))
                picard.run("MergeSamFiles", opts)
    return out_file

def picard_index(picard, in_bam):
    index_file = "%s.bai" % in_bam
    if not file_exists(index_file):
        with file_transaction(index_file) as tx_index_file:
            opts = [("INPUT", in_bam),
                    ("OUTPUT", tx_index_file)]
            picard.run("BuildBamIndex", opts)
    return index_file

def picard_index_ref(picard, ref_file):
    """Provide a Picard style dict index file for a reference genome.
    """
    dict_file = "%s.dict" % os.path.splitext(ref_file)[0]
    if not file_exists(dict_file):
        with file_transaction(dict_file) as tx_dict_file:
            opts = [("REFERENCE", ref_file),
                    ("OUTPUT", tx_dict_file)]
            picard.run("CreateSequenceDictionary", opts)
    return dict_file

def picard_fastq_to_bam(picard, fastq_one, fastq_two, out_dir,
                        platform, sample_name="", rg_name="", pu_name="",
                        qual_format=None):
    """Convert fastq file(s) to BAM, adding sample, run group and platform information.
    """
    qual_formats = {"illumina": "Illumina"}
    if qual_format is None:
        try:
            qual_format = qual_formats[platform.lower()]
        except KeyError:
            raise ValueError("Need to specify quality format for %s" % platform)
    out_bam = os.path.join(out_dir, "%s-fastq.bam" %
                           os.path.splitext(os.path.basename(fastq_one))[0])
    if not file_exists(out_bam):
        with curdir_tmpdir() as tmp_dir:
            with file_transaction(out_bam) as tx_out_bam:
                opts = [("FASTQ", fastq_one),
                        ("QUALITY_FORMAT", qual_format),
                        ("READ_GROUP_NAME", rg_name),
                        ("SAMPLE_NAME", sample_name),
                        ("PLATFORM_UNIT", pu_name),
                        ("PLATFORM", platform),
                        ("TMP_DIR", tmp_dir),
                        ("OUTPUT", tx_out_bam)]
                if fastq_two:
                    opts.append(("FASTQ2", fastq_two))
                picard.run("FastqToSam", opts)
    return out_bam

def picard_bam_to_fastq(picard, in_bam, fastq_one, fastq_two=None):
    """Convert BAM file to fastq.
    """
    if not file_exists(fastq_one):
        with curdir_tmpdir() as tmp_dir:
            with file_transaction(fastq_one) as tx_out1:
                opts = [("INPUT", in_bam),
                        ("FASTQ", tx_out1),
                        ("TMP_DIR", tmp_dir)]
                if fastq_two is not None:
                    opts += [("SECOND_END_FASTQ", fastq_two)]
                picard.run("SamToFastq", opts)
    return (fastq_one, fastq_two)

def picard_sam_to_bam(picard, align_sam, fastq_bam, ref_file,
                      is_paired=False):
    """Convert SAM to BAM, including unmapped reads from fastq BAM file.
    """
    if align_sam.endswith(".sam"):
        out_bam = "%s.bam" % os.path.splitext(align_sam)[0]
    elif align_sam.endswith("-align.bam"):
        out_bam = "%s.bam" % align_sam.replace("-align.bam", "")
    else:
        raise NotImplementedError("Input format not recognized")
    if not file_exists(out_bam):
        with curdir_tmpdir() as tmp_dir:
            with file_transaction(out_bam) as tx_out_bam:
                opts = [("UNMAPPED", fastq_bam),
                        ("ALIGNED", align_sam),
                        ("OUTPUT", tx_out_bam),
                        ("REFERENCE_SEQUENCE", ref_file),
                        ("TMP_DIR", tmp_dir),
                        ("PAIRED_RUN", ("true" if is_paired else "false")),
                        ]
                picard.run("MergeBamAlignment", opts)
    return out_bam

def picard_formatconverter(picard, align_sam):
    """Convert aligned SAM file to BAM format.
    """
    out_bam = "%s.bam" % os.path.splitext(align_sam)[0]
    if not file_exists(out_bam):
        with curdir_tmpdir() as tmp_dir:
            with file_transaction(out_bam) as tx_out_bam:
                opts = [("INPUT", align_sam),
                        ("OUTPUT", tx_out_bam)]
                picard.run("SamFormatConverter", opts)
    return out_bam

def picard_mark_duplicates(picard, align_bam, remove_dups=False):
    base, ext = os.path.splitext(align_bam)
    base = base.replace(".", "-")
    dup_bam = "%s-dup%s" % (base, ext)
    dup_metrics = "%s-dup.dup_metrics" % base
    if not file_exists(dup_bam):
        with curdir_tmpdir() as tmp_dir:
            with file_transaction(dup_bam, dup_metrics) as (tx_dup_bam, tx_dup_metrics):
                opts = [("INPUT", align_bam),
                        ("OUTPUT", tx_dup_bam),
                        ("TMP_DIR", tmp_dir),
                        ("REMOVE_DUPLICATES", "true" if remove_dups else "false"),
                        ("METRICS_FILE", tx_dup_metrics)]
                picard.run("MarkDuplicates", opts)
    return dup_bam, dup_metrics

def picard_fixmate(picard, align_bam):
    """Run Picard's FixMateInformation generating an aligned output file.
    """
    base, ext = os.path.splitext(align_bam)
    out_file = "%s-sort%s" % (base, ext)
    if not file_exists(out_file):
        with curdir_tmpdir() as tmp_dir:
            with file_transaction(out_file) as tx_out_file:
                opts = [("INPUT", align_bam),
                        ("OUTPUT", tx_out_file),
                        ("TMP_DIR", tmp_dir),
                        ("SORT_ORDER", "coordinate")]
                picard.run("FixMateInformation", opts)
    return out_file


"""Example of converting Parquet files to SQLite database."""

import os.path

from graphnet.constants import EXAMPLE_OUTPUT_DIR, TEST_PARQUET_DATA
from graphnet.data.utilities.parquet_to_sqlite import ParquetToSQLiteConverter
from graphnet.utilities.argparse import ArgumentParser
from graphnet.utilities.logging import get_logger

logger = get_logger()

def main(parquet_path: str, mc_truth_table: str) -> None:
    """Run example."""
    # Path to where you want the database to be stored
    outdir = f"{EXAMPLE_OUTPUT_DIR}/convert_parquet_to_sqlite/"

    # Name of the database.
    # Will be saved in {outdir}/{database_name}/data/{database_name}.db
    database_name = parquet_path.split("/")[-1].split(".")[0]
    output_path = f"{outdir}/{database_name}/data/{database_name}.db"

    if os.path.exists(output_path):
        logger.error(
            f"Output database {output_path} already exists. The conversion "
            "will likely fail. If so, please remove the output database "
            "before running this script again."
        )

    converter = ParquetToSQLiteConverter(
        mc_truth_table=mc_truth_table,
        parquet_path=parquet_path,
    )
    converter.run(outdir=outdir, database_name=database_name)

if __name__ == "__main__":

    # Parse command-line arguments
    parser = ArgumentParser(
        description="""
Convert Parquet files to SQLite database.
"""
    )

    parser.add_argument(
        "--parquet-path",
        action="store",
        help="Path to Parquet file (default: %(default)s)",
        default=TEST_PARQUET_DATA,
    )
    parser.add_argument(
        "--mc-truth-table",
        action="store",
        help="Name of MC truth table in Parquet file (default: %(default)s)",
        default="truth",
    )

    args = parser.parse_args()

    main(args.parquet_path, args.mc_truth_table)


# -*- coding: utf-8 -*-
"""
Created on Tue Dec 13 16:40:18 2016

@author: fmoret
"""
import os
import gurobipy as gb
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
dd1 = 'H:/Google Drive/DTU/special course/Chiara'
dd2 = 'H:/Google Drive/DTU/special course/Chiara/Input Data 2'
os.chdir(dd1)

#%%
os.chdir(dd2)
import shelve
filename='input_data_2.out'
d = shelve.open(filename, 'r')
el_price = d['tot_el_price'][0::2]/1000
b2 = d['b2']        # questi sono i coefficienti dei costi/utilities - quadratic function
c2 = d['c2']        # 2 si riferisce ai consumers, 1 ai generators
b1 = d['b1']
c1 = d['c1']
Pmin = d['Pmin']
Pmax = d['Pmax']
PV = d['PV']       # non mi carica il PV
Load = d['Load']
Flex_load = d['Flex_load']
Agg_load = Load + Flex_load
PostCode = d['PostCode']

os.chdir(dd1)
n = b2.shape[1]
g = b1.shape[1]
TMST = 48#b2.shape[0]

Lmin = - (Agg_load + Flex_load)
Lmax = - Load
el_price_e = el_price
tau = 0.1
window = 4

y0_c = 0.01 + b2 - c2*(Lmax+Lmin)/(Lmax-Lmin)
mm_c = 2*c2/(Lmax-Lmin)
if sum(abs(mm_c[np.isinf(mm_c)]))>0:    # se trova degli inf
    y0_c[np.isinf(abs(mm_c))] = 0.01 + b2[np.isinf(abs(mm_c))]  # porta questo a 0.01 + b2
    mm_c[np.isinf(abs(mm_c))] = 0                               # e questo a 0

y0_g = 0.01 + b1 - c1*(Pmax+Pmin)/(Pmax-Pmin)
mm_g = 2*c1/(Pmax-Pmin)
if sum(abs(mm_g[np.isinf(mm_g)]))>0:
    y0_g[np.isinf(abs(mm_g))] = 0.01 + b1[np.isinf(abs(mm_g))]
    mm_g[np.isinf(abs(mm_g))] = 0
y0_g[np.isnan(y0_g)] = 0        # se non produco il mio costo è 0
mm_g[np.isnan(mm_g)] = 0

#%% Community CENTRALIZED solution
CT_p_sol = np.zeros((g,TMST))
CT_l_sol = np.zeros((n,TMST))
CT_q_sol = np.zeros((n,TMST))
CT_alfa_sol = np.zeros((n,TMST))
CT_beta_sol = np.zeros((n,TMST))
CT_imp_sol = np.zeros(TMST)
CT_exp_sol = np.zeros(TMST)
CT_obj_sol = np.zeros(TMST)
CT_price_sol = np.zeros((n,TMST))
CT_price2_sol = np.zeros((3,TMST))

for t in np.arange(0,TMST,24):  # for t = 0, 24
    temp = range(t,t+24)
    # Create a new model
    CT_m = gb.Model("qp")
    CT_m.setParam( 'OutputFlag', False ) # Quieting Gurobi output
    # Create variables
    p = np.array([CT_m.addVar(lb=Pmin[i]+PV[t+k,i], ub=Pmax[i]+PV[t+k,i]) for i in range(n) for k in range(24)])
    l = np.array([CT_m.addVar(lb=Lmin[t+k,i], ub=Lmax[t+k,i]) for i in range(n) for k in range(24)])
    q_imp = np.array([CT_m.addVar() for k in range(24)])
    q_exp = np.array([CT_m.addVar() for k in range(24)])
    alfa = np.array([CT_m.addVar() for i in range(n) for k in range(24)])
    beta = np.array([CT_m.addVar() for i in range(n) for k in range(24)])
    q_pos = np.array([CT_m.addVar() for i in range(n) for k in range(24)])
    q = np.array([CT_m.addVar(lb = -gb.GRB.INFINITY) for i in range(n) for k in range(24)]) # curiosità: perché il lb a -inf
    gamma_i = (el_price_e[temp] + 0.1)
    gamma_e = -el_price_e[temp]
    CT_m.update()

    p = np.transpose(p.reshape(n,24))
    l = np.transpose(l.reshape(n,24))
    q = np.transpose(q.reshape(n,24))
    q_pos = np.transpose(q_pos.reshape(n,24))
    alfa = np.transpose(alfa.reshape(n,24))
    beta = np.transpose(beta.reshape(n,24))

    # Set objective:
    obj = (sum(sum(y0_c[temp,:]*l + mm_c[temp,:]/2*l*l) + sum(y0_g[temp,:]*p + mm_g[temp,:]/2*p*p))
           + sum(gamma_i*q_imp + gamma_e*q_exp) + sum(0.001*sum(q_pos)))
    # doppia sommatoria:
    # la somma interna è sulle colonne, quindi da 15x24 si passa a 24
    # quindi somma sui prosumer
    # la somma esterna somma tutti gli elementi dell'array
    # quindi somma sulle 24 ore --> un giorno
    # discorso simile per le altre sommatorie
    # l'objective è minimizzare il totale di un giorno

    CT_m.setObjective(obj)

    # Add constraint
    for k in range(24):
        CT_m.addConstr(sum(q[k,:]) == 0, name="comm[%s]"%(k)) #somma sui prosumer
        #what about mettere una variabile invece che 0? da minimizzare poi nell'obj
        for i in range(n): #balance per ogni prosumer, ogni ora
            CT_m.addConstr(p[k,i] + l[k,i] + q[k,i] + alfa[k,i] - beta[k,i] == 0, name="pros[%s,%s]"% (k,i))
            CT_m.addConstr(q[k,i] <= q_pos[k,i]) #limite sulla q, che può essere pos o neg
            CT_m.addConstr(q[k,i] >= -q_pos[k,i])
        CT_m.addConstr(sum(alfa[k,:]) - q_imp[k] == 0, name="imp_bal[%s]"%(k))
        CT_m.addConstr(sum(beta[k,:]) - q_exp[k] == 0, name="exp_bal[%s]"%(k))
    for i in range(n): #nell'arco di tutto il giorno i conti sul carico devono tornare
    #per ogni prosumer, ma l'ottimizzazione è fatta ora per ora
        CT_m.addConstr(sum(Agg_load[temp,i] + l[:,i]) == 0)
#        for j in np.arange(0,24,window):
#            CT_m.addConstr(sum(Agg_load[range(t+j,t+j+window),i] + l[range(j,j+window),i]) == 0)
    CT_m.update()

    CT_m.optimize()
    for k in range(24):
        for i in range(n):
            CT_price_sol[i,t+k] = CT_m.getConstrByName("pros[%s,%s]"%(k,i)).Pi
            CT_p_sol[i,t+k] = p[k,i].x
            CT_l_sol[i,t+k] = l[k,i].x
            CT_q_sol[i,t+k] = q[k,i].x
            CT_alfa_sol[i,t+k] = alfa[k,i].x
            CT_beta_sol[i,t+k] = beta[k,i].x
        CT_price2_sol[0,t+k] = CT_m.getConstrByName("comm[%s]"%k).Pi
        CT_price2_sol[1,t+k] = CT_m.getConstrByName("imp_bal[%s]"%k).Pi
        CT_price2_sol[2,t+k] = CT_m.getConstrByName("exp_bal[%s]"%k).Pi
        CT_imp_sol[t+k] = q_imp[k].x
        CT_exp_sol[t+k] = q_exp[k].x
# http://www.gurobi.com/documentation/7.5/refman/attributes.html
    del CT_m

CT_IE_sol = CT_imp_sol - CT_exp_sol

##crea immagini
#for k in range(3):
#    prosumers = ['pros%k']
#    style = ['r','g','y',]
#    plt.plot(range(48), CT_p_sol[k,:] )
#    legend()
#
#d={}
#a=np.empty(9)
#for x in range(1,10):
#       a[x]=d["string{0}".format(x)]

#%% ADMM optimisation via master-sub classes
from ADMM_master import ADMM_Master
o = 0.01
e = 0.00001
asynch = -100
weight = 1/n

#% Cost of Import/Export not considered ==> case = 0
Mast = ADMM_Master(b1, c1, Pmin, Pmax, PV, b2, c2, Load, Flex_load, tau, el_price_e, o, e, TMST, window, 0, asynch)
ADMM_summary = Mast.results
ADMM_prices = Mast.prices
ADMM_flag = Mast.flag

#%%
max_l = abs(Mast.variables.l_k - np.transpose(CT_l_sol)).max()
max_p = abs(Mast.variables.p_k - np.transpose(CT_p_sol)).max()
max_q = abs(Mast.variables.q_k - np.transpose(CT_q_sol)).max()
max_alfa = abs(Mast.variables.alfa_k - np.transpose(CT_alfa_sol)).max()
max_beta = abs(Mast.variables.beta_k - np.transpose(CT_beta_sol)).max()
l_1 = Mast.variables.l_k
p_1 = Mast.variables.p_k
q_1 = Mast.variables.q_k
q_pos_1 = Mast.variables.q_pos_k
alfa_1 = Mast.variables.alfa_k
beta_1 = Mast.variables.beta_k
imp_1 = alfa_1.sum(axis=1)
exp_1 = beta_1.sum(axis=1)
ie_1 = imp_1-exp_1

opt1 = np.empty(TMST)
ooo = np.empty(TMST)
for i1 in range(TMST):
    opt1[i1] = (sum(y0_c[i1,:]*l_1[i1,:] + mm_c[i1,:]/2*l_1[i1,:]*l_1[i1,:]) + sum(y0_g[i1,:]*p_1[i1,:] + mm_g[i1,:]/2*p_1[i1,:]*p_1[i1,:]) #+ el_price_e[i1]*ie_1[i1]
                + 0.001*sum(abs(q_1[i1,:])) + (el_price_e[i1]+0.1)*sum(alfa_1[i1,:]) - el_price_e[i1]*sum(beta_1[i1,:]))
    ooo[i1] = (sum(y0_c[i1,:]*CT_l_sol[:,i1] + mm_c[i1,:]/2*CT_l_sol[:,i1]*CT_l_sol[:,i1]) + sum(y0_g[i1,:]*CT_p_sol[:,i1] + mm_g[i1,:]/2*CT_p_sol[:,i1]*CT_p_sol[:,i1]) +
                (el_price_e[i1]+0.1)*CT_imp_sol[i1] - el_price_e[i1]*CT_exp_sol[i1] + 0.001*sum(abs(CT_q_sol[:,i1]))) #+ pr_i*sum(CT_alfa_sol[:,i1]) + pr_e*sum(CT_beta_sol[:,i1]))

gap_opt1 = opt1-CT_obj_sol
gap_opt12 = opt1-ooo

#%% Save Results
#import shelve
#filename='Res_14_07_1.out'
#var_2_save = ['ADMM_summary','ADMM_prices','ADMM_flag','l_1','p_1','q_1','alfa_1','beta_1']
#if os.path.exists(filename+'.dat'):
#    print('ERROR - file already existing!')
#else:
#    my_shelf = shelve.open(filename,flag = 'n') # 'n' for new
#    for key in var_2_save:
#        try:
#            my_shelf[key] = globals()[key]
#        except TypeError:
#            #
#            # __builtins__, my_shelf, and imported modules can not be shelved.
#            #
#            print(key)
#    my_shelf.close()
#
##%% Community Trading
#CT2_p_sol = np.zeros((g,TMST))
#CT2_l_sol = np.zeros((n,TMST))
#CT2_q_sol = np.zeros((n,TMST))
#CT2_qcomm_sol = np.zeros((3,TMST))
#CT2_alfa_sol = np.zeros((n,TMST))
#CT2_beta_sol = np.zeros((n,TMST))
#CT2_imp_sol = np.zeros(TMST)
#CT2_exp_sol = np.zeros(TMST)
#CT2_obj_sol = np.zeros(TMST)
#CT2_price_sol = np.zeros((n,TMST))
#CT2_price2_sol = np.zeros((2,TMST))
#CT2_price3_sol = np.zeros((3,TMST))
#
#for t in np.arange(0,TMST,24):
#    temp = range(t,t+24)
#    # Create a new model
#    CT2_m = gb.Model("qp")
#    CT2_m.setParam( 'OutputFlag', False )
#    # Create variables
#    p = np.array([CT2_m.addVar(lb=Pmin[i]+PV[t+k,i], ub=Pmax[i]+PV[t+k,i]) for i in range(n) for k in range(24)])
#    l = np.array([CT2_m.addVar(lb=Lmin[t+k,i], ub=Lmax[t+k,i]) for i in range(n) for k in range(24)])
#    q_imp = np.array([CT2_m.addVar() for k in range(24)])
#    q_exp = np.array([CT2_m.addVar() for k in range(24)])
#    alfa = np.array([CT2_m.addVar() for i in range(n) for k in range(24)])
#    beta = np.array([CT2_m.addVar() for i in range(n) for k in range(24)])
#    q_pos = np.array([CT2_m.addVar() for i in range(n) for k in range(24)])
#    q = np.array([CT2_m.addVar(lb = -gb.GRB.INFINITY) for i in range(n) for k in range(24)])
#    q_12 = np.array([CT2_m.addVar() for k in range(24)])
#    q_13 = np.array([CT2_m.addVar() for k in range(24)])
#    q_23 = np.array([CT2_m.addVar() for k in range(24)])
#    q_cpp = np.array([CT2_m.addVar() for i in range(3) for k in range(24)])
#    gamma_i = (el_price_e[temp] + 0.1)
#    gamma_e = -el_price_e[temp]
#    gamma_12 = 0.03
#    gamma_23 = 0.05
#    gamma_13 = 0.06
#    gamma_geo = np.array([gamma_12,gamma_13,gamma_23])
#    CT2_m.update()
#
#    p = np.transpose(p.reshape(n,24))
#    l = np.transpose(l.reshape(n,24))
#    q = np.transpose(q.reshape(n,24))
#    q_pos = np.transpose(q_pos.reshape(n,24))
#    q_cpp = np.transpose(q_cpp.reshape(3,24))
#    alfa = np.transpose(alfa.reshape(n,24))
#    beta = np.transpose(beta.reshape(n,24))
#
#    # Set objective:
#    obj = (sum(sum(y0_c[temp,:]*l + mm_c[temp,:]/2*l*l) + sum(y0_g[temp,:]*p + mm_g[temp,:]/2*p*p))
#           + sum(gamma_i*q_imp + gamma_e*q_exp) + sum(q_cpp[:,0]*gamma_geo[0]+q_cpp[:,1]*gamma_geo[1]+q_cpp[:,2]*gamma_geo[2]) + sum(0.001*sum(q_pos)))
#    CT2_m.setObjective(obj)
#    # Add constraint
#    for k in range(24):
#        CT2_m.addConstr(sum(q[k,range(0,5)]) - q_12[k] - q_13[k] == 0, name="comm1[%s]"%(k))
#        CT2_m.addConstr(sum(q[k,range(5,10)]) + q_12[k] - q_23[k] == 0, name="comm2[%s]"%(k))
#        CT2_m.addConstr(sum(q[k,range(10,15)]) + q_13[k] + q_23[k] == 0, name="comm3[%s]"%(k))
#        for i in range(n):
#            CT2_m.addConstr(p[k,i] + l[k,i] + q[k,i] + alfa[k,i] - beta[k,i] == 0, name="pros[%s,%s]"% (k,i))
#            CT2_m.addConstr(q[k,i] <= q_pos[k,i])
#            CT2_m.addConstr(q[k,i] >= -q_pos[k,i])
#        CT2_m.addConstr(sum(alfa[k,:]) - q_imp[k] == 0, name="imp_bal[%s]"%(k))
#        CT2_m.addConstr(sum(beta[k,:]) - q_exp[k] == 0, name="exp_bal[%s]"%(k))
#        CT2_m.addConstr(q_12[k] <= q_cpp[k,0])
#        CT2_m.addConstr(q_12[k] >= -q_cpp[k,0])
#        CT2_m.addConstr(q_13[k] <= q_cpp[k,1])
#        CT2_m.addConstr(q_13[k] >= -q_cpp[k,1])
#        CT2_m.addConstr(q_23[k] <= q_cpp[k,2])
#        CT2_m.addConstr(q_23[k] >= -q_cpp[k,2])
#    for i in range(n):
#        CT2_m.addConstr(sum(Agg_load[temp,i] + l[:,i]) == 0)
##        for j in np.arange(0,24,window):
##            CT5_m.addConstr(sum(Agg_load[range(t+j,t+j+window),i] + l[range(j,j+window),i]) == 0)
#    CT2_m.update()
#
#    CT2_m.optimize()
#    for k in range(24):
#        for i in range(n):
#            CT2_price_sol[i,t+k] = CT2_m.getConstrByName("pros[%s,%s]"%(k,i)).Pi
#            CT2_p_sol[i,t+k] = p[k,i].x
#            CT2_l_sol[i,t+k] = l[k,i].x
#            CT2_q_sol[i,t+k] = q[k,i].x
#            CT2_alfa_sol[i,t+k] = alfa[k,i].x
#            CT2_beta_sol[i,t+k] = beta[k,i].x
#        CT2_price2_sol[0,t+k] = CT2_m.getConstrByName("imp_bal[%s]"%k).Pi
#        CT2_price2_sol[1,t+k] = CT2_m.getConstrByName("exp_bal[%s]"%k).Pi
#        CT2_price3_sol[0,t+k] = CT2_m.getConstrByName("comm1[%s]"%(k)).Pi
#        CT2_price3_sol[1,t+k] = CT2_m.getConstrByName("comm2[%s]"%(k)).Pi
#        CT2_price3_sol[2,t+k] = CT2_m.getConstrByName("comm3[%s]"%(k)).Pi
#        CT2_imp_sol[t+k] = q_imp[k].x
#        CT2_exp_sol[t+k] = q_exp[k].x
#        CT2_qcomm_sol[0,t+k] = q_12[k].x
#        CT2_qcomm_sol[1,t+k] = q_13[k].x
#        CT2_qcomm_sol[2,t+k] = q_23[k].x
#
#    del CT2_m
#
#CT2_IE_sol = CT2_imp_sol - CT2_exp_sol
#
##%% ADMM optimisation via master-sub classes
#from ADMM_master_geo3Z import ADMM_Master
#o = 0.01
#e = 0.00001
#asynch = -100
#weight = 1/n
#
#gamma_12 = 0.03
#gamma_13 = 0.06
#gamma_23 = 0.05
#gamma_geo = np.array([gamma_12,gamma_13,gamma_23])
#
#
#Mast2 = ADMM_Master(b1, c1, Pmin, Pmax, PV, b2, c2, Load, Flex_load, tau, el_price_e, o, e, TMST, window, 0, asynch, gamma_geo)
#ADMM_summary2 = Mast2.results
#ADMM_prices2 = Mast2.prices
#ADMM_flag2 = Mast2.flag
#
##%%
#max_l_2 = abs(Mast2.variables.l_k - np.transpose(CT2_l_sol)).max()
#max_p_2 = abs(Mast2.variables.p_k - np.transpose(CT2_p_sol)).max()
#max_q_2 = abs(Mast2.variables.q_k - np.transpose(CT2_q_sol)).max()
#max_alfa_2 = abs(Mast2.variables.alfa_k - np.transpose(CT2_alfa_sol)).max()
#max_beta_2 = abs(Mast2.variables.beta_k - np.transpose(CT2_beta_sol)).max()
#l_2 = Mast2.variables.l_k
#p_2 = Mast2.variables.p_k
#q_2 = Mast2.variables.q_k
#alfa_2 = Mast2.variables.alfa_k
#beta_2 = Mast2.variables.beta_k
#q2_com = Mast2.variables.pow_comm
#
#imp_2 = alfa_2.sum(axis=1)
#exp_2 = beta_2.sum(axis=1)
#ie_2 = imp_2-exp_2
#
#opt2 = np.empty(TMST)
#ooo2= np.empty(TMST)
#for i1 in range(TMST):
#    opt2[i1] = (sum(y0_c[i1,:]*l_2[i1,:] + mm_c[i1,:]/2*l_2[i1,:]*l_2[i1,:]) + sum(y0_g[i1,:]*p_2[i1,:] + mm_g[i1,:]/2*p_2[i1,:]*p_2[i1,:]) #+ el_price_e[i1]*ie_1[i1]
#                + 0.001*sum(abs(q_2[i1,:])) + (el_price_e[i1]+0.1)*sum(alfa_2[i1,:]) - el_price_e[i1]*sum(beta_2[i1,:]) + sum(gamma_geo*abs(q2_com[i1,:])))
#    ooo2[i1] = (sum(y0_c[i1,:]*CT2_l_sol[:,i1] + mm_c[i1,:]/2*CT2_l_sol[:,i1]*CT2_l_sol[:,i1]) + sum(y0_g[i1,:]*CT2_p_sol[:,i1] + mm_g[i1,:]/2*CT2_p_sol[:,i1]*CT2_p_sol[:,i1]) +
#                (el_price_e[i1]+0.1)*CT2_imp_sol[i1] - el_price_e[i1]*CT2_exp_sol[i1] + 0.001*sum(abs(CT2_q_sol[:,i1]))  + sum(gamma_geo*abs(CT2_qcomm_sol[:,i1]))) #+ pr_i*sum(CT_alfa_sol[:,i1]) + pr_e*sum(CT_beta_sol[:,i1]))
#
#gap_opt2 = opt2-CT2_obj_sol
#gap_opt22 = opt2-ooo2
#
##%% Save Results
#import shelve
#filename='Res_14_07_2.out'
#var_2_save = ['ADMM_summary2','ADMM_prices2','ADMM_flag2','l_2','p_2','q_2','alfa_2','beta_2','q2_com']
#if os.path.exists(filename+'.dat'):
#    print('ERROR - file already existing!')
#else:
#    my_shelf = shelve.open(filename,flag = 'n') # 'n' for new
#    for key in var_2_save:
#        try:
#            my_shelf[key] = globals()[key]
#        except TypeError:
#            #
#            # __builtins__, my_shelf, and imported modules can not be shelved.
#            #
#            print(key)
#    my_shelf.close()
#
##%% Community Trading
#CT3_p_sol = np.zeros((g,TMST))
#CT3_l_sol = np.zeros((n,TMST))
#CT3_q_sol = np.zeros((n,TMST))
#CT3_qcomm_sol = np.zeros(TMST)
#CT3_alfa_sol = np.zeros((n,TMST))
#CT3_beta_sol = np.zeros((n,TMST))
#CT3_imp_sol = np.zeros(TMST)
#CT3_exp_sol = np.zeros(TMST)
#CT3_obj_sol = np.zeros(TMST)
#CT3_price_sol = np.zeros((n,TMST))
#CT3_price2_sol = np.zeros((2,TMST))
#CT3_price3_sol = np.zeros((3,TMST))
#
#for t in np.arange(0,TMST,24):
#    temp = range(t,t+24)
#    # Create a new model
#    CT3_m = gb.Model("qp")
#    CT3_m.setParam( 'OutputFlag', False )
#    # Create variables
#    p = np.array([CT3_m.addVar(lb=Pmin[i]+PV[t+k,i], ub=Pmax[i]+PV[t+k,i]) for i in range(n) for k in range(24)])
#    l = np.array([CT3_m.addVar(lb=Lmin[t+k,i], ub=Lmax[t+k,i]) for i in range(n) for k in range(24)])
#    q_imp = np.array([CT3_m.addVar() for k in range(24)])
#    q_exp = np.array([CT3_m.addVar() for k in range(24)])
#    alfa = np.array([CT3_m.addVar() for i in range(n) for k in range(24)])
#    beta = np.array([CT3_m.addVar() for i in range(n) for k in range(24)])
#    q_pos = np.array([CT3_m.addVar() for i in range(n) for k in range(24)])
#    q = np.array([CT3_m.addVar(lb = -gb.GRB.INFINITY) for i in range(n) for k in range(24)])
#    q_12 = np.array([CT3_m.addVar() for k in range(24)])
#    q_cpp = np.array([CT3_m.addVar() for k in range(24)])
#    gamma_i = (el_price_e[temp] + 0.1)
#    gamma_e = -el_price_e[temp]
#    gamma_12 = 0.03
#    CT3_m.update()
#
#    p = np.transpose(p.reshape(n,24))
#    l = np.transpose(l.reshape(n,24))
#    q = np.transpose(q.reshape(n,24))
#    q_pos = np.transpose(q_pos.reshape(n,24))
#    alfa = np.transpose(alfa.reshape(n,24))
#    beta = np.transpose(beta.reshape(n,24))
#
#    # Set objective:
#    obj = (sum(sum(y0_c[temp,:]*l + mm_c[temp,:]/2*l*l) + sum(y0_g[temp,:]*p + mm_g[temp,:]/2*p*p))
#           + sum(gamma_i*q_imp + gamma_e*q_exp) + sum(gamma_12*q_cpp) + sum(0.001*sum(q_pos)))
#    CT3_m.setObjective(obj)
#    # Add constraint
#    for k in range(24):
#        CT3_m.addConstr(sum(q[k,range(0,10)]) - q_12[k] == 0, name="comm1[%s]"%(k))
#        CT3_m.addConstr(sum(q[k,range(10,15)]) + q_12[k] == 0, name="comm2[%s]"%(k))
#        for i in range(n):
#            CT3_m.addConstr(p[k,i] + l[k,i] + q[k,i] + alfa[k,i] - beta[k,i] == 0, name="pros[%s,%s]"% (k,i))
#            CT3_m.addConstr(q[k,i] <= q_pos[k,i])
#            CT3_m.addConstr(q[k,i] >= -q_pos[k,i])
#        CT3_m.addConstr(sum(alfa[k,:]) - q_imp[k] == 0, name="imp_bal[%s]"%(k))
#        CT3_m.addConstr(sum(beta[k,:]) - q_exp[k] == 0, name="exp_bal[%s]"%(k))
#        CT3_m.addConstr(q_12[k] <= q_cpp[k])
#        CT3_m.addConstr(q_12[k] >= -q_cpp[k])
#    for i in range(n):
#        CT3_m.addConstr(sum(Agg_load[temp,i] + l[:,i]) == 0)
##        for j in np.arange(0,24,window):
##            CT5_m.addConstr(sum(Agg_load[range(t+j,t+j+window),i] + l[range(j,j+window),i]) == 0)
#    CT3_m.update()
#
#    CT3_m.optimize()
#    for k in range(24):
#        for i in range(n):
#            CT3_price_sol[i,t+k] = CT3_m.getConstrByName("pros[%s,%s]"%(k,i)).Pi
#            CT3_p_sol[i,t+k] = p[k,i].x
#            CT3_l_sol[i,t+k] = l[k,i].x
#            CT3_q_sol[i,t+k] = q[k,i].x
#            CT3_alfa_sol[i,t+k] = alfa[k,i].x
#            CT3_beta_sol[i,t+k] = beta[k,i].x
#        CT3_price2_sol[0,t+k] = CT3_m.getConstrByName("imp_bal[%s]"%k).Pi
#        CT3_price2_sol[1,t+k] = CT3_m.getConstrByName("exp_bal[%s]"%k).Pi
#        CT3_price3_sol[0,t+k] = CT3_m.getConstrByName("comm1[%s]"%(k)).Pi
#        CT3_price3_sol[1,t+k] = CT3_m.getConstrByName("comm2[%s]"%(k)).Pi
#        CT3_imp_sol[t+k] = q_imp[k].x
#        CT3_exp_sol[t+k] = q_exp[k].x
#        CT3_qcomm_sol[t+k] = q_12[k].x
#
#    del CT3_m
#
#CT3_IE_sol = CT3_imp_sol - CT3_exp_sol
#sum_q = CT3_q_sol.sum(axis=0)
#
##%% ADMM optimisation via master-sub classes
#from ADMM_master_geo2Z import ADMM_Master
#o = 0.01
#e = 0.00001
#asynch = -100
#weight = 1/n
#
#gamma_12 = 0.03
#gamma_13 = 0.06
#gamma_23 = 0.05
#gamma_geo = gamma_12 #np.array([gamma_12,gamma_13,gamma_23])
#
#
#Mast3 = ADMM_Master(b1, c1, Pmin, Pmax, PV, b2, c2, Load, Flex_load, tau, el_price_e, o, e, TMST, window, 0, asynch, gamma_geo)
#ADMM_summary3 = Mast3.results
#ADMM_prices3 = Mast3.prices
#ADMM_flag3 = Mast3.flag
#
##%%
#max_l_3 = abs(Mast3.variables.l_k - np.transpose(CT3_l_sol)).max()
#max_p_3 = abs(Mast3.variables.p_k - np.transpose(CT3_p_sol)).max()
#max_q_3 = abs(Mast3.variables.q_k - np.transpose(CT3_q_sol)).max()
#max_alfa_3 = abs(Mast3.variables.alfa_k - np.transpose(CT3_alfa_sol)).max()
#max_beta_3 = abs(Mast3.variables.beta_k - np.transpose(CT3_beta_sol)).max()
#l_3 = Mast3.variables.l_k
#p_3 = Mast3.variables.p_k
#q_3 = Mast3.variables.q_k
#alfa_3 = Mast3.variables.alfa_k
#beta_3 = Mast3.variables.beta_k
#q3_com = Mast3.variables.pow_comm
#
#imp_3 = alfa_3.sum(axis=1)
#exp_3 = beta_3.sum(axis=1)
#ie_3 = imp_3-exp_3
#
#opt3 = np.empty(TMST)
#ooo3= np.empty(TMST)
#for i1 in range(TMST):
#    opt3[i1] = (sum(y0_c[i1,:]*l_3[i1,:] + mm_c[i1,:]/2*l_3[i1,:]*l_3[i1,:]) + sum(y0_g[i1,:]*p_3[i1,:] + mm_g[i1,:]/2*p_3[i1,:]*p_3[i1,:]) #+ el_price_e[i1]*ie_1[i1]
#                + 0.001*sum(abs(q_3[i1,:])) + (el_price_e[i1]+0.1)*sum(alfa_3[i1,:]) - el_price_e[i1]*sum(beta_3[i1,:]) + gamma_geo*abs(q3_com[i1]))
#    ooo3[i1] = (sum(y0_c[i1,:]*CT3_l_sol[:,i1] + mm_c[i1,:]/2*CT3_l_sol[:,i1]*CT3_l_sol[:,i1]) + sum(y0_g[i1,:]*CT3_p_sol[:,i1] + mm_g[i1,:]/2*CT3_p_sol[:,i1]*CT3_p_sol[:,i1]) +
#                (el_price_e[i1]+0.1)*CT3_imp_sol[i1] - el_price_e[i1]*CT3_exp_sol[i1] + 0.001*sum(abs(CT3_q_sol[:,i1]))  + gamma_geo*abs(CT3_qcomm_sol[i1])) #+ pr_i*sum(CT_alfa_sol[:,i1]) + pr_e*sum(CT_beta_sol[:,i1]))
#
#gap_opt3 = opt3-CT3_obj_sol
#gap_opt32 = opt3-ooo3
#
#
##%% Save Results
#import shelve
#filename='Res_14_07_3.out'
#var_2_save = ['ADMM_summary3','ADMM_prices3','ADMM_flag3','l_3','p_3','q_3','alfa_3','beta_3','q3_com']
#if os.path.exists(filename+'.dat'):
#    print('ERROR - file already existing!')
#else:
#    my_shelf = shelve.open(filename,flag = 'n') # 'n' for new
#    for key in var_2_save:
#        try:
#            my_shelf[key] = globals()[key]
#        except TypeError:
#            #
#            # __builtins__, my_shelf, and imported modules can not be shelved.
#            #
#            print(key)
#    my_shelf.close()
#
##%% Community Trading
#CT4_p_sol = np.zeros((g,TMST))
#CT4_l_sol = np.zeros((n,TMST))
#CT4_q_sol = np.zeros((n,TMST))
#CT4_alfa_sol = np.zeros((n,TMST))
#CT4_beta_sol = np.zeros((n,TMST))
#CT4_imp_sol = np.zeros(TMST)
#CT4_exp_sol = np.zeros(TMST)
#CT4_obj_sol = np.zeros(TMST)
#CT4_price_sol = np.zeros((n,TMST))
#CT4_price2_sol = np.zeros((3,TMST))
#CT4_price3_sol = np.zeros((n,TMST))
#CT4_theta_sol = np.zeros(TMST)
#
#for t in np.arange(0,TMST,24):
#    temp = range(t,t+24)
#    # Create a new model
#    CT4_m = gb.Model("qp")
#    CT4_m.setParam( 'OutputFlag', False )
#    # Create variables
#    p = np.array([CT4_m.addVar(lb=Pmin[i]+PV[t+k,i], ub=Pmax[i]+PV[t+k,i]) for i in range(n) for k in range(24)])
#    l = np.array([CT4_m.addVar(lb=Lmin[t+k,i], ub=Lmax[t+k,i]) for i in range(n) for k in range(24)])
#    q_imp = np.array([CT4_m.addVar() for k in range(24)])
#    q_exp = np.array([CT4_m.addVar() for k in range(24)])
#    alfa = np.array([CT4_m.addVar() for i in range(n) for k in range(24)])
#    beta = np.array([CT4_m.addVar() for i in range(n) for k in range(24)])
#    q_pos = np.array([CT4_m.addVar() for i in range(n) for k in range(24)])
#    q = np.array([CT4_m.addVar(lb = -gb.GRB.INFINITY) for i in range(n) for k in range(24)])
#    theta = np.array([CT4_m.addVar() for k in range(24)])
#    gamma_i = (el_price_e[temp] + 0.1)
#    gamma_e = -el_price_e[temp]
#    gamma_m = 1.0
#    CT4_m.update()
#
#    p = np.transpose(p.reshape(n,24))
#    l = np.transpose(l.reshape(n,24))
#    q = np.transpose(q.reshape(n,24))
#    q_pos = np.transpose(q_pos.reshape(n,24))
#    alfa = np.transpose(alfa.reshape(n,24))
#    beta = np.transpose(beta.reshape(n,24))
#
#    # Set objective:
#    obj = (sum(sum(y0_c[temp,:]*l + mm_c[temp,:]/2*l*l) + sum(y0_g[temp,:]*p + mm_g[temp,:]/2*p*p))
#           + sum(gamma_i*q_imp + gamma_e*q_exp + gamma_m*theta) + sum(0.001*sum(q_pos)))
#    CT4_m.setObjective(obj)
#    # Add constraint
#    for k in range(24):
#        CT4_m.addConstr(sum(q[k,:]) == 0, name="comm[%s]"%(k))
#        for i in range(n):
#            CT4_m.addConstr(p[k,i] + l[k,i] + q[k,i] + alfa[k,i] - beta[k,i] == 0, name="pros[%s,%s]"% (k,i))
#            CT4_m.addConstr(q[k,i] <= q_pos[k,i])
#            CT4_m.addConstr(q[k,i] >= -q_pos[k,i])
#            CT4_m.addConstr(alfa[k,i] - theta[k] <= 0, name="maxx[%s,%s]"% (k,i))
#        CT4_m.addConstr(sum(alfa[k,:]) - q_imp[k] == 0, name="imp_bal[%s]"%(k))
#        CT4_m.addConstr(sum(beta[k,:]) - q_exp[k] == 0, name="exp_bal[%s]"%(k))
#    for i in range(n):
#        CT4_m.addConstr(sum(Agg_load[temp,i] + l[:,i]) == 0)
##        for j in np.arange(0,24,window):
##            CT5_m.addConstr(sum(Agg_load[range(t+j,t+j+window),i] + l[range(j,j+window),i]) == 0)
#    CT4_m.update()
#
#    CT4_m.optimize()
#    for k in range(24):
#        for i in range(n):
#            CT4_price_sol[i,t+k] = CT4_m.getConstrByName("pros[%s,%s]"%(k,i)).Pi
#            CT4_price3_sol[i,t+k] = CT4_m.getConstrByName("maxx[%s,%s]"%(k,i)).Pi
#            CT4_p_sol[i,t+k] = p[k,i].x
#            CT4_l_sol[i,t+k] = l[k,i].x
#            CT4_q_sol[i,t+k] = q[k,i].x
#            CT4_alfa_sol[i,t+k] = alfa[k,i].x
#            CT4_beta_sol[i,t+k] = beta[k,i].x
#        CT4_price2_sol[0,t+k] = CT4_m.getConstrByName("comm[%s]"%k).Pi
#        CT4_price2_sol[1,t+k] = CT4_m.getConstrByName("imp_bal[%s]"%k).Pi
#        CT4_price2_sol[2,t+k] = CT4_m.getConstrByName("exp_bal[%s]"%k).Pi
#        CT4_imp_sol[t+k] = q_imp[k].x
#        CT4_exp_sol[t+k] = q_exp[k].x
#        CT4_theta_sol[t+k] = theta[k].x
#
#    del CT4_m
#
#CT4_IE_sol = CT4_imp_sol - CT4_exp_sol
#
##%% ADMM optimisation via master-sub classes
#from ADMM_master_max import ADMM_Master
#o = 0.01
#e = 0.00001
#asynch = -100
#weight = 1/n
#
#Mast4 = ADMM_Master(b1, c1, Pmin, Pmax, PV, b2, c2, Load, Flex_load, tau, el_price_e, o, e, TMST, window, 0, asynch)
#ADMM_summary4 = Mast4.results
#ADMM_prices4 = Mast4.prices
#ADMM_flag4 = Mast4.flag
#
##%%
#max_l_4 = abs(Mast4.variables.l_k - np.transpose(CT4_l_sol)).max()
#max_p_4 = abs(Mast4.variables.p_k - np.transpose(CT4_p_sol)).max()
#max_q_4 = abs(Mast4.variables.q_k - np.transpose(CT4_q_sol)).max()
#max_alfa_4 = abs(Mast4.variables.alfa_k - np.transpose(CT4_alfa_sol)).max()
#max_beta_4 = abs(Mast4.variables.beta_k - np.transpose(CT4_beta_sol)).max()
#l_4 = Mast4.variables.l_k
#p_4 = Mast4.variables.p_k
#q_4 = Mast4.variables.q_k
#alfa_4 = Mast4.variables.alfa_k
#beta_4 = Mast4.variables.beta_k
#theta = Mast4.variables.pow_theta
#
#imp_4 = alfa_4.sum(axis=1)
#exp_4 = beta_4.sum(axis=1)
#ie_4 = imp_4-exp_4
#
#opt4 = np.empty(TMST)
#ooo4= np.empty(TMST)
#for i1 in range(TMST):
#    opt4[i1] = (sum(y0_c[i1,:]*l_4[i1,:] + mm_c[i1,:]/2*l_4[i1,:]*l_4[i1,:]) + sum(y0_g[i1,:]*p_4[i1,:] + mm_g[i1,:]/2*p_4[i1,:]*p_4[i1,:]) #+ el_price_e[i1]*ie_1[i1]
#                + 0.001*sum(abs(q_4[i1,:])) + (el_price_e[i1]+0.1)*sum(alfa_4[i1,:]) - el_price_e[i1]*sum(beta_4[i1,:]) + 1.0*theta[i1])
#    ooo4[i1] = (sum(y0_c[i1,:]*CT4_l_sol[:,i1] + mm_c[i1,:]/2*CT4_l_sol[:,i1]*CT4_l_sol[:,i1]) + sum(y0_g[i1,:]*CT4_p_sol[:,i1] + mm_g[i1,:]/2*CT4_p_sol[:,i1]*CT4_p_sol[:,i1]) +
#                (el_price_e[i1]+0.1)*CT4_imp_sol[i1] - el_price_e[i1]*CT4_exp_sol[i1] + 0.001*sum(abs(CT4_q_sol[:,i1]))  + 1.0*CT4_theta_sol[i1]) #+ pr_i*sum(CT_alfa_sol[:,i1]) + pr_e*sum(CT_beta_sol[:,i1]))
#
#gap_opt4 = opt4-CT4_obj_sol
#gap_opt42 = opt4-ooo4
#
##%% Save Results
#import shelve
#filename='Res_14_07_4.out'
#var_2_save = ['ADMM_summary4','ADMM_prices4','ADMM_flag4','l_4','p_4','q_4','alfa_4','beta_4','theta']
#if os.path.exists(filename+'.dat'):
#    print('ERROR - file already existing!')
#else:
#    my_shelf = shelve.open(filename,flag = 'n') # 'n' for new
#    for key in var_2_save:
#        try:
#            my_shelf[key] = globals()[key]
#        except TypeError:
#            #
#            # __builtins__, my_shelf, and imported modules can not be shelved.
#            #
#            print(key)
#    my_shelf.close()
#
##%% Community Trading
#CT5_p_sol = np.zeros((g,TMST))
#CT5_l_sol = np.zeros((n,TMST))
#CT5_q_sol = np.zeros((n,TMST))
#CT5_alfa_sol = np.zeros((n,TMST))
#CT5_beta_sol = np.zeros((n,TMST))
#CT5_imp_sol = np.zeros(TMST)
#CT5_exp_sol = np.zeros(TMST)
#CT5_price_sol = np.zeros((n,TMST))
#CT5_price2_sol = np.zeros((3,TMST))
#CT5_price3_sol = np.zeros(TMST)
#CT5_theta_sol = np.zeros(TMST)
#
#for t in np.arange(0,TMST,24):
#    temp = range(t,t+24)
#    # Create a new model
#    CT5_m = gb.Model("qp")
#    CT5_m.setParam( 'OutputFlag', False )
#    # Create variables
#    p = np.array([CT5_m.addVar(lb=Pmin[i]+PV[t+k,i], ub=Pmax[i]+PV[t+k,i]) for i in range(n) for k in range(24)])
#    l = np.array([CT5_m.addVar(lb=Lmin[t+k,i], ub=Lmax[t+k,i]) for i in range(n) for k in range(24)])
#    q_imp = np.array([CT5_m.addVar() for k in range(24)])
#    q_exp = np.array([CT5_m.addVar() for k in range(24)])
#    alfa = np.array([CT5_m.addVar() for i in range(n) for k in range(24)])
#    beta = np.array([CT5_m.addVar() for i in range(n) for k in range(24)])
##    delta = np.array([CT5_m.addVar() for k in range(24)])
#    q_pos = np.array([CT5_m.addVar() for i in range(n) for k in range(24)])
#    q = np.array([CT5_m.addVar(lb = -gb.GRB.INFINITY) for i in range(n) for k in range(24)])
#    theta = CT5_m.addVar()
#    gamma_i = (el_price_e[temp] + 0.1)
#    gamma_e = -el_price_e[temp]
#    gamma_m = 1.0
#    CT5_m.update()
#
#    p = np.transpose(p.reshape(n,24))
#    l = np.transpose(l.reshape(n,24))
#    q = np.transpose(q.reshape(n,24))
#    q_pos = np.transpose(q_pos.reshape(n,24))
#    alfa = np.transpose(alfa.reshape(n,24))
#    beta = np.transpose(beta.reshape(n,24))
#
#    # Set objective:
#    obj = (sum(sum(y0_c[temp,:]*l + mm_c[temp,:]/2*l*l) + sum(y0_g[temp,:]*p + mm_g[temp,:]/2*p*p))
#           + sum(gamma_i*q_imp + gamma_e*q_exp) + gamma_m*theta + sum(0.001*sum(q_pos)))
#    CT5_m.setObjective(obj)
#    # Add constraint
#    for k in range(24):
#        CT5_m.addConstr(1*sum(q[k,:]) == 0, name="comm[%s]"%(k))
#        for i in range(n):
#            CT5_m.addConstr(p[k,i] + l[k,i] + q[k,i] + alfa[k,i] - beta[k,i] == 0, name="pros[%s,%s]"% (k,i))
#            CT5_m.addConstr(q[k,i] <= q_pos[k,i])
#            CT5_m.addConstr(q[k,i] >= -q_pos[k,i])
#        CT5_m.addConstr(sum(alfa[k,:]) - q_imp[k] == 0, name="imp_bal[%s]"%(k))
#        CT5_m.addConstr(sum(beta[k,:]) - q_exp[k] == 0, name="exp_bal[%s]"%(k))
##        CT5_m.addConstr(1*(sum(alfa[k,:]) - delta[k]) == 0, name="max_bal[%s]"%(k))
##        CT5_m.addConstr(delta[k] - theta <= 0, name="maxx[%s]"%(k))
#        CT5_m.addConstr(q_imp[k] - theta <= 0, name="maxx[%s]"%(k))
#    for i in range(n):
#        CT5_m.addConstr(sum(Agg_load[temp,i] + l[:,i]) == 0)
##        for j in np.arange(0,24,window):
##            CT5_m.addConstr(sum(Agg_load[range(t+j,t+j+window),i] + l[range(j,j+window),i]) == 0)
#    CT5_m.update()
#
#    CT5_m.optimize()
#    for k in range(24):
#        for i in range(n):
#            CT5_price_sol[i,t+k] = CT5_m.getConstrByName("pros[%s,%s]"%(k,i)).Pi
#            CT5_p_sol[i,t+k] = p[k,i].x
#            CT5_l_sol[i,t+k] = l[k,i].x
#            CT5_q_sol[i,t+k] = q[k,i].x
#            CT5_alfa_sol[i,t+k] = alfa[k,i].x
#            CT5_beta_sol[i,t+k] = beta[k,i].x
#        CT5_price2_sol[0,t+k] = CT5_m.getConstrByName("comm[%s]"%k).Pi
#        CT5_price2_sol[1,t+k] = CT5_m.getConstrByName("imp_bal[%s]"%k).Pi
#        CT5_price2_sol[2,t+k] = CT5_m.getConstrByName("exp_bal[%s]"%k).Pi
#        CT5_price3_sol[t+k] = CT5_m.getConstrByName("maxx[%s]"%k).Pi
#        CT5_imp_sol[t+k] = q_imp[k].x
#        CT5_exp_sol[t+k] = q_exp[k].x
#        CT5_theta_sol[t+k] = theta.x
#
#    del CT5_m
#
#CT5_IE_sol = CT5_imp_sol - CT5_exp_sol
#sum_q = CT5_q_sol.sum(axis=0)
#
##%% ADMM optimisation via master-sub classes
#from ADMM_master_peak2 import ADMM_Master
#o = 0.01
#e = 0.00001
#asynch = -100
#weight = 1/n
#
#Mast5 = ADMM_Master(b1, c1, Pmin, Pmax, PV, b2, c2, Load, Flex_load, tau, el_price_e, o, e, TMST, window, 0, asynch)
#ADMM_summary5 = Mast5.results
#ADMM_prices5 = Mast5.prices
#
##%%
#max_l_5 = abs(Mast5.variables.l_k - np.transpose(CT5_l_sol)).max()
#max_p_5 = abs(Mast5.variables.p_k - np.transpose(CT5_p_sol)).max()
#max_q_5 = abs(Mast5.variables.q_k - np.transpose(CT5_q_sol)).max()
#max_alfa_5 = abs(Mast5.variables.alfa_k - np.transpose(CT5_alfa_sol)).max()
#max_beta_5 = abs(Mast5.variables.beta_k - np.transpose(CT5_beta_sol)).max()
#l_5 = Mast5.variables.l_k
#p_5 = Mast5.variables.p_k
#q_5 = Mast5.variables.q_k
#alfa_5 = Mast5.variables.alfa_k
#beta_5 = Mast5.variables.beta_k
#theta_5 = Mast5.variables.pow_theta
#
#imp_5 = alfa_5.sum(axis=1)
#exp_5 = beta_5.sum(axis=1)
#ie_5 = imp_5-exp_5
#
#opt5 = np.empty(TMST)
#ooo5= np.empty(TMST)
#for i1 in range(TMST):
#    opt5[i1] = (sum(y0_c[i1,:]*l_5[i1,:] + mm_c[i1,:]/2*l_5[i1,:]*l_5[i1,:]) + sum(y0_g[i1,:]*p_5[i1,:] + mm_g[i1,:]/2*p_5[i1,:]*p_5[i1,:]) #+ el_price_e[i1]*ie_1[i1]
#                + 0.001*sum(abs(q_5[i1,:])) + (el_price_e[i1]+0.1)*sum(alfa_5[i1,:]) - el_price_e[i1]*sum(beta_5[i1,:]) + 1.0*theta_5[i1])
#    ooo5[i1] = (sum(y0_c[i1,:]*CT5_l_sol[:,i1] + mm_c[i1,:]/2*CT5_l_sol[:,i1]*CT5_l_sol[:,i1]) + sum(y0_g[i1,:]*CT5_p_sol[:,i1] + mm_g[i1,:]/2*CT5_p_sol[:,i1]*CT5_p_sol[:,i1]) +
#                (el_price_e[i1]+0.1)*CT5_imp_sol[i1] - el_price_e[i1]*CT5_exp_sol[i1] + 0.001*sum(abs(CT5_q_sol[:,i1]))  + 1.0*CT5_theta_sol[i1]) #+ pr_i*sum(CT_alfa_sol[:,i1]) + pr_e*sum(CT_beta_sol[:,i1]))
#
##gap_opt5 = opt5-CT5_obj_sol
#gap_opt52 = opt5-ooo5
##%% Save Results
#import shelve
#filename='Res_14_07_0.out'
#var_2_save = ['Mast','Mast2','Mast3','Mast4']
#if os.path.exists(filename+'.dat'):
#    print('ERROR - file already existing!')
#else:
#    my_shelf = shelve.open(filename,flag = 'n') # 'n' for new
#    for key in var_2_save:
#        try:
#            my_shelf[key] = globals()[key]
#        except TypeError:
#            #
#            # __builtins__, my_shelf, and imported modules can not be shelved.
#            #
#            print(key)
#    my_shelf.close()