import heapq, os

import Global_Module
from resources.tile import *
from resources.primitive import *
from Functions import extend_dict, weight_function, load_data

class Arch:
    def __init__(self, G):
        self.G          = G
        self.Init_tile_port_dict()
        self.tiles      = set()
        self.wires_dict = {}
        self.init_tiles()
        self.Init_tile_node_dicts()
        self.reform_cost()
        self.weight = weight_function(G, 'weight')

    def init_tiles(self):
        all_edges = {Edge(edge) for edge in self.G.edges()}
        for tile, tile_nodes in self.tile_port_dict.items():
            tile1 = Tile(tile, self.G, tile_nodes)
            tile1.edges = set(filter(lambda x: re.search(tile1.name, f'{x.u} {x.v}'), all_edges))
            self.tiles.add(tile1)

    def Init_tile_node_dicts(self):
        self.tile_dirc_dict = {}
        self.gnode_dict = {}
        for tile in self.tiles:
            if tile.type == 'CLB':
                self.tile_dirc_dict[tile.name] = tile.direction

            for node in tile.nodes:
                if node.tile_type == 'INT':
                    key = node.port
                    value = node.tile
                    extend_dict(self.gnode_dict, key, value, value_type='set')
                else:
                    key1 = node.port_suffix
                    key2 = node.bel_group[0]
                    value = node.tile
                    if key1 not in self.gnode_dict:
                        self.gnode_dict[key1] = {key2: {value}}
                    else:
                        extend_dict(self.gnode_dict[key1], key2, value, value_type='set')

    def Init_tile_port_dict(self):
        self.tile_port_dict = {}
        for node in self.G:
            extend_dict(self.tile_port_dict, self.get_tile(node), self.get_port(node), value_type='set')

    def get_gnodes(self, node):
        gnodes = set()
        if node.startswith('INT'):
            port = self.get_port(node)
            for tile in self.gnode_dict[port]:
                gnodes.add(f'{tile}/{port}')
        else:
            dirc = self.tile_dirc_dict[self.get_tile(node)]
            port_suffix = self.port_suffix(node)
            slice_type = self.get_slice_type(node)
            for tile in self.gnode_dict[port_suffix][dirc]:
                gnodes.add(f'{tile}/CLE_CLE_{slice_type}_SITE_0_{port_suffix}')

        return gnodes

    def gen_FFs(self, TC_total=None):
        blocked_FFs = TC_total.FFs if TC_total else set()
        FFs = set()
        for clb in self.get_tiles(type='CLB'):
            for i in range(65, 73):
                FFs.add(f'{clb.name}/{chr(i)}FF')
                FFs.add(f'{clb.name}/{chr(i)}FF2')

        FFs = {FF(ff) for ff in FFs if ff not in blocked_FFs}

        return FFs

    def gen_LUTs(self, TC, TC_total=None):
        blocked_LUTs = TC_total.blocked_LUTs if TC_total else set()
        LUTs = set()
        for clb in self.get_tiles(type='CLB'):
            for i in range(65, 73):
                LUTs.add(f'{clb.name}/{chr(i)}5LUT')
                LUTs.add(f'{clb.name}/{chr(i)}6LUT')

        LUTs = {LUT(lut) for lut in LUTs if lut not in blocked_LUTs}
        full_LUTs = set(filter(lambda x: re.match('CL.*5LUT', x), blocked_LUTs))
        partial_LUTs = set(filter(lambda x: re.match('CL.*6LUT', x), blocked_LUTs))

        full_LUTs_ins = {f'{self.get_tile(key)}/CLE_CLE_{self.get_slice_type(key)}_SITE_0_{self.get_port(key)[0]}{i}' for key in full_LUTs for i in range(1, 7)}
        partial_LUTs_i6 = {f'{self.get_tile(key)}/CLE_CLE_{self.get_slice_type(key)}_SITE_0_{self.get_port(key)[0]}6'
                         for key in partial_LUTs}
        partial_LUTs_mux = {f'{self.get_tile(key)}/CLE_CLE_{self.get_slice_type(key)}_SITE_0_{self.get_port(key)[0]}MUX' for key in partial_LUTs}
        in_graph_blocked_nodes = set(self.G) & full_LUTs_ins.union(partial_LUTs_i6).union(partial_LUTs_mux)
        TC.block_nodes = in_graph_blocked_nodes
        TC.reconst_block_nodes.update(in_graph_blocked_nodes)
        TC.G.remove_nodes_from(in_graph_blocked_nodes)

        return LUTs

    def get_tiles(self, **attributes):
        tiles = set()
        for tile in self.tiles:
            for attr in attributes:
                if getattr(tile, attr) != attributes[attr]:
                    break
            else:
                tiles.add(tile)

        return tiles

    def get_nodes(self, **attributes):
        all_nodes = {node for tile in self.tiles for node in tile.nodes}
        for k, v in attributes.items():
            nodes = set()
            for node in all_nodes:
                if getattr(node, k) == v:
                    nodes.add(node)

            all_nodes = nodes.copy()

        return all_nodes

    def get_edges(self, **attributes):
        all_edges = {edge for tile in self.tiles for edge in tile.edges}
        edges = set()
        for edge in all_edges:
            for attr in attributes:
                if getattr(edge, attr) != attributes[attr]:
                    break
            else:
                edges.add(edge)

        return edges

    def set_wires_dict(self, coord):
        tile = 'INT_' + coord
        for edge in self.G.edges():
            if len(list(filter(lambda x: re.search(tile, x), edge))) != 2:
                for node in edge:
                    if re.search(tile, node):
                        key = node

                    if not re.search(tile, node):
                        value = node

                extend_dict(self.wires_dict, key, value)
                extend_dict(self.wires_dict, value, key)

    def get_wire(self, node):
        if node in self.wires_dict:
            return self.wires_dict[node]
        else:
            return None

    def set_level(self, G, coord):
        mid_back = set()
        node_level = {}
        int_tile = self.get_tiles(type='INT', coordinate=coord).pop()
        queue = list(self.get_nodes(tile_type='INT', mode='in', coordinate=coord))
        next_queue = set()
        level = 0
        while len(node_level) != len(int_tile.nodes):
            level += 1
            neighs = set()
            for node in queue:
                neighs.update(G.neighbors(node.name))
                node_level[node.name] = level

            for neigh in neighs:
                neigh1 = self.get_nodes(name=neigh).pop()
                if neigh1.tile != int_tile.name:
                    continue
                elif neigh1.name not in node_level:
                    next_queue.add(neigh1)
                else:
                    mid_back.add(neigh1)

            queue = list(next_queue).copy()
            next_queue = set()

        for node in int_tile.nodes:
            node.level = node_level[node.name]

        return mid_back

    def get_clb_nodes(self, type):
        all_nodes = {node for tile in self.tiles for node in tile.nodes}
        if type == 'LUT_in':
            return set(filter(lambda x: re.match(GM.LUT_in_pattern, x.name), all_nodes))
        elif type == 'FF_in':
            return set(filter(lambda x: re.match(GM.FF_in_pattern, x.name), all_nodes))
        elif type == 'FF_out':
            return set(filter(lambda x: re.match(GM.FF_out_pattern, x.name), all_nodes))
        elif type == 'CLB_out':
            return set(filter(lambda x: re.match(GM.CLB_out_pattern, x.name), all_nodes))
        elif type == 'CLB_muxed':
            return set(filter(lambda x: re.match(GM.MUXED_CLB_out_pattern, x.name), all_nodes))

    def get_pips_length(self, coordinate):
        tile = f'INT_{coordinate}'
        pips = self.get_edges(u_tile=tile, v_tile=tile)
        sources = {node.name for node in self.get_nodes(clb_node_type='FF_out')}
        sinks = {node.name for node in self.get_nodes(clb_node_type='FF_in')}

        for src in sources:
            self.G.add_edge('s', src, weight=0)

        for sink in sinks:
            self.G.add_edge(sink, 't', weight=0)

        for pip in pips:
            try:
                path_in = nx.shortest_path(self.G, 's', pip[0], weight='weight')[1:]
                path_out = nx.shortest_path(self.G, pip[1], 't', weight='weight')[:-1]
                GM.pips_length_dict[(pip.u, pip.v)] = len(path_in + path_out)
            except:
                continue

        self.G.remove_nodes_from(['s', 't'])

    @staticmethod
    def get_tile(wire, delimiter='/'):
        return wire.split(delimiter)[0]

    @staticmethod
    def get_port(wire, delimiter='/'):
        return wire.split(delimiter)[1]

    @staticmethod
    def get_direction(clb_node):
        if clb_node.startswith('CLEL_R'):
            dir = 'E'
        else:
            dir = 'W'

        return dir

    @staticmethod
    def get_slice_type(tile):
        if tile.startswith('CLEM'):
            return 'M'
        else:
            return 'L'

    @staticmethod
    def port_suffix(node):
        return node.split('_SITE_0_')[-1]

    def reconstruct_device(self, l, coord):
        queue = list(GM.pips_length_dict)
        if l > 1:
            files = sorted(os.listdir(os.path.join(GM.store_path, f'iter{l - 1}')),
                           key=lambda x: int(re.findall('\d+', x).pop()), reverse=False)
            TC_last = load_data(os.path.join(GM.store_path, f'iter{l - 1}'), files[-1])
            for edge in TC_last.G_dev.edges():
                if edge in self.G.edges():
                    if edge not in TC_last.G:
                        continue  # route_thrus

                    self.G.get_edge_data(*edge)['weight'] = TC_last.G.get_edge_data(*edge)['weight']

            pips_dict = load_data(GM.Data_path, 'covered_pips_dict.data')
            tile = f'INT_{coord}'
            pips = pips_dict[tile]
            pips = {(f'{tile}/{pip[0]}', f'{tile}/{pip[1]}') for pip in pips}
            queue = list(set(queue) - pips)

        return queue

    def reform_cost(self):
        for edge in self.G.edges():
            if self.get_tile(edge[0]) == self.get_tile(edge[1]):
                if self.get_tile(edge[0]).startswith('CLE'):
                    if re.match(Global_Module.MUXED_CLB_out_pattern, edge[0]) or re.match(Global_Module.MUXED_CLB_out_pattern, edge[1]):
                        weight = 100
                    elif re.match(Global_Module.LUT_in6_pattern, edge[0]):
                        weight = 50
                    else:
                        weight = 25  # CLB_Route_Thru
                else:
                    continue
            else:
                continue

            self.G.get_edge_data(*edge)['weight'] = weight

    def blocking_nodes(self, CD, tile):
        #these are out mode nodes that have pips back to the INT tile
        blocking_nodes = {node.name for node in self.get_nodes(tile=tile, mode='out') if self.G.out_degree(node.name)>1}
        valid_blocking_nodes = set()
        for node in blocking_nodes:
            clb_neighs = list(
                filter(lambda x: Node(x).clb_node_type == 'FF_in' and CD[Node(x).bel_group] != 'launch',
                       self.G.neighbors(node)))
            if clb_neighs:
                valid_blocking_nodes.add(node)

        return valid_blocking_nodes


n = int(input())

var = "xyz"
mn = [0, 0, 0]
mx = [101, 101, 101]
cond = []

for i in range(n):
    s = input().split()
    try:
        x = int(s[2])
    except ValueError:
        x = None

    v = var.index(s[0])

    if x is not None:
        if s[1] == ">":
            mn[v] = max(mn[v], x + 1)
        else:
            mx[v] = min(mx[v], x)
    else:
        cond.append((v, var.index(s[2])))

ans = 0

for x in range(mn[0], mx[0]):
    for y in range(mn[1], mx[1]):
        for z in range(mn[2], mx[2]):
            t = [x, y, z]
            for g, l in cond:
                if t[g] <= t[l]:
                    break
            else:
                ans += 1

print(ans)


"""
"""
from django.conf.urls import patterns, url
from rest_framework.routers import SimpleRouter

from myapp import views

router = SimpleRouter()
router.register(r'projects', views.ProjectViewSet)
router.register(r'tasks', views.TaskViewSet)
router.register(r'users', views.UserViewSet)

urlpatterns = patterns('',
    url(r'^register/', 'myapp.views.create_auth'),
)

urlpatterns += router.urls


from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.shortcuts import render_to_response

def contact(request):
    errors = []
    if request.method == 'POST':
        if not request.POST.get('subject', ''):
            errors.append('Enter a subject.')
        if not request.POST.get('message', ''):
            errors.append('Enter a message.')
        if request.POST.get('email') and '@' not in request.POST['email']:
            errors.append('Enter a valid e-mail address.')
        if not errors:
            send_mail(
                request.POST['subject'],
                request.POST['message'],
                request.POST.get('email','noreply@texasibiz.net'),
                ['admin@texasibiz.net'], #email address where message is sent.
            )
            return HttpResponseRedirect('/thanks/')
    return render(request, 'contact.html',
        {'errors': errors})

def thanks(request):
    return render_to_response('thanks.html')


# (c) AlenPaulVarghese
# -*- coding: utf-8 -*-

from pathlib import Path
from typing import List

from pikepdf import Pdf

from tools.scaffold import AbstractTask

class RotatePdf(AbstractTask):
    def __init__(self, chat_id: int, message_id: int):
        super().__init__(chat_id, message_id)
        self.input_file: Path
        self.degree: int = 90
        self.page_range: List[int]

    def set_configuration(self, _path: Path, _range: List[int], _degree: int) -> None:
        self.input_file = _path
        self.page_range = _range
        self.degree = _degree

    def process(self):
        with Pdf.open(self.input_file) as input_pdf:
            for index in self.page_range:
                input_pdf.pages[index - 1].rotate(self.degree, False)
            input_pdf.save(self.cwd / self.filename)


import xml.etree.ElementTree as ET
import os.path
import sys
import random

from classes.Station import Station
from classes.Node import Node
from classes.Link import Link
from classes.Network import Network
from classes.Port import Port
from classes.Flow import Flow
from classes.Target import Target
from classes.Switch import Switch

################################################################@
""" Local methods """
################################################################@

""" parseStations
    Method to parse stations
        root : the xml main root
"""
def parseStations(root,network):
    for station in root.findall('station'):

        network.stations.append (   Station(name=station.get('name'),capacity=float(station.get('transmission-capacity')),network=network) )

""" parseSwitches
    Method to parse switches
        root : the xml main root
"""
def parseSwitches(root,network):
    for sw in root.findall('switch'):
        network.switches.append (   Switch( name=sw.get('name'),
                                            latency=float(sw.get('tech-latency')),
                                            capacity=float(sw.get('transmission-capacity')),
                                            network=network),
                                            )

""" parseEdges
    Method to parse edges
        root : the xml main root
"""
def parseEdges(root,network):
    for sw in root.findall('link'):

        frm = [s for s in (network.stations + network.switches) if s.name()==sw.get('from')][0]
        to =  [s for s in (network.stations + network.switches) if s.name()==sw.get('to')][0]

        from_port=Port(device=frm,number=int(sw.get('fromPort')))

        to_port=Port(device=to,number=int(sw.get('toPort')))

        lk = Link(name=sw.get('name'),
                                     frm=frm,
                                     to=to,
                                     from_port=from_port,
                                     to_port=to_port,
                                     capacity=float(sw.get('transmission-capacity')),
                                     network=network)

        from_port.link(lk)
        to_port.link(lk)

        if frm.is_switch():
            frm.ports.append(from_port)
            frm.links.append(lk)
        else:
            frm.port(from_port)
            frm.link(lk)

        if to.is_switch():
            to.ports.append( to_port )
            to.links.append(lk)
        else:
            to.port(to_port)
            to.link = lk

        network.links.append ( lk )

""" parseFlows
    Method to parse flows
        root : the xml main root
"""
def parseFlows(root,network):
    for sw in root.findall('flow'):

        source = [s for s in (network.stations) if s.name()==sw.get('source')][0]

        flow = Flow (name=sw.get('name'),
                     source=source,
                     payload=float(sw.get('max-payload')),
                     overhead=67,
                     period=float(sw.get('period')),
                     network=network)

        for tg in sw.findall('target'):
            target_object = [s for s in (network.stations) if s.name()==tg.get('name')][0]
            target = Target( name=tg.get('name'),
                             target=target_object,
                             flow=flow)

            flow.targets.append(target)
            target.path.append(flow.source)
            for pt in tg.findall('path'):
                path_node=[s for s in (network.stations + network.switches) if s.name()==pt.get('node')][0]
                target.path.append(path_node)
                if path_node.is_switch() and not(flow in path_node.flows) :
                    path_node.flows.append(flow)

        network.flows.append (flow)
        source.flows.append(flow)

""" parseNetwork
    Method to parse the whole network
        xmlFile : the path to the xml file
"""
def parseNetwork(xmlFile,network):
    if os.path.isfile(xmlFile):
        tree = ET.parse(xmlFile)
        root = tree.getroot()

        for sw in root.findall('network'):
            network.overhead(float(sw.get("overhead")))
            network.name(sw.get("name"))
            network.technology(sw.get("technology"))
            network.capacity(float(sw.get("transmission-capacity")))
            network.shortest_path_policy(sw.get("shortest-path-policy"))

        parseStations(root,network)
        parseSwitches(root,network)
        parseEdges(root,network)
        parseFlows(root,network)
    else:
        print("File not found: "+xmlFile)

""" traceNetwork
    Method to trace the network to the console
"""
def traceNetwork(network):
    print("Stations:")
    for node in network.stations:
        print ("\t" + node.name())

    print("\nSwitches:")
    for node in network.switches:
        print ("\t" + node.name())

    print("\nEdges:")
    for edge in network.links:
        print ("\t" + edge.name() + ": " + edge.frm().name() + "=>" + edge.to().name())

    print("\nFlows:")
    for flow in network.flows:
        print ("\t" + flow.name() + ": " + flow.source.name() + " (L=" + str(flow.payload()) +", p=" + str(flow.period()) + ")")
        for target in flow.targets:
            print ("\t\tTarget=" + target.target().name())
            for node in target.path:
                print ("\t\t\t" + node.name())

""" createFakeResultsFile
    Method to create a fake result file ; only delays are generated (random value between 40 and 80)
        xmlFile : the path to the xml (input) file
"""
def createFakeResultsFile (xmlFile,network):
    posDot = xmlFile.rfind('.')
    if not (posDot == -1):
        resFile = xmlFile[0:posDot]+'_res.xml'
    else:
        resFile = xmlFile+'_res.xml'
    res = open(resFile,"w")
    res.write('<?xml version="1.0" encoding="UTF-8"?>\n')
    res.write('<results>\n')
    res.write('\t<delays>\n')
    for flow in network.flows:
        res.write('\t\t<flow name="' + flow.name() + '">\n');
        for target in flow.targets:
            res.write('\t\t\t<target name="' + target.name() + '" value="'+str(random.randint(400, 800))+'" />\n');
        res.write('\t\t</flow>\n')
    res.write('\t</delays>\n')
    res.write('</results>\n')
    res.close()
    file2output(resFile)

def createResultsFile (xmlFile,network):
    posDot = xmlFile.rfind('.')
    if not (posDot == -1):
        resFile = xmlFile[0:posDot]+'_res.xml'
    else:
        resFile = xmlFile+'_res.xml'
    res = open(resFile,"w")
    res.write('<?xml version="1.0" encoding="UTF-8"?>\n')
    res.write('<results>\n')

    # delays
    res.write('\t<delays>\n')
    for flow in network.flows:
        res.write('\t\t<flow name="' + flow.name() + '">\n');
        for target in flow.targets:
            res.write('\t\t\t<target name="' + target.name() + '" value="'+str(  format(target.eed()*1000000, '.0f'  )   )+'" />\n');
        res.write('\t\t</flow>\n')
    res.write('\t</delays>\n')

    #link loads
    res.write('\t<load>\n')
    for link in network.links:
        res.write('\t\t<edge name="' + link.name() + '">\n');
        res.write('\t\t\t<usage type="' + 'direct' + '" value="'+str(link.direct_usage()  )+'"' +  ' percent="'+str(  format(link.direct_load()*100, '.2f'  )   )+'%" />\n')
        res.write('\t\t\t<usage type="' + 'reverse' + '" value="'+str(link.reverse_usage() )+'"' + ' percent="'+str( format(link.reverse_load()*100,  '.2f' ) )+'%" />\n')
        res.write('\t\t</edge>\n')
    res.write('\t</load>\n')

    # backlogs
    res.write('\t<backlogs>\n')
    for sw in network.switches:
        res.write('\t\t<switch name="' + sw.name() + '">\n');
        for port in sw.ports:
            if port.backlog() > 0:
                res.write('\t\t\t<port num="' + str(port.number()) + '" backlog="'+str(format(port.backlog()/8 , '.0f' ))+'"' +  ' delay="'+str( format(port.delay()*1000000, '.1f') )+'" />\n')
        res.write('\t\t</switch>\n')
    res.write('\t</backlogs>\n')

    res.write('</results>\n')
    res.close()
    file2output(resFile)

""" file2output
    Method to print a file to standard ouput
        file : the path to the xml (input) file
"""
def file2output (file):
    hFile = open(file, "r")
    for line in hFile:
        print(line.rstrip())


import os
import numpy as np
import matplotlib.pyplot as plt
import win32com.client as win32
import time

aspen = win32.Dispatch('Apwn.Document')
print("--- loading aspen .bkp file ---")
aspen.InitFromArchive2(os.path.abspath('simulation/PBR.bkp'))
print("--- .bkp file loaded---")

def run_simulation(temperature, filename):
    print("--- starting simulation ---")
    start_time = time.time()
    catalystWts = np.linspace(100, 200, 11)
    x_buoh, x_buacet = [], []

    # temperature = aspen.Tree.FindNode("\Data\Blocks\PBR\Input\REAC_TEMP").Value
    aspen.Tree.FindNode("\Data\Blocks\PBR\Input\REAC_TEMP").Value = temperature

    for catalyst in catalystWts:
        aspen.Tree.FindNode("\Data\Blocks\PBR\Input\CATWT").Value = catalyst
        aspen.Engine.Run2()
        x_buoh.append(aspen.Tree.FindNode("\Data\Streams\OUTPUT\Output\MOLEFLOW\MIXED\BUTANOL").Value)
        x_buacet.append(aspen.Tree.FindNode("\Data\Streams\OUTPUT\Output\MOLEFLOW\MIXED\BUT-ACET").Value)

    plt.plot(catalystWts, x_buacet, catalystWts, x_buoh)
    plt.title('PBR profile at %s' % temperature)
    plt.legend(['Butyl Acetate', 'Buthanol'])
    plt.xlabel('Catalyst weight (kg)')
    plt.ylabel('Mole flows, mol/h')
    plt.savefig('images/' + filename + '-buac-test.png')
    plt.clf()
    plt.close()
    print("--- %s seconds ---" % (time.time() - start_time))

    response = PbrSimulation(temperature)
    return response

class PbrSimulation:
    def __init__(self, temperature):
        self.temperature = temperature

def close_aspen():
    print("--- closing simulation ---")
    aspen.close()


import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import matplotlib.gridspec as gridspec
import math

sscf_dark_data = [
    [1,    1.892824E7],
    [2,    1.4671248E7],
    [3,    1.432372E7],
    [4,    1.3928736E7],
    [4.25, 1.392728E7],
    [4.5,  1.3926672E7],
    [4.75, 1.3926672E7],
    [4.8,  1.3926784E7],
    [4.9,  1.3926784E7],
    [5,    1.9272504E7]
]

def get_sebf_log(filename="gail/sebf-expert.txt"):
    with open(filename, "r") as f:
        line = f.readline()
        count = 0
        jobs_ep = [] # jobs in an episode
        while line:
            if line.startswith("sortedJobs"):
                jobs_str = line.split(":")[-1].strip()[1:-1].split(",")
                # print(jobs_str)
                count += 1
                jobs = []
                for job_s in jobs_str:
                    job_name, job_sent = job_s.strip().split("(")
                    name = eval(job_name.split("-")[-1])
                    sent = eval(job_sent.split("|")[-1].split("/")[0])
                    jobs.append([name, sent])
                jobs_ep.append(jobs)
                # print(jobs)
            line = f.readline()
        return jobs_ep

def analyse_sebf_log():
    jobs_ep = get_sebf_log()
    ## proceed jobs
    # print(jobs_ep)
    prior_jobs = {}
    sent_list = []
    for jobs in jobs_ep:
        for pr, job in enumerate(jobs):
            size = math.log10(job[1]) if job[1] != 0 else 0
            if size == 0:
                continue
            sent_list.append([pr, size])
            if pr in prior_jobs:
                prior_jobs[pr].append(size)
            else:
                prior_jobs[pr]= [size]
    print(prior_jobs.keys())
    sent_list = np.array(sent_list)

    sns.set_style('white')
    data_sent = pd.DataFrame({'prior':sent_list[:,0], 'sent':sent_list[:,1]})
    sns.scatterplot(data=data_sent, x='prior', y='sent')
    plt.xlabel("Priority")
    plt.ylabel("Sent Size(B)")

    # plt.subplot(2, 2, 2)
    # num_jobs = np.array([[key, len(prior_jobs[key])] for key in prior_jobs])
    # plt.scatter(num_jobs[:, 0], num_jobs[:, 1])
    # plt.xlabel("Priority")
    # plt.ylabel("Number of Coflows")

    avg_jobs = np.array([[key, sum(prior_jobs[key])/len(prior_jobs[key])] for key in prior_jobs])
    data = pd.DataFrame({'x':avg_jobs[:,0], 'y':avg_jobs[:,1]})
    sns.lmplot(data=data, x='x', y='y')
    plt.xlabel('Priority')
    plt.ylabel('Average Sent Size(B)')

    plt.show()

def rebuild_mlfq_based_on_sebf():
    jobs_ep = get_sebf_log()
    jobs_log = []
    for jobs in jobs_ep:
        jobs_log.append([(math.log10(job[1]) if job[1] != 0 else 0) for job in jobs])
    MLFQ = [[],[],[],[],[],[],[],[],[],[]]
    N = 10
    ## 尾链表重叠
    count = 0 # 统计优先级错位的数量
    # for jobs in jobs_log:
    #     if len(jobs) <= N:
    #         for i,job in enumerate(jobs):
    #             MLFQ[i].append(job)
    #     else:
    #         rem = len(jobs) - N
    #         count += (rem*2)
    #         for i in range(N-rem):
    #             MLFQ[i].append(jobs[i])
    #         j = N-rem
    #         for i in range(N-rem, N):
    #             MLFQ[i].append(jobs[j])
    #             MLFQ[i].append(jobs[j+1])
    #             j += 2

    ## 末队列添加
    for jobs in jobs_log:
        if len(jobs) <= N:
            for i,job in enumerate(jobs):
                MLFQ[i].append(job)
        else:
            rem = len(jobs) - N
            count += rem
            for i in range(N):
                MLFQ[i].append(jobs[i])
            for i in range(N, N+rem):
                MLFQ[N-1].append(jobs[i])
    sum_active_c = sum([len(jobs) for jobs in jobs_ep])
    print("total: ", sum_active_c, "mismatch:", count)
    print("Rate of mismatch:", round(count/sum_active_c, 4)*100, "%")

    ## 画图
    nozero_MLFQ = []
    for queue in MLFQ:
        q = []
        for size in queue:
            if size > 0:
                q.append(size)
        nozero_MLFQ.append(q)
    queue_size = np.array([[min(queue), max(queue), sum(queue)/len(queue)] for queue in MLFQ])
    print(queue_size)
    queue_nozero = np.array([[min(queue), max(queue), sum(queue)/len(queue)] for queue in nozero_MLFQ])
    print(queue_nozero)
    # plt.plot(range(queue_size.shape[0]), queue_size[:, 2])
    plt.plot(range(queue_nozero.shape[0]), queue_nozero[:, 0], 'ro-')
    plt.plot(range(queue_nozero.shape[0]), queue_nozero[:, 1], 'b+-')
    plt.plot(range(queue_nozero.shape[0]), queue_nozero[:, 2])
    plt.legend(['min', 'max', 'average'])
    plt.show()

def plot_sscf_dark():
    sns.set_style('white')

    data = np.array(sorted(sscf_dark_data, key=lambda x : x[0]))
    print(data)
    plt.plot(data[:, 0], data[:, 1], 'o-')
    plt.show()

if __name__ == "__main__":
    pass
    # analyse_sebf_log()

    # rebuild_mlfq_based_on_sebf()

    plot_sscf_dark()


#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Author:  Mario S. Könz <mskoenz@gmx.net>
# Date:    14.08.2014 10:24:04 CEST
# File:    calibrate.py

from src_import import *
from src.serializer import *

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtSerialPort import *

import sys

class Q2SerializeIOWidget(QWidget):
    def __init__(self):
        super(Q2SerializeIOWidget, self).__init__()
        #=================== logic ===================
        self.sp = QSerialPort()
        self.sp.setPortName("/dev/ttyUSB0")
        self.sp.open(QIODevice.ReadWrite)

        time.sleep(2)

        self.logic_units = [  pos_class(self.sp)
                            , n_gest_class(self.sp)
                            , gest_class(self.sp, 0)
                            , gest_class(self.sp, 1)
                            , gest_class(self.sp, 2)
                            , gest_class(self.sp, 3)
                            , gest_class(self.sp, 4)
                            , eeprom_write_class(self.sp)
                            , remove_all_class(self.sp)
                            , reset_glove_class(self.sp)
                            , reset_time_class(self.sp)
                            , hist_class(self.sp)
                            , begin_learning_class(self.sp)
                            , learning_progress_class(self.sp)
                            , end_learning_class(self.sp)
                           ]

        self.init_ui()

    def init_ui(self):
        #=================== widgets ==================
        self.lbls = []
        self.texts = []
        self.btns = []
        for l in self.logic_units:

            self.lbls.append(QLabel(l.name(), self))
            self.texts.append(QTextEdit(str(l.data_), self))
            self.btns.append(QPushButton("Read", self))
            self.btns.append(QPushButton("Write", self))
        #=================== properties ===============

        #=================== connects =================
        def read_helper(logic, textw):
            def res():
                logic.read()
                textw.setText(str(logic.data_))
            return res

        def write_helper(logic, textw):
            def res():
                logic.data_ = eval(textw.toPlainText())
                logic.write()
            return res

        for l, l_i in zipi(self.logic_units):
            if hasattr(l, "read"):
                self.btns[2*l_i].clicked.connect(read_helper(l, self.texts[l_i]))
            else:
                self.btns[2*l_i].setEnabled(False)

            if hasattr(l, "write"):
                self.btns[2*l_i + 1].clicked.connect(write_helper(l, self.texts[l_i]))
            else:
                self.btns[2*l_i + 1].setEnabled(False)
        #=================== layout ===================
        grid = QGridLayout(self)

        n_layout = 8

        for w, w_i in zipi(self.lbls):
            grid.addWidget(w, 2*(w_i%n_layout), 3*(w_i//n_layout), 2, 1)

        for w, w_i in zipi(self.texts):
            grid.addWidget(w, 2*(w_i%n_layout), 3*(w_i//n_layout)+1, 2, 1)
        for w, w_i in zipi(self.btns):
            grid.addWidget(w, (w_i%(2*n_layout)), 3*(w_i//(2*n_layout))+2, 1, 1)

        self.setLayout(grid)
        #=================== finish ===================
        self.show()

    def write(self, obj):
        obj.write()

    def read(self, obj):
        obj.read()


def str_sort(words: str):
    """
    This function reorder the given words in a string alphabetically
    :param words: input string from user
    :return: the sorted string
    """
    words_list = words.strip().split(',')
    return ','.join(sorted(words_list))

# main program
word = input('Input a list of words: ')
print(str_sort(word))


from flask import render_template, request, url_for, flash, redirect, Blueprint
from werkzeug.exceptions import abort
from models import Posts
from start import db

posts = Blueprint('posts', __name__)

@posts.route('/')
def home():
    posts = Posts.query.all()
    return render_template('index.html', posts=posts)

@posts.route('/post/<int:post_id>')
def show_post(post_id):
    post = Posts.query.filter_by(id=post_id).first()
    if post is None:
        abort(404)
    return render_template('post.html', post=post)

@posts.route('/create', methods=('GET', 'POST'))
def create():
    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']

        if not title:
            flash('Title is required!')
        if not content:
            flash('Content is required!')

        if title and content:
            post = Posts(title=title, content=content)
            db.session.add(post)
            db.session.commit()
            return redirect(url_for('posts.home'))

    return render_template('create.html')

@posts.route('/edit/<int:post_id>', methods=('GET', 'POST'))
def edit(post_id):
    post = Posts.query.filter_by(id=post_id).first()

    if request.method == 'POST':
        post.title = request.form['title']
        post.content = request.form['content']

        if not post.title:
            flash('Title is required!')
        if not post.content:
            flash('Content is required!')

        if post.title and post.content:
            db.session.add(post)
            db.session.commit()
            return redirect(url_for('posts.show_post', post_id=post_id))

    return render_template('edit.html', post=post)

@posts.route('/delete/<int:post_id>', methods=('POST',))
def delete(post_id):
    post = Posts.query.filter_by(id=post_id).first()
    db.session.delete(post)
    db.session.commit()
    flash(f'"{post.title}" was successfully deleted!')
    return redirect(url_for('posts.home'))


#  Using Euclid's Algorithm to find GCD between two intergers

"""
    step 1: for two intergers x and y , where  x > y , divide x by y.
    step 2: if the reminder r is 0  then stop : GCD is y
    step 3: else set x to y, y to r and repeat step step on till r is o.
"""

def gcd(x,y):
    while ( y !=0):
        t = x
        x = y
        y = t % y

    return x

print(gcd(33,3))


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan_dist = lambda x, y: abs(x[0] - y[0]) + abs(x[1] - y[1])
        n = len(points)
        graph = collections.defaultdict(list)

        for i in range(n):
            for j in range(i+1, n):
                dist = manhattan_dist(points[i], points[j])
                graph[i].append((dist, j))
                graph[j].append((dist, i))

        cnt = 1
        ans = 0
        visited = [0] * n
        heap = graph[0]
        heapify(heap)
        visited[0] = 1

        while heap:
            dist, nei = heappop(heap)
            if not visited[nei]:
                visited[nei] = 1
                cnt += 1
                ans += dist
                for node in graph[nei]: heappush(heap, node)
            if cnt >= n: break

        return ans

Tree, Graph, BFS, DFS/P1584 - minCostToConnectAllPoints.py


class Solution(object):
    def removePalindromeSub(self, s):
        """
        :type s: str
        :rtype: int
        """
        n=len(s)
        if(n==0):
            return 0
        ind1=0
        ind2=n-1
        while(ind1<ind2):
            if(s[ind1]!=s[ind2]):
                return 2
            ind1+=1
            ind2-=1
        return 1


import logging
from typing import Any, Dict, List, Mapping, Optional

from langchain_core.callbacks import CallbackManagerForLLMRun
from langchain_core.language_models.llms import LLM
from langchain_core.pydantic_v1 import Extra, Field, root_validator
from langchain_core.utils import get_from_dict_or_env

from langchain_community.llms.utils import enforce_stop_tokens

logger = logging.getLogger(__name__)

class Petals(LLM):
    """Petals Bloom models.

    To use, you should have the ``petals`` python package installed, and the
    environment variable ``HUGGINGFACE_API_KEY`` set with your API key.

    Any parameters that are valid to be passed to the call can be passed
    in, even if not explicitly saved on this class.

    Example:
        .. code-block:: python

            from langchain_community.llms import petals
            petals = Petals()

    """

    client: Any
    """The client to use for the API calls."""

    tokenizer: Any
    """The tokenizer to use for the API calls."""

    model_name: str = "bigscience/bloom-petals"
    """The model to use."""

    temperature: float = 0.7
    """What sampling temperature to use"""

    max_new_tokens: int = 256
    """The maximum number of new tokens to generate in the completion."""

    top_p: float = 0.9
    """The cumulative probability for top-p sampling."""

    top_k: Optional[int] = None
    """The number of highest probability vocabulary tokens
    to keep for top-k-filtering."""

    do_sample: bool = True
    """Whether or not to use sampling; use greedy decoding otherwise."""

    max_length: Optional[int] = None
    """The maximum length of the sequence to be generated."""

    model_kwargs: Dict[str, Any] = Field(default_factory=dict)
    """Holds any model parameters valid for `create` call
    not explicitly specified."""

    huggingface_api_key: Optional[str] = None

    class Config:
        """Configuration for this pydantic config."""

        extra = Extra.forbid

    @root_validator(pre=True)
    def build_extra(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        """Build extra kwargs from additional params that were passed in."""
        all_required_field_names = {field.alias for field in cls.__fields__.values()}

        extra = values.get("model_kwargs", {})
        for field_name in list(values):
            if field_name not in all_required_field_names:
                if field_name in extra:
                    raise ValueError(f"Found {field_name} supplied twice.")
                logger.warning(
                    f"""WARNING! {field_name} is not default parameter.
                    {field_name} was transferred to model_kwargs.
                    Please confirm that {field_name} is what you intended."""
                )
                extra[field_name] = values.pop(field_name)
        values["model_kwargs"] = extra
        return values

    @root_validator()
    def validate_environment(cls, values: Dict) -> Dict:
        """Validate that api key and python package exists in environment."""
        huggingface_api_key = get_from_dict_or_env(
            values, "huggingface_api_key", "HUGGINGFACE_API_KEY"
        )
        try:
            from petals import AutoDistributedModelForCausalLM
            from transformers import AutoTokenizer

            model_name = values["model_name"]
            values["tokenizer"] = AutoTokenizer.from_pretrained(model_name)
            values["client"] = AutoDistributedModelForCausalLM.from_pretrained(
                model_name
            )
            values["huggingface_api_key"] = huggingface_api_key

        except ImportError:
            raise ImportError(
                "Could not import transformers or petals python package."
                "Please install with `pip install -U transformers petals`."
            )
        return values

    @property
    def _default_params(self) -> Dict[str, Any]:
        """Get the default parameters for calling Petals API."""
        normal_params = {
            "temperature": self.temperature,
            "max_new_tokens": self.max_new_tokens,
            "top_p": self.top_p,
            "top_k": self.top_k,
            "do_sample": self.do_sample,
            "max_length": self.max_length,
        }
        return {**normal_params, **self.model_kwargs}

    @property
    def _identifying_params(self) -> Mapping[str, Any]:
        """Get the identifying parameters."""
        return {**{"model_name": self.model_name}, **self._default_params}

    @property
    def _llm_type(self) -> str:
        """Return type of llm."""
        return "petals"

    def _call(
        self,
        prompt: str,
        stop: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForLLMRun] = None,
        **kwargs: Any,
    ) -> str:
        """Call the Petals API."""
        params = self._default_params
        params = {**params, **kwargs}
        inputs = self.tokenizer(prompt, return_tensors="pt")["input_ids"]
        outputs = self.client.generate(inputs, **params)
        text = self.tokenizer.decode(outputs[0])
        if stop is not None:
            # I believe this is required since the stop tokens
            # are not enforced by the model parameters
            text = enforce_stop_tokens(text, stop)
        return text


import sqlite3

class DBHelper:
    def __init__(self, dbname="todo.sqlite"):
        self.dbname = dbname
        self.conn = sqlite3.connect(dbname)

    def setup(self):
        stmt = "CREATE TABLE IF NOT EXISTS items (owner text, description text)"
        itemidx = "CREATE INDEX IF NOT EXISTS itemIndex ON items (description ASC)"
        ownidx = "CREATE INDEX IF NOT EXISTS ownIndex ON items (owner ASC)"
        self.conn.execute(stmt)
        self.conn.execute(itemidx)
        self.conn.execute(ownidx)
        self.conn.commit()

    def add_item(self, owner, item_text):
        stmt = "INSERT INTO items (owner, description) VALUES (?, ?)"
        args = (owner, item_text)
        self.conn.execute(stmt, args)
        self.conn.commit()

    def delete_item(self, owner, item_text):
        stmt = "DELETE FROM items WHERE owner = (?) AND description = (?)"
        args = (owner, item_text)
        self.conn.execute(stmt, args)
        self.conn.commit()

    def get_items(self, owner):
        stmt = "SELECT description FROM items WHERE owner = (?)"
        args = (owner,)
        return [x[0] for x in self.conn.execute(stmt, args)]


import unittest

import numpy as np
import tensorflow as tf
from keras.models import Model
from keras.layers import Input
from keras.layers.core import Lambda
from keras.layers.embeddings import Embedding

from gather_emb import gather3
from gather_emb import gather_output_shape3

class GatherTestCase(unittest.TestCase):
    def setUp(self):
        self.embs = np.array([
            [0, 0, 0],
            [1, 10, 100],
            [2, 20, 200],
            [3, 30, 300],
            [4, 40, 400],
            [5, 50, 500],
            [6, 60, 600],
            [7, 70, 700],
            [8, 80, 800],
            [9, 90, 900]],
            dtype='float32')
        self.emb_dim = self.embs.shape[1]
        self.token_emb = Embedding(
            input_dim=self.embs.shape[0],
            output_dim=self.emb_dim,
            weights=[self.embs],
            mask_zero=False, # Reshape layer does not support masking.
            trainable=True,
            name='token_emb')
        self.gather_layer = Lambda(gather3, output_shape=gather_output_shape3)

    def make_layer_and_evaluate(self, node_inds, node_rels):
        max_nodes = node_inds.shape[1]
        max_relations = node_rels.shape[2]
        relation_length = node_rels.shape[-1]
        # node_rel specifies node relationships. In case of binary parent-child
        # relations, they are [parent_node, child_node].
        node_rel_input = Input(
            shape=(max_nodes, max_relations, relation_length),
            dtype='int32',
            name='node_rel')
        # Specifies the indices of the dataset node embeddings that are part
        # of the current graph.
        node_inds_input = Input(
            shape=(max_nodes,),
            dtype='int32',
            name='node_inds')

        x = self.token_emb(node_inds_input)
        x = self.gather_layer([x, node_rel_input])
        model = Model(inputs=[node_rel_input, node_inds_input], outputs=[x])
        output = model.predict([node_rels, node_inds])

        batch_size = node_inds.shape[0]
        expected_output_shape = (
            batch_size,
            max_nodes,
            max_relations,
            relation_length,
            self.emb_dim)
        self.assertEqual(expected_output_shape, output.shape,
            msg='Unequal output shape: {0} vs {1}'.format(
            expected_output_shape, output.shape))
        return output

    def test_binary_rel_seq(self):
        node_inds = np.array([[0, 1]], dtype='int32')
        node_rels = np.array([
            [[[0, 0],
              [0, 1]],
             [[1, 0],
              [1, 1]]]],
            dtype='int32')
        assert node_inds.shape[1] == node_rels.shape[1], \
            'Number of nodes must be equal: {0} vs. {1}.'.format(
            node_inds.shape[1], node_rels.shape[1])

        output = self.make_layer_and_evaluate(node_inds, node_rels)
        expected_output = np.array(
            [0, 0, 0,
             0, 0, 0,
             0, 0, 0,
             1, 10, 100,
             1, 10, 100,
             0, 0, 0,
             1, 10, 100,
             1, 10, 100],
            dtype='float32').reshape(output.shape)
        self.assertTrue(np.allclose(expected_output, output),
            msg='\nExpected:\n{0}\nGot:\n{1}'.format(expected_output, output))

    def test_binary_rel_noseq(self):
        node_inds = np.array([[1, 3]], dtype='int32')
        node_rels = np.array([
            [[[0, 0],
              [0, 1]],
             [[1, 0],
              [1, 1]]]],
            dtype='int32')
        assert node_inds.shape[1] == node_rels.shape[1], \
            'Number of nodes must be equal: {0} vs. {1}.'.format(
            node_inds.shape[1], node_rels.shape[1])

        output = self.make_layer_and_evaluate(node_inds, node_rels)
        expected_output = np.array(
            [1, 10, 100,
             1, 10, 100,
             1, 10, 100,
             3, 30, 300,
             3, 30, 300,
             1, 10, 100,
             3, 30, 300,
             3, 30, 300],
            dtype='float32').reshape(output.shape)
        self.assertTrue(np.allclose(expected_output, output),
            msg='\nExpected:\n{0}\nGot:\n{1}'.format(expected_output, output))

    def test_error_out_of_bounds(self):
        node_inds = np.array([[1, 3]], dtype='int32')
        node_rels = np.array([
            [[[0, 0],
              [1, 1]],
             [[1, 0],
              [1, 2]]]],
            dtype='int32')
        assert node_inds.shape[1] == node_rels.shape[1], \
            'Number of nodes must be equal: {0} vs. {1}.'.format(
            node_inds.shape[1], node_rels.shape[1])

        with self.assertRaises(Exception) as context:
            output = self.make_layer_and_evaluate(node_inds, node_rels)
        self.assertTrue('InvalidArgumentError' in str(context.exception))

    def test_binary_rel_max_nodes3(self):
        node_inds = np.array([[1, 3, 4]], dtype='int32')
        node_rels = np.array([
            [[[0, 0],
              [0, 1]],
             [[0, 2],
              [2, 1]],
             [[1, 0],
              [1, 2]]]],
            dtype='int32')
        assert node_inds.shape[1] == node_rels.shape[1], \
            'Number of nodes must be equal: {0} vs. {1}.'.format(
            node_inds.shape[1], node_rels.shape[1])

        output = self.make_layer_and_evaluate(node_inds, node_rels)
        expected_output = np.array(
            [1, 10, 100,
             1, 10, 100,
             1, 10, 100,
             3, 30, 300,
             1, 10, 100,
             4, 40, 400,
             4, 40, 400,
             3, 30, 300,
             3, 30, 300,
             1, 10, 100,
             3, 30, 300,
             4, 40, 400],
            dtype='float32').reshape(output.shape)
        self.assertTrue(np.allclose(expected_output, output),
            msg='\nExpected:\n{0}\nGot:\n{1}'.format(expected_output, output))

    def test_binary_rel_max_rel3(self):
        node_inds = np.array([[2, 5]], dtype='int32')
        node_rels = np.array([
            [[[0, 0],
              [0, 1],
              [1, 0]],
             [[1, 0],
              [1, 1],
              [0, 0]]]],
            dtype='int32')
        assert node_inds.shape[1] == node_rels.shape[1], \
            'Number of nodes must be equal: {0} vs. {1}.'.format(
            node_inds.shape[1], node_rels.shape[1])

        output = self.make_layer_and_evaluate(node_inds, node_rels)
        expected_output = np.array(
            [2, 20, 200,
             2, 20, 200,
             2, 20, 200,
             5, 50, 500,
             5, 50, 500,
             2, 20, 200,
             5, 50, 500,
             2, 20, 200,
             5, 50, 500,
             5, 50, 500,
             2, 20, 200,
             2, 20, 200],
            dtype='float32').reshape(output.shape)
        self.assertTrue(np.allclose(expected_output, output),
            msg='\nExpected:\n{0}\nGot:\n{1}'.format(expected_output, output))

    def test_ternary(self):
        node_inds = np.array([[1, 3]], dtype='int32')
        node_rels = np.array([
            [[[0, 0, 1],
              [0, 1, 0]],
             [[1, 0, 1],
              [1, 1, 1]]]],
            dtype='int32')
        assert node_inds.shape[1] == node_rels.shape[1], \
            'Number of nodes must be equal: {0} vs. {1}.'.format(
            node_inds.shape[1], node_rels.shape[1])

        output = self.make_layer_and_evaluate(node_inds, node_rels)
        expected_output = np.array(
            [1, 10, 100,
             1, 10, 100,
             3, 30, 300,
             1, 10, 100,
             3, 30, 300,
             1, 10, 100,
             3, 30, 300,
             1, 10, 100,
             3, 30, 300,
             3, 30, 300,
             3, 30, 300,
             3, 30, 300],
            dtype='float32').reshape(output.shape)
        self.assertTrue(np.allclose(expected_output, output),
            msg='\nExpected:\n{0}\nGot:\n{1}'.format(expected_output, output))

    def test_batch2(self):
        node_inds = np.array([[1, 3], [3, 6]], dtype='int32')
        node_rels = np.array([
            [[[0, 0],
              [0, 1]],
             [[1, 0],
              [1, 1]]],
            [[[1, 0],
              [0, 1]],
             [[1, 1],
              [0, 0]]]],
            dtype='int32')
        assert node_inds.shape[1] == node_rels.shape[1], \
            'Number of nodes must be equal: {0} vs. {1}.'.format(
            node_inds.shape[1], node_rels.shape[1])

        output = self.make_layer_and_evaluate(node_inds, node_rels)
        expected_output = np.array(
            [1, 10, 100,
             1, 10, 100,
             1, 10, 100,
             3, 30, 300,
             3, 30, 300,
             1, 10, 100,
             3, 30, 300,
             3, 30, 300,
             6, 60, 600,
             3, 30, 300,
             3, 30, 300,
             6, 60, 600,
             6, 60, 600,
             6, 60, 600,
             3, 30, 300,
             3, 30, 300],
            dtype='float32').reshape(output.shape)
        self.assertTrue(np.allclose(expected_output, output),
            msg='\nExpected:\n{0}\nGot:\n{1}'.format(expected_output, output))

if __name__ == '__main__':
    suite1 = unittest.TestLoader().loadTestsFromTestCase(GatherTestCase)
    suites = unittest.TestSuite([suite1])
    unittest.TextTestRunner(verbosity=2).run(suites)


# from itertools import combinations
# str, n=input().split()
# strings=sorted(str)
# for i in range(len(strings)):
#     print(strings[i], end="\n")
# combi=list(combinations(sorted(str),int(n)))

# for i in range(len(combi)):
#     print("".join(combi[i]))

from itertools import combinations
str, n = input().split()
for i in range(1,int(n)+1):
    combi=list(combinations(sorted(str),i))
    for i in combi:
      print("".join(i))


import random
import math
import logging
import torch
import torch.nn as nn
import numpy as np
import networkx as nx
import pandas as pd
import pprint

from typing import List, Tuple, Dict, Union
from ..base import *
from .link_state import *
from ...constants import DQNROUTE_LOGGER
from ...messages import *
from ...memory import *
from ...utils import *
from ...networks import *

MIN_TEMP = 1.5

logger = logging.getLogger(DQNROUTE_LOGGER)

class DQNRouter(LinkStateRouter, RewardAgent):
    """
    A router which implements DQN-routing algorithm
    """
    def __init__(self, batch_size: int, mem_capacity: int, nodes: List[AgentId],
                 optimizer='rmsprop', brain=None, random_init=False, max_act_time=None,
                 additional_inputs=[], **kwargs):
        super().__init__(**kwargs)
        self.batch_size = batch_size
        self.memory = Memory(mem_capacity)
        self.additional_inputs = additional_inputs
        self.nodes = nodes
        self.max_act_time = max_act_time

        if brain is None:
            self.brain = self._makeBrain(additional_inputs=additional_inputs, **kwargs)
            if random_init:
                self.brain.init_xavier()
            else:
                self.brain.restore()
                self.log('Restored model {}'.format(self.brain._label))

        else:
            self.brain = brain

        self.optimizer = get_optimizer(optimizer)(self.brain.parameters())
        self.loss_func = nn.MSELoss()

    def route(self, sender: AgentId, pkg: Package, allowed_nbrs: List[AgentId]) -> Tuple[AgentId, List[Message]]:
        if self.max_act_time is not None and self.env.time() > self.max_act_time:
            return super().route(sender, pkg, allowed_nbrs)
        else:
            to, estimate, saved_state = self._act(pkg, allowed_nbrs)
            reward = self.registerResentPkg(pkg, estimate, to, saved_state)
            return to, [OutMessage(self.id, sender, reward)] if sender[0] != 'world' else []

    def handleMsgFrom(self, sender: AgentId, msg: Message) -> List[Message]:
        if isinstance(msg, RewardMsg):
            action, Q_new, prev_state = self.receiveReward(msg)
            self.memory.add((prev_state, action[1], -Q_new))
            self._replay()
            return []
        else:
            return super().handleMsgFrom(sender, msg)

    def _makeBrain(self, additional_inputs=[], **kwargs):
        return QNetwork(len(self.nodes), additional_inputs=additional_inputs,
                        one_out=False, **kwargs)

    def _act(self, pkg: Package, allowed_nbrs: List[AgentId]):
        state = self._getNNState(pkg, allowed_nbrs)
        prediction = self._predict(state)[0]
        distr = softmax(prediction, MIN_TEMP)
        estimate = -np.dot(prediction, distr)

        to = -1
        while ('router', to) not in allowed_nbrs:
            to = sample_distr(distr)

        return ('router', to), estimate, state

    def _predict(self, x):
        self.brain.eval()
        return self.brain(*map(torch.from_numpy, x))\
                   .clone().detach().numpy()

    def _train(self, x, y):
        self.brain.train()
        self.optimizer.zero_grad()
        output = self.brain(*map(torch.from_numpy, x))
        loss = self.loss_func(output, torch.from_numpy(y))
        loss.backward()
        self.optimizer.step()
        return float(loss)

    def _getAddInput(self, tag, *args, **kwargs):
        if tag == 'amatrix':
            amatrix = nx.convert_matrix.to_numpy_array(
                self.network, nodelist=self.nodes, weight=self.edge_weight,
                dtype=np.float32)
            gstate = np.ravel(amatrix)
            return gstate
        else:
            raise Exception('Unknown additional input: ' + tag)

    def _getNNState(self, pkg: Package, nbrs: List[AgentId]):
        n = len(self.nodes)
        addr = np.array(self.id[1])
        dst = np.array(pkg.dst[1])

        neighbours = np.array(
            list(map(lambda v: v in nbrs, self.nodes)),
            dtype=np.float32)
        input = [addr, dst, neighbours]

        for inp in self.additional_inputs:
            tag = inp['tag']
            add_inp = self._getAddInput(tag)
            if tag == 'amatrix':
                add_inp[add_inp > 0] = 1
            input.append(add_inp)

        return tuple(input)

    def _sampleMemStacked(self):
        """
        Samples a batch of episodes from memory and stacks
        states, actions and values from a batch together
        """
        i_batch = self.memory.sample(self.batch_size)
        batch = [b[1] for b in i_batch]

        states = stack_batch([l[0] for l in batch])
        actions = [l[1] for l in batch]
        values = [l[2] for l in batch]

        return states, actions, values

    def _replay(self):
        """
        Fetches a batch of samples from the memory and fits against them
        """
        states, actions, values = self._sampleMemStacked()
        preds = self._predict(states)

        for i in range(self.batch_size):
            a = actions[i]
            preds[i][a] = values[i]

        self._train(states, preds)

class DQNRouterOO(DQNRouter):
    """
    Variant of DQN router which uses Q-network with scalar output
    """
    def _makeBrain(self, additional_inputs=[], **kwargs):
        return QNetwork(len(self.nodes), additional_inputs=additional_inputs,
                        one_out=True, **kwargs)

    def _act(self, pkg: Package, allowed_nbrs: List[AgentId]):
        state = self._getNNState(pkg, allowed_nbrs)
        prediction = self._predict(state).flatten()
        distr = softmax(prediction, MIN_TEMP)
        to_idx = sample_distr(distr)
        estimate = -np.dot(prediction, distr)

        saved_state = [s[to_idx] for s in state]
        to = allowed_nbrs[to_idx]
        return to, estimate, saved_state

    def _nodeRepr(self, node):
        return np.array(node)

    def _getAddInput(self, tag, nbr):
        return super()._getAddInput(tag)

    def _getNNState(self, pkg: Package, nbrs: List[AgentId]):
        n = len(self.nodes)
        addr = self._nodeRepr(self.id[1])
        dst = self._nodeRepr(pkg.dst[1])

        get_add_inputs = lambda nbr: [self._getAddInput(inp['tag'], nbr)
                                      for inp in self.additional_inputs]

        input = [[addr, dst, self._nodeRepr(v[1])] + get_add_inputs(v)
                 for v in nbrs]
        return stack_batch(input)

    def _replay(self):
        states, _, values = self._sampleMemStacked()
        self._train(states, np.expand_dims(np.array(values, dtype=np.float32), axis=0))

class DQNRouterEmb(DQNRouterOO):
    """
    Variant of DQNRouter which uses graph embeddings instead of
    one-hot label encodings.
    """
    def __init__(self, embedding: Union[dict, Embedding], edges_num: int, **kwargs):
        # Those are used to only re-learn the embedding when the topology is changed
        self.prev_num_nodes = 0
        self.prev_num_edges = 0
        self.init_edges_num = edges_num
        self.network_initialized = False

        if type(embedding) == dict:
            self.embedding = get_embedding(**embedding)
        else:
            self.embedding = embedding

        super().__init__(**kwargs)

    def _makeBrain(self, additional_inputs=[], **kwargs):
        return QNetwork(len(self.nodes), additional_inputs=additional_inputs,
                        embedding_dim=self.embedding.dim, one_out=True, **kwargs)

    def _nodeRepr(self, node):
        return self.embedding.transform(node).astype(np.float32)

    def networkStateChanged(self):
        num_nodes = len(self.network.nodes)
        num_edges = len(self.network.edges)

        if not self.network_initialized and num_nodes == len(self.nodes) and num_edges == self.init_edges_num:
            self.network_initialized = True

        if self.network_initialized and (num_edges != self.prev_num_edges or num_nodes != self.prev_num_nodes):
            self.prev_num_nodes = num_nodes
            self.prev_num_edges = num_edges
            self.embedding.fit(self.network, weight=self.edge_weight)
            # self.log(pprint.pformat(self.embedding._X), force=self.id[1] == 0)

class DQNRouterNetwork(NetworkRewardAgent, DQNRouter):
    pass

class DQNRouterOONetwork(NetworkRewardAgent, DQNRouterOO):
    pass

class DQNRouterEmbNetwork(NetworkRewardAgent, DQNRouterEmb):
    pass

class ConveyorAddInputMixin:
    """
    Mixing which adds conveyor-specific additional NN inputs support
    """
    def _getAddInput(self, tag, nbr=None):
        if tag == 'work_status':
            return np.array(
                list(map(lambda n: self.network.nodes[n].get('works', False), self.nodes)),
                dtype=np.float32)
        if tag == 'working':
            nbr_works = 1 if self.network.nodes[nbr].get('works', False) else 0
            return np.array(nbr_works, dtype=np.float32)
        else:
            return super()._getAddInput(tag, nbr)

class DQNRouterConveyor(LSConveyorMixin, ConveyorRewardAgent, ConveyorAddInputMixin, DQNRouter):
    pass

class DQNRouterOOConveyor(LSConveyorMixin, ConveyorRewardAgent, ConveyorAddInputMixin, DQNRouterOO):
    pass

class DQNRouterEmbConveyor(LSConveyorMixin, ConveyorRewardAgent, ConveyorAddInputMixin, DQNRouterEmb):
    pass


from pandas import read_csv
import numpy
import IntegratedPipeline as CT

# # Set the pipelines
# pipelines = CT.special_datastory_pipelines_for_Scottish_government_report

# # # Dataset of Drug-related death. Sort by gender, age, drug type.
col_names = ['years', 'drug related deaths', 'males', 'females', 'Deaths under age 14',
             'Deaths between the ages of 15 and 24', 'Deaths between the ages of 25 and 34',
             'Deaths between the ages of 35 and 44', 'Deaths between the ages of 45 and 54',
             'Deaths between the ages of 55 and 64', 'Deaths ages over 65', 'average age of death',
             'dead by Heroin/morphine 2', 'dead by Methadone', 'dead by Heroin/morphine, Methadone or Bupren-orphine',
             'dead by Codeine or a codeine-containing compound',
             'dead by Dihydro-codeine or a d.h.c-containing compound', 'dead by any opiate or opioid', ]
data = read_csv("./data/drugdeathsexagetype.csv", header=None, names=col_names)

# Q1. What are the trends in drug-related deaths from 1996 to 2020?
# # Set the pipelines
pipelines = CT.special_datastory_pipelines_for_Scottish_government_report
Xcolname = "years"; ycolname = "drug related deaths"
X = data.years; y = data[ycolname] # Features and Target variable
pipelines.segmentedregression_fit(X, y, Xcolname, ycolname, level=1,
             graph=False, base=False, r2=False, p=False,
             breakpointnum=5, governmentdrug=True, governmentchild=False)
# Q2. How has the number of drug-related deaths of men and women changed from 1996 to 2020?
y1name = "males"
y2name = "females"
y1 = data[y1name]
y2 = data[y2name]
model = "magnificationcompare"
pipelines.dependentcompare_con(model, X, y1, y2, Xcolname, y1name, y2name, begin=4, end=24)

# # # Dataset of The amount of drugs found in the deceased, and the cause of death
col_names = ['Year', 'all drug-related deaths', 'more than one drug was found', 'only one drug was found',
             'more than one drug was found in %', 'more than one drug was found to be present in the body',
             'accidental poisonings']
data = read_csv("./data/onedrug.csv", header=None, names=col_names)
Xcolname = "Year"
ycolname1 = "accidental poisonings"
ycolname2 = "all drug-related deaths"
X = data.Year  # Features
y1 = data[ycolname1]
y2 = data[ycolname2]

# Q3. Accidental poisoning accounts for what percent of drug-related deaths?
m = "independenttwopointcomparison"
pipelines.independenttwopointcompare_con(m, X, Xcolname, y1, y2, ycolname1, ycolname2, point="", mode="mag")
# Q4. More than one drug was found in what percent of the dead?
ycolname1 = "more than one drug was found to be present in the body"
y1 = data[ycolname1]
pipelines.independenttwopointcompare_con(m, X, Xcolname, y1, y2, ycolname1, ycolname2, point="", mode="mag")

# # # Dataset of Drug-related death number Sort by drug type
col_names = ['Year', 'death by ‘street’ benzodiazepines (such as etizolam)',
             'death by methadone', 'death by heroin/morphine',
             'death by gabapentin and/or pregabalin',
             'death by cocaine', 'death by opiates/opioids (such as heroin/morphine and methadone)',
             'death by benzodiazepines (such as diazepam and etizolam)']
data = read_csv("./data/drugsubstancesimplicated.csv", header=None, names=col_names)
X = data.Year  # Features
Xcolname = "Year"
ycolnames = ["death by ‘street’ benzodiazepines (such as etizolam)",
             "death by methadone", "death by heroin/morphine",
             "death by gabapentin and/or pregabalin",
             "death by cocaine", "death by opiates/opioids (such as heroin/morphine and methadone)",
             "death by benzodiazepines (such as diazepam and etizolam)"]
begin = 0
end = numpy.size(X) - 1
y = data[ycolnames]
# Q5. How many of the deceased were caused by the each of the following drugs?
model = 1
category_name = " number of deaths where one or more of the following substances "
pipelines.batchprovessing_con(model, X, y, Xcolname, ycolnames, category_name, end, begin=0)


#!//home/pi/Desktop/MetaBell
#motion button camera trigger
import RPi.GPIO as GPIO
from picamera import PiCamera

#global number

GPIO.setmode(GPIO.BOARD)

number = 0

GPIO.setup(11,GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(7,GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
temp = 0
camera = PiCamera()
while True:

    if GPIO.input(11) == GPIO.HIGH or GPIO.input(7) == GPIO.HIGH :
        temp = 1
    if ((GPIO.input(11) == GPIO.LOW) and (temp==1)) or ((GPIO.input(7) == GPIO.LOW) and temp == 1):
        temp = 0
        print("puh")
        print(number)

        filename = "/home/pi/Desktop/MetaBell/test"+str(number)+".jpg"
        print(filename)
        #camera.start_preview()
        camera.capture(filename)
        number += 1


import pygame

def main():
    pygame.init()
    pygame.mixer.init()
    pantalla = pygame.display.set_mode([800, 800])
    pygame.display.set_caption("Laberinto mamadisimo")
    salir = False
    reloj1 = pygame.time.Clock()
    blanco=(255,255,255)

    fuente1=pygame.font.SysFont("calibri",16,True,False)
    fuente2=pygame.font.SysFont("Timesnewroman",36,True,True)

    presentacion=fuente2.render("MERLINO PRODUCTIONS",0,blanco)
    presentacion1=fuente2.render("PRESENTS",0,blanco)
    presentacion2=fuente2.render("ZOMBIE ENVOLU 2",0,blanco)

    while salir != True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                salir = True

        reloj1.tick(20)
        pantalla.fill((0,0,0))
        pantalla.blit(presentacion2,(220,275))
        pygame.display.update()

    pygame.quit()

main()


#      ___          ___       ___          ___          ___          ___
#     /\  \        /\  \     /\  \        /\  \        /\  \        /\  \
#    /::\  \      /::\  \    \:\  \      /::\  \      /::\  \      /::\  \
#   /:/\:\  \    /:/\:\  \    \:\  \    /:/\:\  \    /:/\:\  \    /:/\:\  \
#  /:/  \:\  \  /:/  \:\  \   /::\  \  /::\~\:\  \  /::\~\:\  \  /::\~\:\  \
# /:/__/ \:\__\/:/__/ \:\__\ /:/\:\__\/:/\:\ \:\__\/:/\:\ \:\__\/:/\:\ \:\__\
# \:\  \ /:/  /\:\  \  \/__//:/  \/__/\/_|::\/:/  /\:\~\:\ \/__/\:\~\:\ \/__/
#  \:\  /:/  /  \:\  \     /:/  /        |:|::/  /  \:\ \:\__\   \:\ \:\__\
#   \:\/:/  /    \:\  \    \/__/         |:|\/__/    \:\ \/__/    \:\ \/__/
#    \::/  /      \:\__\                 |:|  |       \:\__\       \:\__\
#     \/__/        \/__/                  \|__|        \/__/        \/__/
#
#
#
#                      .----------------.----------------.
#                     /|               /|               /|
#                    / |              / |              / |
#                   /  |      6      /  |     7       /  |
#                  /   |            /   |            /   |
#                 .----------------.----+-----------.    |
#                /|    . ---------/|----.----------/|----.
#               / |   /|         / |   /|         / |   /|
#              /  |  / |  4     /  |  / |   5    /  |  / |
#             /   | /  |       /   | /  |       /   | /  |
#            . -------------- .----------------.    |/   |
#            |    . ---+------|----.----+------|----.    |
#            |   /|    .______|___/|____.______|___/|____.
#            |  / |   /    2  |  / |   /     3 |  / |   /
#            | /  |  /        | /  |  /        | /  |  /
#            . ---+---------- . ---+---------- .    | /
#            |    |/          |    |/          |    |/             z
#            |    . ----------|----.-----------|----.              ^   y
#            |   /      0     |   /       1    |   /               |  /
#            |  /             |  /             |  /                | /
#            | /              | /              | /                 o----> x
#            . -------------- . -------------- .
#
#
# Face Refinement:
#
#      2_______________3                    _______________
#      |               |                   |       |       |
#   ^  |               |                   |   2   |   3   |
#   |  |               |                   |       |       |
#   |  |       x       |        --->       |-------+-------|
#   t1 |               |                   |       |       |
#      |               |                   |   0   |   1   |
#      |_______________|                   |_______|_______|
#      0      t0-->    1
#
#
# Face and Edge naming conventions:
#
#                      fZp
#                       |
#                 6 ------eX3------ 7
#                /|     |         / |
#               /eZ2    .        / eZ3
#             eY2 |        fYp eY3  |
#             /   |            / fXp|
#            4 ------eX2----- 5     |
#            |fXm 2 -----eX1--|---- 3          z
#           eZ0  /            |  eY1           ^   y
#            | eY0   .  fYm  eZ1 /             |  /
#            | /     |        | /              | /
#            0 ------eX0------1                o----> x
#                    |
#                   fZm
#
#
#            fX                                  fY
#      2___________3                       2___________3
#      |     e1    |                       |     e1    |
#      |           |                       |           |
#   e0 |     x     | e2      z          e0 |     x     | e2      z
#      |           |         ^             |           |         ^
#      |___________|         |___> y       |___________|         |___> x
#      0    e3     1                       0    e3     1
#           fZ
#      2___________3
#      |     e1    |
#      |           |
#   e0 |     x     | e2      y
#      |           |         ^
#      |___________|         |___> x
#      0    e3     1

import properties

from .base import BaseTensorMesh
from .InnerProducts import InnerProducts
from .MeshIO import TreeMeshIO
from . import utils
from .tree_ext import _TreeMesh, TreeCell
import numpy as np
from scipy.spatial import Delaunay
import scipy.sparse as sp
from six import integer_types

from discretize.utils.codeutils import requires
# matplotlib is a soft dependencies for discretize
try:
    import matplotlib.pyplot as plt
    import matplotlib
except ImportError:
    matplotlib = False

class TreeMesh(_TreeMesh, BaseTensorMesh, InnerProducts, TreeMeshIO):
    """
    TreeMesh is a class for adaptive QuadTree (2D) and OcTree (3D) meshes.
    """
    _meshType = 'TREE'

    #inheriting stuff from BaseTensorMesh that isn't defined in _QuadTree
    def __init__(self, h=None, x0=None, **kwargs):
        if 'h' in kwargs.keys():
            h = kwargs.pop('h')
        if 'x0' in kwargs.keys():
            x0 = kwargs.pop('x0')
        # print(h, x0)
        BaseTensorMesh.__init__(self, h, x0)#TODO:, **kwargs) # pass the kwargs for copy/paste

        nx = len(self.h[0])
        ny = len(self.h[1])
        nz = len(self.h[2]) if self.dim == 3 else 2
        def is_pow2(num): return ((num & (num - 1)) == 0) and num != 0
        if not (is_pow2(nx) and is_pow2(ny) and is_pow2(nz)):
            raise ValueError("length of cell width vectors must be a power of 2")
        # Now can initialize cpp tree parent
        _TreeMesh.__init__(self, self.h, self.x0)

        if 'cell_levels' in kwargs.keys() and 'cell_indexes' in kwargs.keys():
            inds = kwargs.pop('cell_indexes')
            levels = kwargs.pop('cell_levels')
            self.__setstate__((inds, levels))

    def __repr__(self):
        """Plain text representation."""
        mesh_name = '{0!s}TreeMesh'.format(('Oc' if self.dim==3 else 'Quad'))

        top = "\n"+mesh_name+": {0:2.2f}% filled\n\n".format(self.fill*100)

        # Number of cells per level
        level_count = self._count_cells_per_index()
        non_zero_levels = np.nonzero(level_count)[0]
        cell_display = ["Level : Number of cells"]
        cell_display.append("-----------------------")
        for level in non_zero_levels:
            cell_display.append("{:^5} : {:^15}".format(level, level_count[level]))
        cell_display.append("-----------------------")
        cell_display.append("Total : {:^15}".format(self.nC))

        extent_display =     ["            Mesh Extent       "]
        extent_display.append("        min     ,     max     ")
        extent_display.append("   ---------------------------")
        dim_label = {0:'x',1:'y',2:'z'}
        for dim in range(self.dim):
            n_vector = getattr(self, 'vectorN'+dim_label[dim])
            extent_display.append("{}: {:^13},{:^13}".format(dim_label[dim], n_vector[0], n_vector[-1]))

        for i, line in enumerate(extent_display):
            if i==len(cell_display):
                cell_display.append(" "*(len(cell_display[0])-3-len(line)))
            cell_display[i] += 3*" " + line

        h_display =     ['     Cell Widths    ']
        h_display.append("    min   ,   max   ")
        h_display.append("-"*(len(h_display[0])))
        h_gridded = self.h_gridded
        mins = np.min(h_gridded,axis=0)
        maxs = np.max(h_gridded,axis=0)
        for dim in range(self.dim):
            h_display.append("{:^10}, {:^10}".format(mins[dim], maxs[dim]))

        for i, line in enumerate(h_display):
            if i==len(cell_display):
                cell_display.append(" "*len(cell_display[0]))
            cell_display[i] += 3*" " + line

        return top+"\n".join(cell_display)

    def _repr_html_(self):
        """html representation"""
        mesh_name = '{0!s}TreeMesh'.format(('Oc' if self.dim==3 else 'Quad'))
        level_count = self._count_cells_per_index()
        non_zero_levels = np.nonzero(level_count)[0]
        dim_label = {0:'x',1:'y',2:'z'}
        h_gridded = self.h_gridded
        mins = np.min(h_gridded,axis=0)
        maxs = np.max(h_gridded,axis=0)

        style = " style='padding: 5px 20px 5px 20px;'"
        #Cell level table:
        cel_tbl =  "
\n"
        cel_tbl += "
\n"
        cel_tbl += "Level	\n"
        cel_tbl += "Number of cells	\n"
        cel_tbl += "
\n"
        for level in non_zero_levels:
            cel_tbl += "
\n"
            cel_tbl += "{}	\n".format(level)
            cel_tbl += "{}	\n".format(level_count[level])
            cel_tbl += "
\n"
        cel_tbl += "
\n"
        cel_tbl += " Total 	\n"
        cel_tbl += " {} 	\n".format(self.nC)
        cel_tbl += "
\n"
        cel_tbl += "
\n"

        det_tbl =  "
\n"
        det_tbl += "
\n"
        det_tbl += "	\n"
        det_tbl += "Mesh extent	\n"
        det_tbl += "Cell widths	\n"
        det_tbl += "
\n"

        det_tbl += "
\n"
        det_tbl += "	\n"
        det_tbl += "min	\n"
        det_tbl += "max	\n"
        det_tbl += "min	\n"
        det_tbl += "max	\n"
        det_tbl += "
\n"
        for dim in range(self.dim):
            n_vector = getattr(self, 'vectorN'+dim_label[dim])
            det_tbl += "
\n"
            det_tbl += "{}	\n".format(dim_label[dim])
            det_tbl += "{}	\n".format(n_vector[0])
            det_tbl += "{}	\n".format(n_vector[-1])
            det_tbl += "{}	\n".format(mins[dim])
            det_tbl += "{}	\n".format(maxs[dim])
            det_tbl += "
\n"
        det_tbl += "
\n"

        full_tbl =  "
\n"
        full_tbl += "
\n"
        full_tbl += "{}	\n".format(mesh_name)
        full_tbl += "{0:2.2f}% filled	\n".format(100*self.fill)
        full_tbl += "
\n"
        full_tbl += "
\n"

        full_tbl += "\n"
        full_tbl += cel_tbl
        full_tbl += "	\n"

        full_tbl += "\n"
        full_tbl += det_tbl
        full_tbl += "	\n"

        full_tbl += "
\n"
        full_tbl += "
\n"

        return full_tbl

    @properties.validator('x0')
    def _x0_validator(self, change):
        self._set_x0(change['value'])

    @property
    def vntF(self):
        """Total number of hanging and non-hanging faces in a [nx,ny,nz] form"""
        return [self.ntFx, self.ntFy] + ([] if self.dim == 2 else [self.ntFz])

    @property
    def vntE(self):
        """Total number of hanging and non-hanging edges in a [nx,ny,nz] form"""
        return [self.ntEx, self.ntEy] + ([] if self.dim == 2 else [self.ntEz])

    @property
    def cellGradStencil(self):
        if getattr(self, '_cellGradStencil', None) is None:

            self._cellGradStencil = sp.vstack([
                self._cellGradxStencil, self._cellGradyStencil
            ])
            if self.dim == 3:
                self._cellGradStencil = sp.vstack([
                    self._cellGradStencil, self._cellGradzStencil
                ])

        return self._cellGradStencil

    @property
    def cellGrad(self):
        """
        Cell centered Gradient operator built off of the faceDiv operator.
        Grad =  - (Mf)^{-1} * Div * diag (volume)
        """
        if getattr(self, '_cellGrad', None) is None:

            i_s = self.faceBoundaryInd

            ix = np.ones(self.nFx)
            ix[i_s[0]] = 0.
            ix[i_s[1]] = 0.
            Pafx = sp.diags(ix)

            iy = np.ones(self.nFy)
            iy[i_s[2]] = 0.
            iy[i_s[3]] = 0.
            Pafy = sp.diags(iy)

            MfI = self.getFaceInnerProduct(invMat=True)

            if self.dim == 2:
                Pi = sp.block_diag([Pafx, Pafy])

            elif self.dim == 3:
                iz = np.ones(self.nFz)
                iz[i_s[4]] = 0.
                iz[i_s[5]] = 0.
                Pafz = sp.diags(iz)
                Pi = sp.block_diag([Pafx, Pafy, Pafz])

            self._cellGrad = -Pi * MfI * self.faceDiv.T * sp.diags(self.vol)

        return self._cellGrad

    @property
    def cellGradx(self):
        """
        Cell centered Gradient operator in x-direction (Gradx)
        Grad = sp.vstack((Gradx, Grady, Gradz))
        """
        if getattr(self, '_cellGradx', None) is None:

            nFx = self.nFx
            i_s = self.faceBoundaryInd

            ix = np.ones(self.nFx)
            ix[i_s[0]] = 0.0
            ix[i_s[1]] = 0.0
            Pafx = sp.diags(ix)

            MfI = self.getFaceInnerProduct(invMat=True)
            MfIx = sp.diags(MfI.diagonal()[:nFx])

            self._cellGradx = (
                -Pafx * MfIx * self.faceDivx.T * sp.diags(self.vol)
            )

        return self._cellGradx

    @property
    def cellGrady(self):
        """
        Cell centered Gradient operator in y-direction (Grady)
        Grad = sp.vstack((Gradx, Grady, Gradz))
        """
        if getattr(self, '_cellGrady', None) is None:

            nFx = self.nFx
            nFy = self.nFy
            i_s = self.faceBoundaryInd

            iy = np.ones(self.nFy)
            iy[i_s[2]] = 0.
            iy[i_s[3]] = 0.
            Pafy = sp.diags(iy)

            MfI = self.getFaceInnerProduct(invMat=True)
            MfIy = sp.diags(MfI.diagonal()[nFx:nFx+nFy])

            self._cellGrady = (
                -Pafy * MfIy * self.faceDivy.T * sp.diags(self.vol)
            )

        return self._cellGrady

    @property
    def cellGradz(self):
        """
        Cell centered Gradient operator in z-direction (Gradz)
        Grad = sp.vstack((Gradx, Grady, Gradz))
        """
        if self.dim == 2:
            raise TypeError("z derivative not defined in 2D")
        if getattr(self, '_cellGradz', None) is None:

            nFx = self.nFx
            nFy = self.nFy
            i_s = self.faceBoundaryInd

            iz = np.ones(self.nFz)
            iz[i_s[4]] = 0.
            iz[i_s[5]] = 0.
            Pafz = sp.diags(iz)

            MfI = self.getFaceInnerProduct(invMat=True)
            MfIz = sp.diags(MfI.diagonal()[nFx+nFy:])

            self._cellGradz = (
                -Pafz * MfIz * self.faceDivz.T * sp.diags(self.vol)
            )

        return self._cellGradz

    @property
    def faceDivx(self):
        if getattr(self, '_faceDivx', None) is None:
            self._faceDivx = self.faceDiv[:, :self.nFx]
        return self._faceDivx

    @property
    def faceDivy(self):
        if getattr(self, '_faceDivy', None) is None:
            self._faceDivy = self.faceDiv[:, self.nFx:self.nFx+self.nFy]
        return self._faceDivy

    @property
    def faceDivz(self):
        if getattr(self, '_faceDivz', None) is None:
            self._faceDivz = self.faceDiv[:, self.nFx+self.nFy:]
        return self._faceDivz

    def point2index(self, locs):
        """Finds cells that contain the given points.
        Returns an array of index values of the cells that contain the given
        points

        Parameters
        ----------
        locs: array_like of shape (N, dim)
            points to search for the location of

        Returns
        -------
        numpy.array of integers of length(N)
            Cell indices that contain the points
        """
        locs = utils.asArray_N_x_Dim(locs, self.dim)
        inds = self._get_containing_cell_indexes(locs)
        return inds

    def cell_levels_by_index(self, indices):
        """Fast function to return a list of levels for the given cell indices

        Parameters
        ----------
        index: array_like of length (N)
            Cell indexes to query

        Returns
        -------
        numpy.array of length (N)
            Levels for the cells.
        """

        return self._cell_levels_by_indexes(indices)

    def getInterpolationMat(self, locs, locType, zerosOutside=False):
        """ Produces interpolation matrix

        Parameters
        ----------
        loc : numpy.ndarray
            Location of points to interpolate to

        locType: str
            What to interpolate

            locType can be::

                'Ex'    -> x-component of field defined on edges
                'Ey'    -> y-component of field defined on edges
                'Ez'    -> z-component of field defined on edges
                'Fx'    -> x-component of field defined on faces
                'Fy'    -> y-component of field defined on faces
                'Fz'    -> z-component of field defined on faces
                'N'     -> scalar field defined on nodes
                'CC'    -> scalar field defined on cell centers

        Returns
        -------
        scipy.sparse.csr_matrix
            M, the interpolation matrix

        """
        locs = utils.asArray_N_x_Dim(locs, self.dim)
        if locType not in ['N', 'CC', "Ex", "Ey", "Ez", "Fx", "Fy", "Fz"]:
            raise Exception('locType must be one of N, CC, Ex, Ey, Ez, Fx, Fy, or Fz')

        if self.dim == 2 and locType in ['Ez', 'Fz']:
            raise Exception('Unable to interpolate from Z edges/face in 2D')

        locs = np.require(np.atleast_2d(locs), dtype=np.float64, requirements='C')

        if locType == 'N':
            Av = self._getNodeIntMat(locs, zerosOutside)
        elif locType in ['Ex', 'Ey', 'Ez']:
            Av = self._getEdgeIntMat(locs, zerosOutside, locType[1])
        elif locType in ['Fx', 'Fy', 'Fz']:
            Av = self._getFaceIntMat(locs, zerosOutside, locType[1])
        elif locType in ['CC']:
            Av = self._getCellIntMat(locs, zerosOutside)
        return Av

    @property
    def permuteCC(self):
        """Permutation matrix re-ordering of cells sorted by x, then y, then z"""
        # TODO: cache these?
        P = np.lexsort(self.gridCC.T) # sort by x, then y, then z
        return sp.identity(self.nC).tocsr()[P]

    @property
    def permuteF(self):
        """Permutation matrix re-ordering of faces sorted by x, then y, then z"""
        # TODO: cache these?
        Px = np.lexsort(self.gridFx.T)
        Py = np.lexsort(self.gridFy.T)+self.nFx
        if self.dim == 2:
            P = np.r_[Px, Py]
        else:
            Pz = np.lexsort(self.gridFz.T)+(self.nFx+self.nFy)
            P = np.r_[Px, Py, Pz]
        return sp.identity(self.nF).tocsr()[P]

    @property
    def permuteE(self):
        """Permutation matrix re-ordering of edges sorted by x, then y, then z"""
        # TODO: cache these?
        Px = np.lexsort(self.gridEx.T)
        Py = np.lexsort(self.gridEy.T) + self.nEx
        if self.dim == 2:
            P = np.r_[Px, Py]
        if self.dim == 3:
            Pz = np.lexsort(self.gridEz.T) + (self.nEx+self.nEy)
            P = np.r_[Px, Py, Pz]
        return sp.identity(self.nE).tocsr()[P]

    @requires({'matplotlib': matplotlib})
    def plotSlice(
        self, v, vType='CC',
        normal='Z', ind=None, grid=False, view='real',
        ax=None, clim=None, showIt=False,
        pcolorOpts=None, streamOpts=None, gridOpts=None,
        range_x=None, range_y=None,
    ):

        if pcolorOpts is None:
            pcolorOpts = {}
        if streamOpts is None:
            streamOpts = {'color': 'k'}
        if gridOpts is None:
            gridOpts = {'color': 'k', 'alpha': 0.5}
        vTypeOpts = ['CC', 'N', 'F', 'E', 'Fx', 'Fy', 'Fz', 'E', 'Ex', 'Ey', 'Ez']
        viewOpts = ['real', 'imag', 'abs']
        normalOpts = ['X', 'Y', 'Z']
        if vType not in vTypeOpts:
            raise ValueError(
                "vType must be in ['{0!s}']".format("', '".join(vTypeOpts))
            )
        if self.dim == 2:
            raise NotImplementedError(
                'Must be a 3D mesh. Use plotImage.'
            )
        if view == 'vec':
            raise NotImplementedError(
                'Vector view plotting is not implemented for TreeMesh (yet)'
            )
        if view not in viewOpts:
            raise ValueError(
                "view must be in ['{0!s}']".format("', '".join(viewOpts))
            )
        normal = normal.upper()
        if normal not in normalOpts:
            raise ValueError(
                "normal must be in ['{0!s}']".format("', '".join(normalOpts))
            )

        if not isinstance(grid, bool):
            raise TypeError('grid must be a boolean')

        normalInd = {'X': 0, 'Y': 1, 'Z': 2}[normal]
        antiNormalInd = {'X': [1, 2], 'Y': [0, 2], 'Z': [0, 1]}[normal]

        h2d = (self.h[antiNormalInd[0]], self.h[antiNormalInd[1]])
        x2d = (self.x0[antiNormalInd[0]], self.x0[antiNormalInd[1]])

        #: Size of the sliced dimension
        szSliceDim = len(self.h[normalInd])
        if ind is None:
            ind = int(szSliceDim//2)

        cc_tensor = [None, None, None]
        for i in range(3):
            cc_tensor[i] = np.cumsum(np.r_[self.x0[i], self.h[i]])
            cc_tensor[i] = (cc_tensor[i][1:] + cc_tensor[i][:-1])*0.5
        slice_loc = cc_tensor[normalInd][ind]

        if type(ind) not in integer_types:
            raise ValueError('ind must be an integer')

        # create a temporary TreeMesh with the slice through
        temp_mesh = TreeMesh(h2d, x2d)
        level_diff = self.max_level - temp_mesh.max_level

        XS = [None, None, None]
        XS[antiNormalInd[0]], XS[antiNormalInd[1]] = np.meshgrid(cc_tensor[antiNormalInd[0]],
                                                                 cc_tensor[antiNormalInd[1]])
        XS[normalInd] = np.ones_like(XS[antiNormalInd[0]])*slice_loc
        loc_grid = np.c_[XS[0].reshape(-1), XS[1].reshape(-1), XS[2].reshape(-1)]
        inds = np.unique(self._get_containing_cell_indexes(loc_grid))

        grid2d = self.gridCC[inds][:, antiNormalInd]
        levels = self._cell_levels_by_indexes(inds) - level_diff
        temp_mesh.insert_cells(grid2d, levels)
        tm_gridboost = np.empty((temp_mesh.nC, 3))
        tm_gridboost[:, antiNormalInd] = temp_mesh.gridCC
        tm_gridboost[:, normalInd] = slice_loc

        # interpolate values to self.gridCC if not 'CC'
        if vType is not 'CC':
            aveOp = 'ave' + vType + '2CC'
            Av = getattr(self, aveOp)
            if v.size == Av.shape[1]:
                v = Av*v
            elif len(vType) == 2:
                # was one of Fx, Fy, Fz, Ex, Ey, Ez
                # assuming v has all three components in these cases
                vec_ind = {'x': 0, 'y': 1, 'z': 2}[vType[1]]
                if vType[0] == 'E':
                    i_s = np.cumsum([0, self.nEx, self.nEy, self.nEz])
                elif vType[0] == 'F':
                    i_s = np.cumsum([0, self.nFx, self.nFy, self.nFz])
                v = v[i_s[vec_ind]:i_s[vec_ind+1]]
                v = Av*v

        # interpolate values from self.gridCC to grid2d
        ind_3d_to_2d = self._get_containing_cell_indexes(tm_gridboost)
        v2d = v[ind_3d_to_2d]

        if ax is None:
            plt.figure()
            ax = plt.subplot(111)
        elif not isinstance(ax, matplotlib.axes.Axes):
            raise Exception("ax must be an matplotlib.axes.Axes")

        out = temp_mesh.plotImage(
            v2d, vType='CC',
            grid=grid, view=view,
            ax=ax, clim=clim, showIt=False,
            pcolorOpts=pcolorOpts,
            gridOpts=gridOpts,
            range_x=range_x,
            range_y=range_y)

        ax.set_xlabel('y' if normal == 'X' else 'x')
        ax.set_ylabel('y' if normal == 'Z' else 'z')
        ax.set_title(
            'Slice {0:d}, {1!s} = {2:4.2f}'.format(ind, normal, slice_loc)
        )
        if showIt:
            plt.show()
        return tuple(out)

    def serialize(self):
        serial = BaseTensorMesh.serialize(self)
        inds, levels = self.__getstate__()
        serial['cell_indexes'] = inds.tolist()
        serial['cell_levels'] = levels.tolist()
        return serial

    @classmethod
    def deserialize(cls, serial):
        mesh = cls(**serial)
        return mesh

    def __reduce__(self):
        return TreeMesh, (self.h, self.x0), self.__getstate__()