text:
import numpy as np

from .utils import PAD_TOKEN, UNK_TOKEN

class TwitterDataset:
    """Class capable of loading CIL Twitter dataset."""

    def __init__(self, lines, labels, word_vocab=None, train=None, padding_size=None):
        """Load dataset from the given files.

        Arguments:
        train: If given, the vocabularies from the training data will be reused.
        """
        self.padding_size = padding_size
        self.is_train = train is None  # if train is none, this dataset is the training one

        # Create vocabulary_maps
        if train:
            self._vocabulary_maps = train._vocabulary_maps
        else:
            self._vocabulary_maps = {'chars': {PAD_TOKEN: 0, UNK_TOKEN: 1}, 'labels': {0: 0, 1: 1}}
            if word_vocab:
                self._vocabulary_maps['words'] = word_vocab
            else:
                self._vocabulary_maps['words'] = {0: 0, 1: 1},  # pad = 0, unk = 1

        self._word_ids = []
        self._charseq_ids = []
        self._charseqs_map = {PAD_TOKEN: 0}
        self._charseqs = []
        if labels:
            self._labels = []

        # Load the sentences
        for idx, line in enumerate(lines):
            if labels:  # if not test
                label = labels[idx]
                assert label in self._vocabulary_maps['labels']
                self._labels.append(self._vocabulary_maps['labels'][label])

            self._word_ids.append([])
            self._charseq_ids.append([])
            for word in line:
                # Characters
                if word not in self._charseqs_map:
                    self._charseqs_map[word] = len(self._charseqs)
                    self._charseqs.append([])
                    for c in word:
                        if c not in self._vocabulary_maps['chars']:
                            if not train:
                                self._vocabulary_maps['chars'][c] = len(
                                    self._vocabulary_maps['chars'])
                            else:
                                c = UNK_TOKEN
                        self._charseqs[-1].append(self._vocabulary_maps['chars'][c])
                self._charseq_ids[-1].append(self._charseqs_map[word])

                # Words -- MissingDict handles UNKs automatically
                self._word_ids[-1].append(self._vocabulary_maps['words'][word])

        # Compute sentence lengths
        sentences = len(self._word_ids)
        self._sentence_lens = np.zeros([sentences], np.int32)
        for i in range(sentences):
            self._sentence_lens[i] = len(self._word_ids[i])

        # Create vocabularies
        if train:
            self._vocabularies = train._vocabularies
        else:
            self._vocabularies = {}
            for feature, words in self._vocabulary_maps.items():
                self._vocabularies[feature] = [""] * len(words)
                for word, idx in words.items():
                    self._vocabularies[feature][idx] = word

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

    @staticmethod
    def generate_permutation(ln, is_train=False):
        if is_train:
            return np.random.permutation(ln)
        else:
            return np.arange(ln)

    def vocabulary(self, feature):
        """Return vocabulary for required feature.

        The features are the following:
        words
        chars
        labels
        """
        return self._vocabularies[feature]

    def next_batch(self, batch_perm):  # TODO(oskopek): Make this faster for fixed padding.
        """Return the next batch.

        Args:
            batch_perm
        Returns: (sentence_lens, word_ids, charseq_ids, charseqs, charseq_lens, labels)
        sequence_lens: batch of sentence_lens
        word_ids: batch of word_ids
        charseq_ids: batch of charseq_ids (the same shape as word_ids, but with the ids pointing
                     into charseqs).
        charseqs: unique charseqs in the batch, indexable by charseq_ids;
          contain indices of characters from vocabulary('chars')
        charseq_lens: length of charseqs
        labels: batch of labels

        batch: [string]

        sequence_lens: tweet -> len([word_id]) == len([charseq_id]) # number of words per tweet
        word_ids: tweet -> [word_id] #
        word_vocab: word -> word_id
        charseq_ids: tweet -> [charseq_id]
        charseqs: charseq_id -> [char_id]
        charseq_lens: word_id -> len([char_id])
        char_vocab: char -> char_id
        """
        batch_size = len(batch_perm)

        # General data
        batch_sentence_lens = self._sentence_lens[batch_perm]
        if self.padding_size is None:
            max_sentence_len = np.max(batch_sentence_lens)
        else:
            max_sentence_len = self.padding_size

        # Word-level data
        batch_word_ids = np.zeros([batch_size, max_sentence_len], np.int32)
        for i in range(batch_size):
            length = min(batch_sentence_lens[i], max_sentence_len)
            batch_sentence_lens[i] = length
            batch_word_ids[i, :length] = self._word_ids[batch_perm[i]][:length]

        if hasattr(self, '_labels'):  # not test
            batch_labels = np.zeros([batch_size], np.int32)
            for i in range(batch_size):
                batch_labels[i] = self._labels[batch_perm[i]]
        else:
            batch_labels = None

        # Character-level data
        batch_charseq_ids = np.zeros([batch_size, max_sentence_len], np.int32)
        charseqs_map, charseqs = {}, []
        for i in range(batch_size):
            for j, charseq_id in enumerate(self._charseq_ids[batch_perm[i]]):
                if j >= max_sentence_len:
                    break
                if charseq_id not in charseqs_map:
                    charseqs_map[charseq_id] = len(charseqs)
                    charseqs.append(self._charseqs[charseq_id])
                batch_charseq_ids[i, j] = charseqs_map[charseq_id]

        batch_charseq_lens = np.array([len(charseq) for charseq in charseqs], np.int32)
        batch_charseqs = np.zeros([len(charseqs), np.max(batch_charseq_lens)], np.int32)
        for i in range(len(charseqs)):
            batch_charseqs[i, 0:len(charseqs[i])] = charseqs[i]

        return batch_sentence_lens, batch_word_ids, batch_charseq_ids, batch_charseqs, \
            batch_charseq_lens, batch_labels, self.is_train

    def batch_per_epoch_generator(self, batch_size, shuffle=True):
        assert self.is_train == shuffle
        permutation = self.generate_permutation(len(self), is_train=shuffle)
        for n_batch in range(self.n_batches(batch_size=batch_size)):
            batch_size = min(batch_size, len(permutation))
            batch_perm = permutation[:batch_size]
            permutation = permutation[batch_size:]
            yield self.next_batch(batch_perm)

    def batches_per_epoch(self, batch_size: int = 1, shuffle: bool = True):
        n_batches = self.n_batches(batch_size=batch_size)
        batch_generator = self.batch_per_epoch_generator(batch_size=batch_size, shuffle=shuffle)
        return n_batches, batch_generator

    def n_batches(self, batch_size: int = 1):
        remainder = 0 if len(self) % batch_size == 0 else 1
        return len(self) // batch_size + remainder

ext: py

max_stars_repo_name: oskopek/cil

max_issues_repo_name: oskopek/cil

max_forks_repo_name: oskopek/cil

reason: import numpy


text:
import pygame, math, sys
pygame.init()
from model import evaluate, refresh
import numpy as np

X = 900  # screen width
Y = 600  # screen height

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 50, 50)
YELLOW = (255, 255, 0)
GREEN = (0, 255, 50)
BLUE = (50, 50, 255)
GREY = (200, 200, 200)
ORANGE = (200, 100, 50)
CYAN = (0, 255, 255)
MAGENTA = (255, 0, 255)
TRANS = (1, 1, 1)

flow = False  # controls type of color flow

class Gradient():
    def __init__(self, palette, maximum):
        self.COLORS = palette
        self.N = len(self.COLORS)
        self.SECTION = maximum // (self.N - 1)

    def gradient(self, x):
        """
        Returns a smooth color profile with only a single input value.
        The color scheme is determinated by the list 'self.COLORS'
        """
        i = x // self.SECTION
        fraction = (x % self.SECTION) / self.SECTION
        c1 = self.COLORS[i % self.N]
        c2 = self.COLORS[(i+1) % self.N]
        col = [0, 0, 0]
        for k in range(3):
            col[k] = (c2[k] - c1[k]) * fraction + c1[k]
        return col

def wave(num):
    """
    The basic calculating and drawing function.
    The internal function is 'cosine' >> (x, y) values.

    The function uses slider values to variate the output.
    Slider values are defined by <slider name>.val
    """
    for i, letter in enumerate('abcdefghijklmnopqrstuvwxyz'):
        evaluate(i, np.array([s.val for s in slides]))

        sprite = pygame.image.load('out.png')
        sprite = pygame.transform.scale2x(sprite)
        rect = sprite.get_rect()
        rect.center = (50 + i % 13 * 62, 50 + i//13 * 90)
        screen.blit(sprite, rect)

class Slider():
    def __init__(self, name, val, maxi, mini, pos):
        self.val = val  # start value
        self.maxi = maxi  # maximum at slider position right
        self.mini = mini  # minimum at slider position left
        self.xpos = pos  # x-location on screen
        self.ypos = 550
        self.surf = pygame.surface.Surface((100, 50))
        self.hit = False  # the hit attribute indicates slider movement due to mouse interaction

        self.txt_surf = font.render(name, 1, BLACK)
        self.txt_rect = self.txt_surf.get_rect(center=(50, 15))

        # Static graphics - slider background #
        self.surf.fill((100, 100, 100))
        pygame.draw.rect(self.surf, GREY, [0, 0, 100, 50], 3)
        pygame.draw.rect(self.surf, ORANGE, [10, 10, 80, 10], 0)
        pygame.draw.rect(self.surf, WHITE, [10, 30, 80, 5], 0)

        self.surf.blit(self.txt_surf, self.txt_rect)  # this surface never changes

        # dynamic graphics - button surface #
        self.button_surf = pygame.surface.Surface((20, 20))
        self.button_surf.fill(TRANS)
        self.button_surf.set_colorkey(TRANS)
        pygame.draw.circle(self.button_surf, BLACK, (10, 10), 6, 0)
        pygame.draw.circle(self.button_surf, ORANGE, (10, 10), 4, 0)

    def draw(self):
        """ Combination of static and dynamic graphics in a copy of
    the basic slide surface
    """
        # static
        surf = self.surf.copy()

        # dynamic
        pos = (10+int((self.val-self.mini)/(self.maxi-self.mini)*80), 33)
        self.button_rect = self.button_surf.get_rect(center=pos)
        surf.blit(self.button_surf, self.button_rect)
        self.button_rect.move_ip(self.xpos, self.ypos)  # move of button box to correct screen position

        # screen
        screen.blit(surf, (self.xpos, self.ypos))

    def move(self):
        """
    The dynamic part; reacts to movement of the slider button.
    """
        self.val = (pygame.mouse.get_pos()[0] - self.xpos - 10) / 80 * (self.maxi - self.mini) + self.mini
        if self.val < self.mini:
            self.val = self.mini
        if self.val > self.maxi:
            self.val = self.maxi

font = pygame.font.SysFont("Verdana", 12)
screen = pygame.display.set_mode((X, Y))
clock = pygame.time.Clock()

COLORS = [MAGENTA, RED, YELLOW, GREEN, CYAN, BLUE]
xcolor = Gradient(COLORS, X).gradient

pen = Slider("1", 0, 1, -1, 25)
freq = Slider("2", 0, 1, -1, 150)
jmp = Slider("3", 0, 1, -1, 275)
size = Slider("4", 0, 1, -1, 400)
focus = Slider("5", 0, 1, -1, 525)
phase = Slider("6", 0, 1, -1, 650)
speed = Slider("7", 0, 1, -1, 775)
slides = [pen, freq, jmp, size, focus, phase, speed]

num = 0

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == pygame.MOUSEBUTTONDOWN:
            pos = pygame.mouse.get_pos()
            for s in slides:
                if s.button_rect.collidepoint(pos):
                    s.hit = True
        elif event.type == pygame.MOUSEBUTTONUP:
            for s in slides:
                s.hit = False

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_r:
                refresh()

    # Move slides
    for s in slides:
        if s.hit:
            s.move()

    # Update screen
    screen.fill(WHITE)
    num += 2
    wave(num)

    for s in slides:
        s.draw()

    pygame.display.flip()
    clock.tick(30)

max_stars_repo_name: MarkintoshZ/FontTransformer

max_issues_repo_name: MarkintoshZ/FontTransformer

max_forks_repo_name: MarkintoshZ/FontTransformer


text:
import networkx
import numpy
import sympy
import scipy.optimize
import sys
import matplotlib.cbook
import warnings
from sys import platform as sys_pf
if sys_pf == 'darwin':
    import matplotlib
    matplotlib.use("TkAgg")
    import matplotlib.pyplot as plt
else:
    import matplotlib.pyplot as plt

warnings.filterwarnings("ignore", category=matplotlib.cbook.mplDeprecation)

class Cgraph:
    """
    Class for constructing core CRNT values and C-graph of the network.
    """
    def __init__(self, model):
        """
        Initialization of Cgraph class.

        See also
        ---------
        crnt4sbml.CRNT.get_c_graph()
        """
        self.__g = networkx.DiGraph()

        # list of nodes and edges in the order they were added
        self.__g_nodes = []
        self.__g_edges = []

        self.__dic_species_id_bcs = {}
        for i in model.getListOfSpecies():
            self.__dic_species_id_bcs.update({i.getId(): i.getBoundaryCondition()})

        self.__species = []

        self.__parse_reactions(model)

        self.__assign_reaction_type()

        # self.__species = [i.getId() for i in model.getListOfSpecies() if not i.getBoundaryCondition()]

        # temporary makes testing of higher deficiency theory easier
        ######################################################################################
        #self.__species_name = [i.getName() for i in model.getListOfSpecies()]
        #self.__dic_species_id_name = {}
        #for i in range(len(self.__species)):
        #    self.__dic_species_id_name.update({self.__species[i]: self.__species_name[i]})
        ######################################################################################

        self.__linkage_classes = [self.__g.subgraph(c) for c in networkx.weakly_connected_components(self.__g)]

        self.__complexes = [self.__g.nodes[n]['label'] for n in self.__g_nodes]
        self.__reactions = [self.__g.edges[e]['label'] for e in self.__g_edges]

        # self.__check_weak_reversibility_of_linkage_classes() # todo: candidate for deletion

        # core calculations
        self.__create_y_matrix()
        self.__create_s_matrix()
        self.__create_a_matrix()
        self.__create_mass_action_monomials()

        if all([i <= 1 for i in self.get_number_of_terminal_strong_lc_per_lc()]) and \
            self.get_dim_equilibrium_manifold() > 0:
            self.__create_BT_matrix()
            self.__create_lambda_matrix()

        # self.__calculate_deficiency() # todo: candidate for deletion
        # self.__calculate_number_of_conservation_relations() # todo: candidate for deletion
        # self.__classify_dimensionality() # todo: candidate for deletion

    def __parse_reactants_and_products(self, reaction):

        # extracting reactants
        reactants = [i.getSpecies() for i in reaction.getListOfReactants()]

        bound_cond = any([self.__dic_species_id_bcs.get(n, n) for n in reactants])
        if bound_cond:
            color = 'red'
        else:
            color = 'green'

        stoichiometries = [int(i.getStoichiometry()) for i in reaction.getListOfReactants()]
        temp = zip([repr(i) if i != 1 else '' for i in stoichiometries], reactants)
        reactant_complex_name = '+'.join(['*'.join(filter(lambda x: x != '', i)) for i in temp])
        if self.__g.number_of_nodes() == 0 or reactant_complex_name not in [self.__g.nodes[v]['label'] for
                                                                            v in self.__g.nodes]:
            self.__g.add_node(reactant_complex_name,
                              label=reactant_complex_name,
                              species=reactants,
                              stoichiometries=stoichiometries,
                              species_bc=bound_cond,
                              color=color)
            self.__g_nodes.append(reactant_complex_name)

        # extracting products
        products = [i.getSpecies() for i in reaction.getListOfProducts()]

        bound_cond = any([self.__dic_species_id_bcs.get(n, n) for n in products])
        if bound_cond:
            color = 'red'
        else:
            color = 'green'

        stoichiometries = [int(i.getStoichiometry()) for i in reaction.getListOfProducts()]
        temp = zip([repr(i) if i != 1 else '' for i in stoichiometries], products)
        product_complex_name = '+'.join(['*'.join(filter(lambda x: x != '', i)) for i in temp])
        if product_complex_name not in [self.__g.nodes[v]['label'] for v in self.__g.nodes]:
            self.__g.add_node(product_complex_name,
                              label=product_complex_name,
                              species=products,
                              stoichiometries=stoichiometries,
                              species_bc=bound_cond,
                              color=color)
            self.__g_nodes.append(product_complex_name)

        [self.__species.append(i) for i in reactants if (i not in self.__species) and (not self.__dic_species_id_bcs[i])]
        [self.__species.append(i) for i in products if (i not in self.__species) and (not self.__dic_species_id_bcs[i])]

        return [reactant_complex_name, product_complex_name]

    def __parse_reactants_products_and_modifiers(self, reaction):

        modifiers = [i.getSpecies() for i in reaction.getListOfModifiers()]

        # extracting reactants
        reactants = [i.getSpecies() for i in reaction.getListOfReactants()]

        reactant_complex_name = self.__create_reactant_or_product_complex(reaction, reactants, modifiers, "reactant")

        # extracting products
        products = [i.getSpecies() for i in reaction.getListOfProducts()]

        product_complex_name = self.__create_reactant_or_product_complex(reaction, products, modifiers, "product")

        # extracting modifiers
        bound_cond = any([self.__dic_species_id_bcs.get(n, n) for n in modifiers])
        if bound_cond:
            color = 'red'
        else:
            color = 'green'

        stoichiometries = [int(1.0)]
        modifiers_complex_name = "".join(modifiers) + "".join(reactants)

        if modifiers_complex_name not in [self.__g.nodes[v]['label'] for v in self.__g.nodes]:
            self.__g.add_node(modifiers_complex_name,
                              label=modifiers_complex_name,
                              species=[modifiers_complex_name],
                              stoichiometries=stoichiometries,
                              species_bc=bound_cond,
                              color=color)
            self.__g_nodes.append(modifiers_complex_name)

        [self.__species.append(i) for i in reactants if (i not in self.__species) and (not self.__dic_species_id_bcs[i])]
        [self.__species.append(i) for i in products if (i not in self.__species) and (not self.__dic_species_id_bcs[i])]
        [self.__species.append(i) for i in modifiers if (i not in self.__species) and (not self.__dic_species_id_bcs[i])]
        [self.__species.append(i) for i in [modifiers_complex_name] if (i not in self.__species)]

        return [reactant_complex_name, product_complex_name, modifiers_complex_name]

    def __create_reactant_or_product_complex(self, reaction, non_modifier, modifiers, comp):

        bound_cond = any([self.__dic_species_id_bcs.get(n, n) for n in non_modifier + modifiers])
        if bound_cond:
            color = 'red'
        else:
            color = 'green'

        # this statement assumes one species in modifier
        indices = [i for i in range(len(non_modifier)) if modifiers[0] == non_modifier[i]]
        if comp == 'reactant':

            reactants_stoich = [int(i.getStoichiometry()) for i in reaction.getListOfReactants()]

            # assumes only one modifier
            modifiers_sotich = int(1.0)

            if indices:
                stoich_sum = sum([reactants_stoich[i] for i in indices]) + modifiers_sotich
                stoichiometries = [reactants_stoich[i] for i in range(len(reactants_stoich)) if i not in indices] + \
                                  [stoich_sum]
                species_list = [non_modifier[i] for i in range(len(non_modifier)) if i not in indices] + modifiers

            else:
                stoichiometries = reactants_stoich + [modifiers_sotich]
                species_list = non_modifier + modifiers
        else:
            products_stoich = [int(i.getStoichiometry()) for i in reaction.getListOfProducts()]
            # assumes only one modifier
            modifiers_sotich = int(1.0)

            if indices:
                stoich_sum = sum([products_stoich[i] for i in indices]) + modifiers_sotich
                stoichiometries = [products_stoich[i] for i in range(len(products_stoich)) if i not in indices] + \
                                  [stoich_sum]
                species_list = [non_modifier[i] for i in range(len(non_modifier)) if i not in indices] + modifiers
            else:
                stoichiometries = products_stoich + [modifiers_sotich]
                species_list = non_modifier + modifiers

        temp = zip([repr(i) if i != 1 else '' for i in stoichiometries], species_list)
        complex_name = '+'.join(['*'.join(filter(lambda x: x != '', i)) for i in temp])

        if self.__g.number_of_nodes() == 0 or complex_name not in [self.__g.nodes[v]['label'] for
                                                                   v in self.__g.nodes]:
            self.__g.add_node(complex_name, label=complex_name, species=species_list, stoichiometries=stoichiometries,
                              species_bc=bound_cond, color=color)
            self.__g_nodes.append(complex_name)

        return complex_name

    def __extract_direct_reaction(self, reaction):
        r, p = self.__parse_reactants_and_products(reaction)
        if (r, p) not in [i for i in self.__g.edges]:
            self.__g.add_edge(r, p,
                              label=reaction.getId(),
                              k=None,
                              sbml_label=reaction.getId(),
                              type=None)
            self.__g_edges.append((r, p))

    def __extract_reverse_reaction(self, reaction):
        r, p = self.__parse_reactants_and_products(reaction)
        if (p, r) not in [i for i in self.__g.edges]:
            self.__g.add_edge(p, r,
                              label=reaction.getId() + 'r',
                              k=None,
                              sbml_label=reaction.getId(),
                              type=None)
            self.__g_edges.append((p, r))

    def __extract_catalysis_reaction(self, reaction):

        modifier = self.__get_celldesigner_reaction_type(reaction)

        if modifier != 'CATALYSIS':

            exception_statement = "For reaction " + reaction.getId() + " there is a modifier that cannot be " \
                                                                       "identified, there are multiple modifiers," \
                                                                       " or is not catalysis. \nThis may be" \
                                                                       " a result of not constructing the SBML file " \
                                                                       "using CellDesigner. \nPlease make the appropriate" \
                                                                       " changes to this reaction to continue."
            raise Exception(exception_statement)

        r, p, m = self.__parse_reactants_products_and_modifiers(reaction)

        # add complex formation
        if (r, m) not in [i for i in self.__g.edges]:
            self.__g.add_edge(r, m,
                              label=reaction.getId() + 'f',
                              k=None,
                              sbml_label=reaction.getId(),
                              type="complex formation")
            self.__g_edges.append((r, m))

        # add complex dissociation
        if (m, r) not in [i for i in self.__g.edges]:
            self.__g.add_edge(m, r,
                              label=reaction.getId() + 'd',
                              k=None,
                              sbml_label=reaction.getId(),
                              type="complex dissociation")
            self.__g_edges.append((m, r))

        # add catalysis
        if (m, p) not in [i for i in self.__g.edges]:
            self.__g.add_edge(m, p,
                              label=reaction.getId() + 'c',
                              k=None,
                              sbml_label=reaction.getId(),
                              type="catalysis")
            self.__g_edges.append((m, p))

    def __parse_reactions(self, model):
        for i in model.getListOfReactions():
            if i.getNumModifiers() != 0:
                self.__extract_catalysis_reaction(i)
            else:
                self.__extract_direct_reaction(i)
                if i.getReversible():
                    self.__extract_reverse_reaction(i)

    def __get_celldesigner_reaction_type(self, i):

        i_initial = i.getAnnotation().getChild(0)

        child_number = self.__get_child_number(i_initial, 'reactionType')

        if child_number is not None:

            if i.getNumModifiers() == 1:

                child_number1 = self.__get_child_number(i_initial, 'listOfModification')

                if child_number1 is not None:

                    child_number2 = self.__get_child_number(i_initial.getChild(child_number1), 'modification')

                    ii = i_initial.getChild(child_number1).getChild(child_number2)
                    modification = self.__get_modification_type(ii)

                    return modification
                else:
                    return None
            else:
                return None

        else:
            return None

    def __get_child_number(self, i, string_value):

        num_children = i.getNumChildren()
        children_strings = [i.getChild(ii).getName() for ii in range(num_children)]
        if string_value in children_strings:
            child_number = children_strings.index(string_value)
        else:
            child_number = None

        return child_number

    def __get_modification_type(self, ii):

        attribute_names = [ii.getAttrName(iii) for iii in range(ii.getAttributesLength())]

        if 'type' in attribute_names:

            indx_type = attribute_names.index('type')
            attribute_values = [ii.getAttrValue(iii) for iii in attribute_names]

            return attribute_values[indx_type]
        else:
            return None

    def __assign_reaction_type(self):

        for i in self.get_g_edges():

            current_edge = self.__g.edges[i]

            if current_edge['type'] is None:

                reactant_node = self.__g.nodes[i[0]]
                product_node = self.__g.nodes[i[1]]

                if sum(reactant_node['stoichiometries']) == 2 and sum(product_node['stoichiometries']) == 1:
                    current_edge['type'] = "complex formation"

                elif sum(reactant_node['stoichiometries']) == 1 and sum(product_node['stoichiometries']) == 2:
                    if (i[1], i[0]) in self.get_g_edges():
                        current_edge['type'] = "complex dissociation"
                    else:
                        current_edge['type'] = "catalysis"

                elif sum(reactant_node['stoichiometries']) == 1 and sum(product_node['stoichiometries']) == 1:
                    current_edge['type'] = "catalysis"

                elif sum(reactant_node['stoichiometries']) == 1 and sum(product_node['stoichiometries']) == 3:
                    current_edge['type'] = "catalysis"

                else:
                    output_statement = "The reaction type of reaction " + current_edge['label'] + " could not be " +\
                                       "identified as it does not fit any biological criteria established. \n" +\
                                       "Automatic creation of bounds for optimization routines cannot be completed. \n"

                    print(output_statement)

    # core CRNT calcs
    def __create_y_matrix(self):

        self.__Y = sympy.zeros(len(self.__species), len(self.__complexes))
        count = 0
        for i in self.__g_nodes:
            v = self.__g.nodes[i]
            stoich = dict(zip(v['species'], v['stoichiometries']))
            self.__Y[:, count] = [stoich[i] if i in stoich.keys() else 0 for i in self.__species]
            count += 1

    def __create_s_matrix(self):

        self.__S = sympy.zeros(len(self.__species), len(self.__reactions))
        count = 0
        for i in self.__g_edges:
            target = self.__complexes.index(i[1])
            source = self.__complexes.index(i[0])
            self.__S[:, count] = self.__Y[:, target] - self.__Y[:, source]
            count += 1

    def __create_lambda_matrix(self):
        self.__Lambda = sympy.zeros(len(self.__complexes), len(self.__linkage_classes))
        for li in range(len(self.__linkage_classes)):
            l_complexes = [i for i in self.__linkage_classes[li].nodes]
            self.__Lambda[:, li] = [1 if i in l_complexes else 0 for i in self.__complexes]

    def __create_a_matrix(self):
        self.__A = sympy.zeros(len(self.__complexes), len(self.__complexes))
        inc_list = [list(self.__g.out_edges(n, data='label')) for n in self.__g_nodes]

        for i in range(len(self.__complexes)):
            for ii in inc_list[i]:
                self.__A[i, i] = self.__A[i, i] - sympy.Symbol(ii[2], positive=True)

        for i in range(len(self.__complexes)):
            for j in range(len(self.__complexes)):
                if self.__g.has_edge(self.__complexes[j], self.__complexes[i]):
                    self.__A[i, j] = self.__A[i, j] + sympy.Symbol(self.__g.get_edge_data(self.__complexes[j],
                                                                                self.__complexes[i])['label'],
                                                                   positive=True)

    def __create_BT_matrix(self):
        # (bt = NullSpace[Transpose[Y.A]]) // MatrixForm
        the_null_space = (self.__Y * self.__A).T.nullspace()

        # getting the number of columns given in nullspace computation
        sizes = len(the_null_space)

        # simplifying the entries given in the columns
        # produced by the nullspace
        for i in range(0, sizes):
            the_null_space[i] = sympy.simplify(the_null_space[i])

        bt_temp = self.__create_non_negative_b_matrix(the_null_space, sizes)

        # taking out zero rows if they are in unique vectors
        bt = sympy.Matrix(bt_temp[~numpy.all(bt_temp == 0, axis=1)]).evalf(10)

        # making the dimension of bt be lambda by N, just incase
        # we have more vectors than we should
        bt = bt[0:self.get_dim_equilibrium_manifold(), :]

        # putting in a check to make sure that the rows
        # of bt are linearly independent
        _, vals = bt.T.rref()
        if len(vals) != self.get_dim_equilibrium_manifold():
            print(" ")
            print("Error: Not all rows of B^T are linearly independent!")
            print(" ")
            sys.exit()

        self.__B = bt

    def __simplify_nullspace(self, the_null_space):

        # Flag that says a species or reaction was found in one of the column vectors of the nullspace
        denom_flag = False

        print("beginning null space")
        #print(the_null_space)
        print("")
        for i in range(0, len(the_null_space)):
            #print(the_null_space[i])
            the_null_space[i] = sympy.simplify(the_null_space[i])

        print(the_null_space)

        # find those columns that have a common denominator
        denom_list = []
        for ii in the_null_space:

            # getting common denominator
            denom_in_column = [sympy.denom(i) for i in ii]
            denom_list.append(denom_in_column)

        print(f"denom_list {denom_list}")

        like_columns = []
        for i in denom_list:
            same_denoms = [ii for ii in range(len(denom_list)) if denom_list[ii] == i]
            if same_denoms not in like_columns:
                like_columns.append(same_denoms)

        print(like_columns)
        temp_null = [sympy.zeros(len(self.__species), 1)] * (len(self.__species) - self.__S.rank())
        count = 0
        for ii in like_columns:

            for i in ii:
                temp_null[count] += the_null_space[i]
                temp_null[count] = sympy.simplify(temp_null[count])
            count += 1

        print(temp_null)
        sys.exit()

        # collecting nullspace vectors with common denominators
        all_denom = list(set(denom_list))
        temp_null = [sympy.zeros(len(self.__species), 1)] * (len(self.__species) - self.__S.rank())

        try:
            for ii in range(len(all_denom)):
                indices = [i for i, x in enumerate(denom_list) if x == all_denom[ii]]
                print(f"indices {indices}")
                for i in indices:
                    temp_null[ii] += the_null_space[i]
                    temp_null[ii] = sympy.simplify(temp_null[ii])
        except Exception as e:
            print("hi")

        print(f"final temp null {temp_null}")
        sys.exit()

        # checking to see if a reaction or species is in the reduced nullspace
        for i in temp_null:
            atoms_of_col_vec = [ii.atoms() for ii in i[:, 0]]
            for ii in atoms_of_col_vec:
                if any([iii in self.__reactions + self.__species for iii in ii]):
                    denom_flag = True

        if denom_flag:
            raise Exception("Nullspace calculation from S contains SymPy variables and this could not be resolved.")

        return temp_null

    def __create_non_negative_b_matrix(self, the_null_space, sizes):
        '''
        Idea inspired by https://r.789695.n4.nabble.com/convex-nonnegative-basis-vectors-in-nullspace-of-matrix-td4548822.html.
        '''

        a_null = numpy.zeros((len(self.__species), sizes))
        for i in range(len(self.__species)):
            temp_vec = []
            for j in range(sizes):
                temp_vec.append(the_null_space[j][i])
            a_null[i, :] = temp_vec

        a_eq = numpy.array([numpy.sum(a_null, axis=0)])

        # must multiply by negative one because in optimization we have the inequality <= 0.0
        a_ub = -1.0*a_null
        b_ub = numpy.zeros(len(self.__species))
        b_eq = numpy.array([1.0])

        # defining the number of solutions to simulate
        num_sols = ((a_ub.shape[0]+1)*(a_ub.shape[1]+1))*10

        # a matrix to hold the different solutions of the method
        sol = numpy.zeros((num_sols, len(self.__species)))

        # searching the nullspace for nonnegative vectors
        for i in range(num_sols):
            # generating a multivariate normal random variates
            crit = numpy.random.normal(0, 1.0, a_ub.shape[1])

            # Solving the linear programming problem
            out = scipy.optimize.linprog(crit, A_eq=a_eq, b_eq=b_eq, A_ub=a_ub, b_ub=b_ub, bounds=(None, None),
                                         method='simplex')
            # multiplying our nullspace vectors with the minimized value
            # to create a nonnegative vector
            sol[i, :] = numpy.dot(a_null, out.x)
            sol[i, [numpy.abs(sol[i, :]) < numpy.finfo(float).eps][0]] = numpy.float64(0.0)

        # getting the unique vectors
        unique_vecs = numpy.unique(sol, axis=0)
        num_rows = numpy.size(unique_vecs, 0)

        # taking the smallest nonzero entry of the unique vectors
        # and dividing by it this will hopefully create nice
        # looking vectors that are whole numbers
        for i in range(num_rows):
            minval = numpy.min(unique_vecs[i, numpy.nonzero(unique_vecs[i, :])])
            unique_vecs[i, :] = unique_vecs[i, :]/numpy.float64(minval)

        unique_vecs = numpy.unique(unique_vecs.round(decimals=10), axis=0)

        return unique_vecs

    def __create_mass_action_monomials(self):
        self.__psi = sympy.ones(len(self.__complexes), 1)
        for j in range(len(self.__complexes)):
            for i in range(len(self.__species)):
                self.__psi[j] *= sympy.Symbol(self.__species[i], positive=True)**self.__Y[i, j]

                # TODO: possibly make concetrations positive

    # public getters
    def get_dict_id_name(self):
        return self.__dic_species_id_name

    def get_ode_system(self):
        """
        Returns SymPy matrix representing the ODE system.
        :download:`Fig1Ci.xml <../../sbml_files/Fig1Ci.xml>` for the
        provided example.

        Example
        --------
        >>> import crnt4sbml
        >>> import sympy
        >>> network = crnt4sbml.CRNT("path/to/Fig1Ci.xml")
        >>> sympy.pprint(network.get_c_graph().get_ode_system())
            ⎡    -re₁⋅s₁⋅s₂ + re1r⋅s₃ + re₄⋅s₁₆ - re₅⋅s₁⋅s₆ + re5r⋅s₁₅     ⎤
            ⎢                                                              ⎥
            ⎢                 -re₁⋅s₁⋅s₂ + s₃⋅(re1r + re₂)                 ⎥
            ⎢                                                              ⎥
            ⎢                 re₁⋅s₁⋅s₂ + s₃⋅(-re1r - re₂)                 ⎥
            ⎢                                                              ⎥
            ⎢re₂⋅s₃ - re₃⋅s₆⋅s₇ + re3r⋅s₁₆ - re₅⋅s₁⋅s₆ + s₁₅⋅(re5r + 2⋅re₆)⎥
            ⎢                                                              ⎥
            ⎢                -re₃⋅s₆⋅s₇ + s₁₆⋅(re3r + re₄)                 ⎥
            ⎢                                                              ⎥
            ⎢                re₃⋅s₆⋅s₇ + s₁₆⋅(-re3r - re₄)                 ⎥
            ⎢                                                              ⎥
            ⎣                re₅⋅s₁⋅s₆ + s₁₅⋅(-re5r - re₆)                 ⎦
        """
        return self.__Y*self.__A*self.__psi

    def get_graph(self):
        """
        Returns the NetworkX DiGraph representation of the network.

        Example
        --------
        >>> import crnt4sbml
        >>> network = crnt4sbml.CRNT("path/to/sbml_file.xml")
        >>> network.get_c_graph().get_graph()
        """
        return self.__g

    def get_species(self):
        """
        Returns Python list of strings representing the species of the network.
        :download:`Fig1Ci.xml <../../sbml_files/Fig1Ci.xml>` for the provided
        example.

        Example
        --------
        >>> import crnt4sbml
        >>> network = crnt4sbml.CRNT("path/to/Fig1Ci.xml")
        >>> print(network.get_c_graph().get_species())
            ['s1', 's2', 's3', 's6', 's7', 's16', 's15']
        """
        return self.__species

    def get_complexes(self):
        """
        Returns Python list of strings representing the complexes of the network.
        :download:`Fig1Ci.xml <../../sbml_files/Fig1Ci.xml>` for the provided
        example.

        Example
        --------
        >>> import crnt4sbml
        >>> network = crnt4sbml.CRNT("path/to/Fig1Ci.xml")
        >>> print(network.get_c_graph().get_complexes())
            ['s1+s2', 's3', 's6+s2', 's6+s7', 's16', 's7+s1', 's1+s6', 's15', '2*s6']
        """
        return self.__complexes

    def get_reactions(self):
        """
        Returns Python list of strings representing the reactions of the network.
        :download:`Fig1Ci.xml <../../sbml_files/Fig1Ci.xml>` for the provided
        example.

        Example
        --------
        >>> import crnt4sbml
        >>> network = crnt4sbml.CRNT("path/to/Fig1Ci.xml")
        >>> print(network.get_c_graph().get_reactions())
            ['re1', 're1r', 're2', 're3', 're3r', 're4', 're5', 're5r', 're6']
        """
        return self.__reactions

    def get_a(self):
        """
        Returns SymPy matrix representing the kinetic constant matrix, :math:`A`.
        :download:`Fig1Ci.xml <../../sbml_files/Fig1Ci.xml>` for the provided
        example.

        Example
        --------
        >>> import crnt4sbml
        >>> import sympy
        >>> network = crnt4sbml.CRNT("path/to/Fig1Ci.xml")
        >>> sympy.pprint(network.get_c_graph().get_a())
            ⎡-re₁     re1r      0   0         0       0   0         0       0⎤
            ⎢                                                                ⎥
            ⎢re₁   -re1r - re₂  0   0         0       0   0         0       0⎥
            ⎢                                                                ⎥
            ⎢ 0        re₂      0   0         0       0   0         0       0⎥
            ⎢                                                                ⎥
            ⎢ 0         0       0  -re₃     re3r      0   0         0       0⎥
            ⎢                                                                ⎥
            ⎢ 0         0       0  re₃   -re3r - re₄  0   0         0       0⎥
            ⎢                                                                ⎥
            ⎢ 0         0       0   0        re₄      0   0         0       0⎥
            ⎢                                                                ⎥
            ⎢ 0         0       0   0         0       0  -re₅     re5r      0⎥
            ⎢                                                                ⎥
            ⎢ 0         0       0   0         0       0  re₅   -re5r - re₆  0⎥
            ⎢                                                                ⎥
            ⎣ 0         0       0   0         0       0   0        re₆      0⎦
        """
        return self.__A

    def get_y(self):
        """
        Returns SymPy matrix representing the molecularity matrix, :math:`Y`.
        :download:`Fig1Ci.xml <../../sbml_files/Fig1Ci.xml>` for the provided
        example.

        Example
        --------
        >>> import crnt4sbml
        >>> import sympy
        >>> network = crnt4sbml.CRNT("path/to/Fig1Ci.xml")
        >>> sympy.pprint(network.get_c_graph().get_y())
            ⎡1  0  0  0  0  1  1  0  0⎤
            ⎢                         ⎥
            ⎢1  0  1  0  0  0  0  0  0⎥
            ⎢                         ⎥
            ⎢0  1  0  0  0  0  0  0  0⎥
            ⎢                         ⎥
            ⎢0  0  1  1  0  0  1  0  2⎥
            ⎢                         ⎥
            ⎢0  0  0  1  0  1  0  0  0⎥
            ⎢                         ⎥
            ⎢0  0  0  0  1  0  0  0  0⎥
            ⎢                         ⎥
            ⎣0  0  0  0  0  0  0  1  0⎦
        """
        return self.__Y

    def get_s(self):
        """
        Returns SymPy matrix representing the stoichiometric matrix, :math:`S`.
        :download:`Fig1Ci.xml <../../sbml_files/Fig1Ci.xml>` for the provided
        example.

        Example
        --------
        >>> import crnt4sbml
        >>> import sympy
        >>> network = crnt4sbml.CRNT("path/to/Fig1Ci.xml")
        >>> sympy.pprint(network.get_c_graph().get_s())
            ⎡-1  1   0   0   0   1   -1  1   0 ⎤
            ⎢                                  ⎥
            ⎢-1  1   1   0   0   0   0   0   0 ⎥
            ⎢                                  ⎥
            ⎢1   -1  -1  0   0   0   0   0   0 ⎥
            ⎢                                  ⎥
            ⎢0   0   1   -1  1   0   -1  1   2 ⎥
            ⎢                                  ⎥
            ⎢0   0   0   -1  1   1   0   0   0 ⎥
            ⎢                                  ⎥
            ⎢0   0   0   1   -1  -1  0   0   0 ⎥
            ⎢                                  ⎥
            ⎣0   0   0   0   0   0   1   -1  -1⎦
        """
        return self.__S

    def get_b(self):
        """
        Returns SymPy matrix representing the mass conservation matrix, :math:`B`.
        :download:`Fig1Ci.xml <../../sbml_files/Fig1Ci.xml>` for the provided
        example.

        Example
        --------
        >>> import crnt4sbml
        >>> import sympy
        >>> network = crnt4sbml.CRNT("path/to/Fig1Ci.xml")
        >>> sympy.pprint(network.get_c_graph().get_b())
            ⎡ 0    0    0    0   1.0  1.0   0 ⎤
            ⎢                                 ⎥
            ⎢ 0   1.0  1.0   0    0    0    0 ⎥
            ⎢                                 ⎥
            ⎣1.0   0   1.0  1.0   0   1.0  2.0⎦
        """
        return self.__B

    def get_lambda(self):
        """
        Returns SymPy matrix representing the linkage class matrix, :math:`\Lambda`.
        :download:`Fig1Ci.xml <../../sbml_files/Fig1Ci.xml>` for the provided
        example.

        Example
        --------
        >>> import crnt4sbml
        >>> import sympy
        >>> network = crnt4sbml.CRNT("path/to/Fig1Ci.xml")
        >>> sympy.pprint(network.get_c_graph().get_lambda())
            ⎡1  0  0⎤
            ⎢       ⎥
            ⎢1  0  0⎥
            ⎢       ⎥
            ⎢1  0  0⎥
            ⎢       ⎥
            ⎢0  1  0⎥
            ⎢       ⎥
            ⎢0  1  0⎥
            ⎢       ⎥
            ⎢0  1  0⎥
            ⎢       ⎥
            ⎢0  0  1⎥
            ⎢       ⎥
            ⎢0  0  1⎥
            ⎢       ⎥
            ⎣0  0  1⎦
        """
        return self.__Lambda

    def get_psi(self):
        """
        Returns SymPy matrix representing the mass action monomials, :math:`\psi`.
        :download:`Fig1Ci.xml <../../sbml_files/Fig1Ci.xml>` for the provided
        example.

        Example
        --------
        >>> import crnt4sbml
        >>> import sympy
        >>> network = crnt4sbml.CRNT("path/to/Fig1Ci.xml")
        >>> sympy.pprint(network.get_c_graph().get_psi())
            ⎡s₁⋅s₂⎤
            ⎢     ⎥
            ⎢ s₃  ⎥
            ⎢     ⎥
            ⎢s₂⋅s₆⎥
            ⎢     ⎥
            ⎢s₆⋅s₇⎥
            ⎢     ⎥
            ⎢ s₁₆ ⎥
            ⎢     ⎥
            ⎢s₁⋅s₇⎥
            ⎢     ⎥
            ⎢s₁⋅s₆⎥
            ⎢     ⎥
            ⎢ s₁₅ ⎥
            ⎢     ⎥
            ⎢   2 ⎥
            ⎣ s₆  ⎦
        """
        return self.__psi

    def get_g_nodes(self):
        """
        Returns a list of strings that represent the order of the nodes of the NetworkX DiGraph.

        Example
        --------
        >>> import crnt4sbml
        >>> network = crnt4sbml.CRNT("path/to/sbml_file.xml")
        >>> network.get_c_graph().get_g_nodes()
        """
        return self.__g_nodes

    def get_g_edges(self):
        """
        Returns a list of tuples of strings that represent the order of the edges of the NetworkX DiGraph.

        Example
        --------
        >>> import crnt4sbml
        >>> network = crnt4sbml.CRNT("path/to/sbml_file.xml")
        >>> network.get_c_graph().get_g_edges()
        """
        return self.__g_edges

    def get_weak_reversibility_of_linkage_classes(self):
        """
        Returns list of Python boolean types for the weak reversibility of each linkage class. If the linkage class is
        weakly reversible then the entry in the list is True, False otherwise with order as defined by
        :func:`crnt4sbml.Cgraph.get_linkage_classes`.

        Example
        --------
        >>> import crnt4sbml
        >>> network = crnt4sbml.CRNT("path/to/sbml_file.xml")
        >>> network.get_c_graph().get_weak_reversibility_of_linkage_classes()
        """
        return [networkx.is_strongly_connected(i) for i in self.__linkage_classes]

    def get_if_cgraph_weakly_reversible(self):
        """
        Returns weak reversibility of the network. If the network is weakly reversible True is returned, False otherwise.

        Example
        --------
        >>> import crnt4sbml
        >>> network = crnt4sbml.CRNT("path/to/sbml_file.xml")
        >>> network.get_c_graph().get_if_cgraph_weakly_reversible()
        """
        return all(self.get_weak_reversibility_of_linkage_classes())

    def get_dim_equilibrium_manifold(self):
        """
        Returns integer value representing the dimension of the equilibrium manifold, :math:`\lambda`. This value
        is the number of mass conservation relationships.
        :download:`Fig1Ci.xml <../../sbml_files/Fig1Ci.xml>` for the provided
        example.

        Example
        --------
        >>> import crnt4sbml
        >>> network = crnt4sbml.CRNT("path/to/Fig1Ci.xml")
        >>> print(network.get_c_graph().get_dim_equilibrium_manifold())
            3
        """
        return len(self.__species) - self.__S.rank()

    def get_deficiency(self):
        """
        Returns integer value representing the deficiency of the network, :math:`\delta`.
        :download:`Fig1Ci.xml <../../sbml_files/Fig1Ci.xml>` for the provided
        example.

        Example
        --------
        >>> import crnt4sbml
        >>> network = crnt4sbml.CRNT("path/to/Fig1Ci.xml")
        >>> print(network.get_c_graph().get_deficiency())
            2
        """
        return len(self.__complexes) - len(self.__linkage_classes) - self.__S.rank()

    def get_linkage_classes(self):
        """
        Returns list of NetworkX subgraphs representing the linkage classes.

        Example
        --------
        >>> import crnt4sbml
        >>> network = crnt4sbml.CRNT("path/to/sbml_file.xml")
        >>> network.get_c_graph().get_linkage_classes()
        """
        return self.__linkage_classes

    def get_network_dimensionality_classification(self):
        """
        Returns a two element list specifying the dimensionality of the network.
        Possible output:
        ["over-dimensioned",0]

        or

        ["proper",1]

        or

        ["under-dimensioned",2]

        or

        ["NOT DEFINED!",3]

        Example
        --------
        >>> import crnt4sbml
        >>> network = crnt4sbml.CRNT("path/to/sbml_file.xml")
        >>> network.get_c_graph().get_network_dimensionality_classification()
        """
        temp = self.get_dim_equilibrium_manifold() - self.get_deficiency()
        if temp < 0:
            network_class = "over-dimensioned"
            classification = 0
        elif temp == 0:
            network_class = "proper"
            classification = 1
        elif temp > 0:
            network_class = "under-dimensioned"
            classification = 2
        else:
            network_class = "NOT DEFINED!"
            classification = 3
        return [network_class, classification]

    def get_linkage_classes_deficiencies(self):
        """
        Returns an interger list of each linkage class deficiency. Here, the first element corresponds to the first
        linkage class with order as defined by :func:`crnt4sbml.Cgraph.get_linkage_classes`.

        Example
        ---------
        >>> import crnt4sbml
        >>> network = crnt4sbml.CRNT("path/to/sbml_file.xml")
        >>> network.get_c_graph().get_linkage_classes_deficiencies()
        """
        deficiencies = []
        for l in self.__linkage_classes:
            temp = [self.__g.edges[e]['label'] for e in l.edges]
            reactions_idx = [self.__reactions.index(i) for i in temp]
            deficiencies.append(networkx.number_of_nodes(l) - 1 - self.__S[:, reactions_idx].rank())
        return deficiencies

    def get_number_of_terminal_strong_lc_per_lc(self):
        """
        Returns an integer list stating the number of terminally strong linkage classes per linkage class. Here,
        the first element corresponds to the first linkage class with order as defined by
        :func:`crnt4sbml.Cgraph.get_linkage_classes`.

        Example
        ---------
        >>> import crnt4sbml
        >>> network = crnt4sbml.CRNT("path/to/sbml_file.xml")
        >>> network.get_c_graph().get_number_of_terminal_strong_lc_per_lc()
        """
        number_of_terminal_strong_lc_per_lc = []
        for lc_i in self.__linkage_classes:
            num_term_strong = 0
            strong_lcs = [lc_i.subgraph(c).copy() for c in networkx.strongly_connected_components(lc_i)]
            for slc_j in strong_lcs:
                slc_j_lbls = [i for i in slc_j.nodes]
                x = [lc_i.successors(v_i) for v_i in slc_j_lbls]
                connected_out_vertices = [item for sublist in x for item in sublist]
                d = set(connected_out_vertices) - set(slc_j_lbls)
                if d == set():
                    num_term_strong += 1
            number_of_terminal_strong_lc_per_lc.append(num_term_strong)
        return number_of_terminal_strong_lc_per_lc

    # public methods
    def print(self):
        """
        Prints edges and nodes of NetworkX DiGraph.

        See also
        ---------
        crnt4sbml.CRNT.print_c_graph
        """
        print("")
        print("Reaction graph of the form")
        print("reaction -- reaction label:")
        for e in self.__g_edges:
            print(e[0] + ' -> ' + e[1] + '  --  ' + self.__g.edges[e]['label'])
        print("")

    def plot(self):
        """
        Plots NetworkX DiGraph.

        See also
        ---------
        crnt4sbml.CRNT.plot_c_graph
        """
        pos = networkx.circular_layout(self.__g, scale=1.5)
        pos = networkx.kamada_kawai_layout(self.__g, pos=pos, scale=1.5)
        node_colors = [self.__g.nodes[n]['color'] for n in self.__g_nodes]
        networkx.draw(self.__g, pos, node_color=node_colors)
        node_labels = networkx.get_node_attributes(self.__g, 'label')
        networkx.draw_networkx_labels(self.__g, pos, labels=node_labels)
        edge_labels = networkx.get_edge_attributes(self.__g, 'label')
        networkx.draw_networkx_edge_labels(self.__g, pos, edge_labels, label_pos=0.3)
        plt.show()

    def plot_save(self):
        """
        Saves the plot of the NetworkX DiGraph.

        See also
        ---------
        crnt4sbml.CRNT.plot_save_c_graph
        """
        pos = networkx.circular_layout(self.__g, scale=1.5)
        pos = networkx.kamada_kawai_layout(self.__g, pos=pos, scale=1.5)
        node_colors = [self.__g.nodes[n]['color'] for n in self.__g_nodes]
        networkx.draw(self.__g, pos, node_color=node_colors)
        node_labels = networkx.get_node_attributes(self.__g, 'label')
        networkx.draw_networkx_labels(self.__g, pos, labels=node_labels)
        edge_labels = networkx.get_edge_attributes(self.__g, 'label')
        networkx.draw_networkx_edge_labels(self.__g, pos, edge_labels, label_pos=0.3)
        plt.savefig('network_cgraph.png')

reason: import numpy,import scipy,import sympy,import networkx


text:
#!/usr/bin/env python
import logging
import sys
from typing import List, Optional

import numpy as np
import pandas as pd

from cascade_at.executor.args.arg_utils import ArgumentList
from cascade_at.executor.args.args import ModelVersionID, BoolArg, ListArg, StrArg, LogLevel
from cascade_at.context.model_context import Context
from cascade_at.core.log import get_loggers, LEVELS
from cascade_at.dismod.api.dismod_io import DismodIO

LOG = get_loggers(__name__)

ARG_LIST = ArgumentList([
    ModelVersionID(),
    ListArg('--locations', help='The locations to pull mulcov statistics from', type=int, required=True),
    ListArg('--sexes', help='The sexes to pull mulcov statistics from', type=int, required=True),
    StrArg('--outfile-name', help='Filepath where mulcov statistics will be saved', required=False, default='mulcov_stats'),
    BoolArg('--sample', help='If true, the results will be pulled from the sample table rather'
                             'than the fit_var table'),
    BoolArg('--mean', help='Whether or not to compute the mean'),
    BoolArg('--std', help='Whether or not to compute the standard deviation'),
    ListArg('--quantile', help='Quantiles to compute', type=float),
    LogLevel()
])

def common_covariate_names(dbs):
    return set.intersection(
        *map(set, [d.covariate.c_covariate_name.tolist() for d in dbs])
    )

def get_mulcovs(dbs: List[DismodIO], covs: List[str],
                table: str = 'fit_var') -> pd.DataFrame:
    """
    Get mulcov values from all of the dbs, with all of the common covariates.

    Parameters
    dbs
        A list of dismod i/o objects
    covs
        A list of covariate names
    table
        Name of the table to pull from (can be fit_var or sample)
    """
    if table == 'fit_var':
        id_col = 'fit_var_id'
        val_col = 'fit_var_value'
    elif table == 'sample':
        id_col = 'var_id'
        val_col = 'var_value'
    else:
        raise ValueError("Must pass tables fit_var or sample.")

    dfs = pd.DataFrame()
    for db in dbs:
        mulcov = db.covariate[db.covariate.c_covariate_name.isin(covs)].merge(db.mulcov)
        try:
            df = db.var.merge(getattr(db, table), left_on='var_id', right_on=id_col)
            df = df.fillna(np.nan)
            df = df.merge(db.integrand, on='integrand_id', how='left')
            df = df.merge(db.rate, on='rate_id', how='left')
            mulcov = mulcov.astype({'integrand_id': 'float64', 'rate_id': 'float64'})
            df = mulcov.merge(df)
            df.rename(columns={val_col: 'mulcov_value'}, inplace=True)
            df = df[[
                'c_covariate_name', 'mulcov_type', 'rate_name',
                'integrand_name', 'mulcov_value'
            ]]
        except AttributeError:
            df = pd.DataFrame()
        dfs = dfs.append(df)
    return dfs

def compute_statistics(df, mean=True, std=True, quantile=None):
    """
    Compute statistics on a data frame with covariate multipliers.
    Args:
        df: pd.DataFrame
        mean: bool
        std: bool
        quantile: optional list

    Returns: dictionary with requested statistics

    """
    stats_df = pd.DataFrame()
    group_cols = ['c_covariate_name', 'mulcov_type', 'rate_name', 'integrand_name']
    df_groups = df.fillna('none').copy().groupby(group_cols, sort=False)
    stats_df = df_groups.count().reset_index()[group_cols]
    if mean:
        ds = df_groups.mean().reset_index()
        stats_df['mean'] = ds['mulcov_value']
    if std:
        degrees_of_freedom = int(df_groups.ngroups > len(df))
        ds = df_groups.std(ddof=degrees_of_freedom).reset_index()
        stats_df['std'] = ds['mulcov_value']
    if quantile is not None:
        for q in quantile:
            ds = df_groups.quantile(q=q).reset_index()
            stats_df[f'quantile_{q}'] = ds['mulcov_value']
    return stats_df

def mulcov_statistics(model_version_id: int, locations: List[int], sexes: List[int],
                      outfile_name: str, sample: bool = True,
                      mean: bool = True, std: bool = True,
                      quantile: Optional[List[float]] = None) -> None:
    """
    Compute statistics for the covariate multipliers on a dismod database,
    and save them to a file.

    Parameters
    ----------
    model_version_id
        The model version ID
    locations
        A list of locations that, when used in combination with sexes, point to the databases
        to pull covariate multiplier estimates from
    sexes
        A list of sexes that, when used in combination with locations, point to the databases
        to pull covariate multiplier estimates from
    outfile_name
        A filepath specifying where to save the covariate multiplier statistics.
    sample
        Whether or not the results are stored in the sample table or the fit_var table.
    mean
        Whether or not to compute the mean
    std
        Whether or not to compute the standard deviation
    quantile
        An optional list of quantiles to compute
    """

    context = Context(model_version_id=model_version_id)
    db_files = [DismodIO(context.db_file(location_id=loc, sex_id=sex))
                for loc in locations for sex in sexes]
    LOG.info(f"There are {len(db_files)} databases that will be aggregated.")

    common_covariates = common_covariate_names(db_files)
    LOG.info(f"The common covariates in the passed databases are {common_covariates}.")

    if sample:
        table_name = 'sample'
    else:
        table_name = 'fit_var'

    LOG.info(f"Will pull from the {table_name} table from each database.")
    mulcov_estimates = get_mulcovs(
        dbs=db_files, covs=common_covariates, table=table_name
    )
    if not mulcov_estimates.empty:
        stats = compute_statistics(
            df=mulcov_estimates, mean=mean, std=std, quantile=quantile
        )
    else:
        stats = mulcov_estimates
    LOG.info('Write to output file.')
    stats.to_csv(context.outputs_dir / f'{outfile_name}.csv', index=False)

def main():

    args = ARG_LIST.parse_args(sys.argv[1:])
    logging.basicConfig(level=LEVELS[args.log_level])

    mulcov_statistics(
        model_version_id=args.model_version_id,
        locations=args.locations,
        sexes=args.sexes,
        outfile_name=args.outfile_name,
        sample=args.sample,
        mean=args.mean,
        std=args.std,
        quantile=args.quantile
    )

if __name__ == '__main__':
    main()

max_stars_repo_name: ihmeuw/cascade-at

max_issues_repo_name: ihmeuw/cascade

max_forks_repo_name: ihmeuw/cascade


text:
import numpy as np
import warnings
warnings.filterwarnings("ignore")
import talib as ta
import yfinance as yf
import matplotlib.pyplot as plt
from datetime import datetime
import matplotlib.dates as mdates
from yahooquery import Ticker
import pandas as pd
import streamlit as st

from src.tools import functions as f0

plt.style.use('seaborn-talk')
sm, med, lg = 10, 15, 20
plt.rc("font", size=sm)  # controls default text sizes
plt.rc("axes", titlesize=med)  # fontsize of the axes title
plt.rc("axes", labelsize=med)  # fontsize of the x & y labels
plt.rc("xtick", labelsize=sm)  # fontsize of the tick labels
plt.rc("ytick", labelsize=sm)  # fontsize of the tick labels
plt.rc("legend", fontsize=sm)  # legend fontsize
plt.rc("figure", titlesize=lg)  # fontsize of the figure title
plt.rc("axes", linewidth=2)  # linewidth of plot lines
plt.rcParams["figure.figsize"] = [15, 8]
plt.rcParams["figure.dpi"] = 100

class Indicator_Ike(object):

    def __init__(self, ticker, date1=str(datetime.now())[:10], cc=0.0, ccc=0.0, graphit=True):
        self.stock = ticker
        self.date1 = date1
        self.cc = cc
        self.ccc = ccc
        self.graphit = graphit

    def get_data(self):
        data = yf.download(self.stock, period='1y')
        self.data = data.loc[:self.date1]
        return self.data

    def bollinger_bands(self, df):
        df['upper_band'], df['middle_band'], df['lower_band'] = ta.BBANDS(df['Close'], timeperiod =20)
        df["Signal"] = 0.0
        df["Signal"] = np.where(df['Close'] > df['middle_band'], 1.0, 0.0)
        df["Position"] = df["Signal"].diff()
        df_pos = df[(df["Position"] == 1) | (df["Position"] == -1)]
        df_pos["Position"] = df_pos["Position"].apply(lambda x: "Buy" if x == 1 else "Sell")

        if self.graphit is True:
            fig, ax = plt.subplots()
            plt.tick_params(axis="both", labelsize=15)
            df['Close'].plot(color="k", lw=2, label='Close')
            df['upper_band'].plot(color="g", lw=1, label='upper_band', linestyle='dashed')
            df['middle_band'].plot(color="r", lw=1, label='middle_band')
            df['lower_band'].plot(color="b", lw=1, label='lower_band', linestyle='dashed')
            # plot 'buy' signals
            plt.plot(
                df[df["Position"] == 1].index,
                df['Close'][df["Position"] == 1],
                "^", markersize=15, color="g", alpha=0.7, label="buy",
            )
            # plot 'sell' signals
            plt.plot(
                df[df["Position"] == -1].index,
                df['Close'][df["Position"] == -1],
                "v", markersize=15, color="r", alpha=0.7, label="sell",
            )
            plt.ylabel("Price", fontsize=20, fontweight="bold")
            plt.xlabel("Date", fontsize=20, fontweight="bold")
            plt.grid(True, color="k", linestyle="-", linewidth=1, alpha=0.3)
            ax.legend(loc="best", prop={"size": 16})
            plt.tight_layout()
            plt.show()
            st.pyplot(fig)

        try:
            if df_pos['Position'][-1] == 'Buy':
                st.metric(f"No. {self.cc} / {self.ccc} In Portfolio", f"{self.stock}", f"{df_pos['Position'][-1]}");
                return
            elif df_pos['Position'][-1] == 'Sell':
                st.metric(f"No. {self.cc} / {self.ccc} In Portfolio", f"{self.stock}", f"- {df_pos['Position'][-1]}")
        except Exception:
            pass

    def macd(self, data):
        data['macd'], data['macdsignal'], data['macdhist'] = ta.MACD(data['Close'], fastperiod=12, slowperiod=26, signalperiod=9)
        stock_df = pd.DataFrame(data)
        stock_df["Signal"] = 0.0
        stock_df["Signal"] = np.where(stock_df['macd'] > stock_df['macdsignal'], 1.0, 0.0)
        stock_df["Position"] = stock_df["Signal"].diff()
        df_pos = stock_df[(stock_df["Position"] == 1) | (stock_df["Position"] == -1)]
        df_pos["Position"] = df_pos["Position"].apply(lambda x: "Buy" if x == 1 else "Sell")
        stock_df.dropna(inplace=True)

        if self.graphit is True:
            fig, ax = plt.subplots()
            # plot close price, short-term and long-term moving averages
            plt.tick_params(axis="both", labelsize=15)
            stock_df["macdhist"].plot(color="r", lw=1.5, label="macdhist")
            stock_df['macd'].plot(color="b", lw=2, label='macd')
            stock_df['macdsignal'].plot(color="g", lw=2, label='macdsignal')
            # plot 'buy' signals
            plt.plot(
                stock_df[stock_df["Position"] == 1].index,
                stock_df['macd'][stock_df["Position"] == 1],
                "^", markersize=15, color="g", alpha=0.7, label="buy",
            )
            # plot 'sell' signals
            plt.plot(
                stock_df[stock_df["Position"] == -1].index,
                stock_df['macd'][stock_df["Position"] == -1],
                "v", markersize=15, color="r", alpha=0.7, label="sell",
            )
            plt.ylabel("MACD", fontsize=20, fontweight="bold")
            plt.xlabel("Date", fontsize=20, fontweight="bold")
            plt.grid(True, color="k", linestyle="-", linewidth=1, alpha=0.3)
            ax.legend(loc="best", prop={"size": 16})
            plt.tight_layout()
            plt.show()
            st.pyplot(fig)

        try:
            if df_pos['Position'][-1] == 'Buy':
                st.metric(f"No. {self.cc} / {self.ccc} In Portfolio", f"{self.stock}", f"{df_pos['Position'][-1]}");
                return
            elif df_pos['Position'][-1] == 'Sell':
                st.metric(f"No. {self.cc} / {self.ccc} In Portfolio", f"{self.stock}", f"- {df_pos['Position'][-1]}")
        except Exception:
            pass

        act_lst = []
        for i in stock_df['Position']:
            if i == 1.0:
                act_lst.append('Buy')
            elif i == -1.0:
                act_lst.append('Sell')
            else:
                act_lst.append('')
        stock_df['action'] = act_lst
        del stock_df['Open']
        del stock_df['High']
        del stock_df['Low']
        del stock_df['Adj Close']
        del stock_df['Volume']
        stock_df = stock_df[stock_df['action'] != ""]

    def rsi(self, data):
        df = pd.DataFrame(data).reset_index()
        df.columns = [x.lower() for x in df.columns]
        df.date = df.date.astype("str")
        date = [datetime.strptime(d, "%Y-%m-%d") for d in df["date"]]
        candlesticks = list(
            zip(
                mdates.date2num(date),
                df["open"],
                df["high"],
                df["low"],
                df["close"],
                df["volume"],
            )
        )
        df['rsi'] = ta.RSI(df['close'], timeperiod=14)
        df.dropna(inplace=True)

        def removal(signal, repeat):
            copy_signal = np.copy(signal)
            for j in range(repeat):
                for i in range(3, len(signal)):
                    copy_signal[i - 1] = (copy_signal[i - 2] + copy_signal[i]) / 2
            return copy_signal

        def get(original_signal, removed_signal):
            buffer = []
            for i in range(len(removed_signal)):
                buffer.append(original_signal[i] - removed_signal[i])
            return np.array(buffer)

        signal = np.copy(df.open.values)
        removed_signal = removal(signal, 30)
        noise_open = get(signal, removed_signal)

        signal = np.copy(df.high.values)
        removed_signal = removal(signal, 30)
        noise_high = get(signal, removed_signal)

        signal = np.copy(df.low.values)
        removed_signal = removal(signal, 30)
        noise_low = get(signal, removed_signal)

        signal = np.copy(df.close.values)
        removed_signal = removal(signal, 30)
        noise_close = get(signal, removed_signal)

        noise_candlesticks = list(
            zip(mdates.date2num(date),
            noise_open,
            noise_high,
            noise_low,
            noise_close
            )
        )
        df = df.set_index('date')

        if self.graphit is True:
            fig, ax = plt.subplots()
            # plot close price, short-term and long-term moving averages
            plt.tick_params(axis="both", labelsize=15)
            df["rsi"].plot(color="k", lw=2, label="rsi")
            ax.plot(
                df.index,
                [np.percentile(noise_close, 95)] * len(noise_candlesticks),
                color=(1.0, 0.792156862745098, 0.8, 1.0),
                linewidth=5.0,
                label="overbought line",
                alpha=1.0,
            )
            ax.plot(
                df.index,
                [np.percentile(noise_close, 82)] * len(noise_candlesticks),
                color=(0.6627450980392157, 1.0, 0.6392156862745098, 1.0),
                linewidth=5.0,
                label="oversold line",
                alpha=1.0,
            )
            plt.ylabel("RSI", fontsize=20, fontweight="bold")
            plt.xlabel("Date", fontsize=20, fontweight="bold")
            plt.grid(True, color="k", linestyle="-", linewidth=1, alpha=0.3)
            plt.legend(loc='upper right', prop={"size": 16})
            plt.tight_layout()
            plt.show()
            st.pyplot(fig)

        df["Signal"] = 0.0
        df["Signal"] = np.where(df['rsi'] > 30, 1.0, 0.0)
        df["Position"] = df["Signal"].diff()
        df_pos = df[(df["Position"] == 1) | (df["Position"] == -1)]
        df_pos["Position"] = df_pos["Position"].apply(lambda x: "Buy" if x == 1 else "Sell")

        try:
            if df_pos['Position'][-1] == 'Buy':
                st.metric(f"No. {self.cc} / {self.ccc} In Portfolio", f"{self.stock}", f"{df_pos['Position'][-1]}");

            elif df_pos['Position'][-1] == 'Sell':
                st.metric(f"No. {self.cc} / {self.ccc} In Portfolio", f"{self.stock}", f"- {df_pos['Position'][-1]}")
        except Exception:
            pass

    def kingpin(self):
        company_name = f0.company_longName(self.stock)
        x = f"{company_name} [{self.stock}]"
        self.data = self.get_data()

        st.subheader(f"𝄖𝄖𝄗𝄗𝄘𝄘𝄙𝄙𝄙 Bollinger Bands - {x} 𝄙𝄙𝄙𝄘𝄘𝄗𝄗𝄖𝄖")
        self.bollinger_bands(self.data)
        st.write("*"*34)

        st.subheader(f"𝄖𝄖𝄗𝄗𝄘𝄘𝄙𝄙𝄙 MACD - {x} 𝄙𝄙𝄙𝄘𝄘𝄗𝄗𝄖𝄖")
        self.macd(self.data)
        st.write("*"*34)

        st.subheader(f"𝄖𝄖𝄗𝄗𝄘𝄘𝄙𝄙𝄙 RSI - {x} 𝄙𝄙𝄙𝄘𝄘𝄗𝄗𝄖𝄖")
        self.rsi(self.data)


text:
# -*- coding: utf-8

"""Module of class Drum.

This file is part of project TESPy (github.com/oemof/tespy). It's copyrighted
by the contributors recorded in the version control history of the file,
available from its original location tespy/components/nodes/drum.py

SPDX-License-Identifier: MIT
"""

from tespy.components.nodes.droplet_separator import DropletSeparator
from tespy.tools.fluid_properties import h_mix_pQ

class Drum(DropletSeparator):
    r"""
    A drum separates saturated gas from saturated liquid.

    **Mandatory Equations**

    - :py:meth:`tespy.components.nodes.base.NodeBase.mass_flow_func`
    - :py:meth:`tespy.components.nodes.base.NodeBase.pressure_equality_func`
    - :py:meth:`tespy.components.nodes.droplet_separator.DropletSeparator.fluid_func`
    - :py:meth:`tespy.components.nodes.droplet_separator.DropletSeparator.energy_balance_func`
    - :py:meth:`tespy.components.nodes.droplet_separator.DropletSeparator.outlet_states_func`

    Inlets/Outlets

    - in1, in2 (index 1: from economiser, index 2: from evaporator)
    - out1, out2 (index 1: saturated liquid, index 2: saturated gas)

    Image

    .. image:: _images/Drum.svg
       :alt: alternative text
       :align: center

    Parameters
    ----------
    label : str
        The label of the component.

    design : list
        List containing design parameters (stated as String).

    offdesign : list
        List containing offdesign parameters (stated as String).

    design_path : str
        Path to the components design case.

    local_offdesign : boolean
        Treat this component in offdesign mode in a design calculation.

    local_design : boolean
        Treat this component in design mode in an offdesign calculation.

    char_warnings : boolean
        Ignore warnings on default characteristics usage for this component.

    printout : boolean
        Include this component in the network's results printout.

    Note
    ----
    If you are using a drum in a network with multiple fluids, it is likely
    the fluid propagation causes trouble. If this is the case, try to
    specify the fluid composition at another connection of your network.

    This component assumes, that the fluid composition between outlet 1 and
    inlet 2 does not change, thus there is no equation for the fluid mass
    fraction at the inlet 2!

    Example
    -------
    The drum separates saturated gas from saturated liquid. The liquid phase is
    transported to an evaporator, the staturated gas phase is extracted from
    the drum. In this example ammonia is evaporated using ambient air. A
    characteristic function is applied for the heat transfer coefficient of the
    evaporator. It is possible to load the CharLine with the function
    :code:`load_default_char` from the default lines. We want to use the
    'EVAPORATING FLUID' lines of the heat exchanger.

    >>> from tespy.components import Sink, Source, Drum, Pump, HeatExchanger
    >>> from tespy.connections import Connection, Ref
    >>> from tespy.networks import Network
    >>> from tespy.tools.characteristics import CharLine
    >>> from tespy.tools.characteristics import load_default_char as ldc
    >>> import shutil
    >>> import numpy as np
    >>> nw = Network(fluids=['NH3', 'air'], T_unit='C', p_unit='bar',
    ...     h_unit='kJ / kg', iterinfo=False)
    >>> fa = Source('feed ammonia')
    >>> amb_in = Source('air inlet')
    >>> amb_out = Sink('air outlet')
    >>> s = Sink('steam')
    >>> dr = Drum('drum')
    >>> dr.component()
    'drum'
    >>> ev = HeatExchanger('evaporator')
    >>> erp = Pump('evaporator reciculation pump')
    >>> f_dr = Connection(fa, 'out1', dr, 'in1')
    >>> dr_erp = Connection(dr, 'out1', erp, 'in1')
    >>> erp_ev = Connection(erp, 'out1', ev, 'in2')
    >>> ev_dr = Connection(ev, 'out2', dr, 'in2')
    >>> dr_s = Connection(dr, 'out2', s, 'in1')
    >>> nw.add_conns(f_dr, dr_erp, erp_ev, ev_dr, dr_s)
    >>> amb_ev = Connection(amb_in, 'out1', ev, 'in1')
    >>> ev_amb = Connection(ev, 'out1', amb_out, 'in1')
    >>> nw.add_conns(amb_ev, ev_amb)

    The ambient air enters the evaporator at 30 °C. The pinch point temperature
    difference (ttd_l) of the evaporator is at 5 K, and 1 MW of heat should be
    transferred. State of ammonia at the inlet is at -5 °C and 5 bar. From this
    design it is possible to calculate offdesign performance at 75 % part load.

    >>> char1 = ldc('heat exchanger', 'kA_char1', 'DEFAULT',
    ... CharLine)
    >>> char2 = ldc('heat exchanger', 'kA_char2', 'EVAPORATING FLUID',
    ... CharLine)
    >>> ev.set_attr(pr1=0.999, pr2=0.99, ttd_l=5, kA_char1=char1,
    ...     kA_char2=char2, design=['pr1', 'ttd_l'],
    ...     offdesign=['zeta1', 'kA_char'])
    >>> ev.set_attr(Q=-1e6)
    >>> erp.set_attr(eta_s=0.8)
    >>> f_dr.set_attr(p=5, T=-5)
    >>> erp_ev.set_attr(m=Ref(f_dr, 4, 0), fluid={'air': 0, 'NH3': 1})
    >>> amb_ev.set_attr(fluid={'air': 1, 'NH3': 0}, T=30)
    >>> ev_amb.set_attr(p=1)
    >>> nw.solve('design')
    >>> nw.save('tmp')
    >>> round(ev_amb.T.val - erp_ev.T.val ,1)
    5.0
    >>> round(f_dr.h.val, 1)
    322.7
    >>> round(dr_erp.h.val, 1)
    364.9
    >>> round(ev_dr.h.val, 1)
    687.2
    >>> round(f_dr.m.val, 2)
    0.78
    >>> ev.set_attr(Q=-0.75e6)
    >>> nw.solve('offdesign', design_path='tmp')
    >>> round(f_dr.m.val, 2)
    0.58
    >>> round(ev_amb.T.val - erp_ev.T.val ,1)
    3.0
    >>> shutil.rmtree('./tmp', ignore_errors=True)
    """

    @staticmethod
    def component():
        return 'drum'

    @staticmethod
    def inlets():
        return ['in1', 'in2']

    @staticmethod
    def outlets():
        return ['out1', 'out2']

    @staticmethod
    def initialise_source(c, key):
        r"""
        Return a starting value for pressure and enthalpy at outlet.

        Parameters
        ----------
        c : tespy.connections.connection.Connection
            Connection to perform initialisation on.

        key : str
            Fluid property to retrieve.

        Returns
        -------
        val : float
            Starting value for pressure/enthalpy in SI units.

            .. math::

                val = \begin{cases}
                10^6 & \text{key = 'p'}\\
                h\left(p, x=0 \right) & \text{key = 'h' at outlet 1}\\
                h\left(p, x=1 \right) & \text{key = 'h' at outlet 2}
                \end{cases}
        """
        if key == 'p':
            return 10e5
        elif key == 'h':
            if c.source_id == 'out1':
                return h_mix_pQ(c.get_flow(), 0)
            else:
                return h_mix_pQ(c.get_flow(), 1)

    @staticmethod
    def initialise_target(c, key):
        r"""
        Return a starting value for pressure and enthalpy at inlet.

        Parameters
        ----------
        c : tespy.connections.connection.Connection
            Connection to perform initialisation on.

        key : str
            Fluid property to retrieve.

        Returns
        -------
        val : float
            Starting value for pressure/enthalpy in SI units.

            .. math::

                val = \begin{cases}
                10^6 & \text{key = 'p'}\\
                h\left(p, x=0 \right) & \text{key = 'h' at inlet 1}\\
                h\left(p, x=0.7 \right) & \text{key = 'h' at inlet 2}
                \end{cases}
        """
        if key == 'p':
            return 10e5
        elif key == 'h':
            if c.target_id == 'in1':
                return h_mix_pQ(c.get_flow(), 0)
            else:
                return h_mix_pQ(c.get_flow(), 0.7)

    def propagate_fluid_to_target(self, inconn, start):
        r"""
        Propagate the fluids towards connection's target in recursion.

        Parameters
        ----------
        inconn : tespy.connections.connection.Connection
            Connection to initialise.

        start : tespy.components.component.Component
            This component is the fluid propagation starting point.
            The starting component is saved to prevent infinite looping.
        """
        if self != start:
            start = self
            for outconn in self.outl:
                for fluid, x in inconn.fluid.val.items():
                    if (outconn.fluid.val_set[fluid] is False and
                            outconn.good_starting_values is False):
                        outconn.fluid.val[fluid] = x

                outconn.target.propagate_fluid_to_target(outconn, start)

    def propagate_fluid_to_source(self, outconn, start):
        r"""
        Propagate the fluids towards connection's source in recursion.

        Parameters
        ----------
        outconn : tespy.connections.connection.Connection
            Connection to initialise.

        start : tespy.components.component.Component
            This component is the fluid propagation starting point.
            The starting component is saved to prevent infinite looping.
        """
        if self != start:
            start = self
            for inconn in self.inl:
                for fluid, x in outconn.fluid.val.items():
                    if (inconn.fluid.val_set[fluid] is False and
                            inconn.good_starting_values is False):
                        inconn.fluid.val[fluid] = x

                inconn.source.propagate_fluid_to_source(inconn, start)

    def get_plotting_data(self):
        """
        Generate a dictionary containing FluProDia plotting information.

        Returns
        -------
        data : dict
            A nested dictionary containing the keywords required by the
            :code:`calc_individual_isoline` method of the
            :code:`FluidPropertyDiagram` class. First level keys are the
            connection index ('in1' -> 'out1', therefore :code:`1` etc.).
        """
        return {
            1: {
                'isoline_property': 'p',
                'isoline_value': self.outl[0].p.val,
                'isoline_value_end': self.outl[1].p.val,
                'starting_point_property': 'v',
                'starting_point_value': self.outl[0].vol.val,
                'ending_point_property': 'v',
                'ending_point_value': self.outl[1].vol.val
            }}


text:
from typing import Dict, Union, Tuple, Iterator, Optional, Iterable, Sequence, Generic, TypeVar, Callable, List, \
    ItemsView, KeysView, ValuesView

import numpy as np

from reconstruction.data.data_utils import MinMaxCheck, PositionIter
from reconstruction.mathlib import Vec3i

T = TypeVar('T')
Index = Tuple[int, int, int]
IndexUnion = Union[Index, Sequence[int], np.ndarray]

class IndexDict(Generic[T]):
    """
    A dictionary that uses 3d integer position tuples as keys.

    It keeps track of the minimum and maximum positions, which enables a fast size query.
    """
    __slots__ = ('_data', '_minmax')

    def __init__(self) -> None:
        self._data: Dict[Index, T] = dict()
        self._minmax = MinMaxCheck()

    def clear(self):
        self._data.clear()
        self._minmax.clear()

    def __delitem__(self, key):
        index = self.index(key)
        del self._data[index]
        self._minmax.set_dirty()

    def pop(self, index, default=None) -> Optional[T]:
        l = len(self._data)
        c = self._data.pop(index, default)
        if l != len(self._data):
            self._minmax.set_dirty()
        return c

    def minmax(self, asarray=False) -> Tuple[Vec3i, Vec3i]:
        """ Returns the min and max index of all contained indices"""
        if asarray:
            # noinspection PyTypeChecker
            return np.asarray(self._minmax.safe(self._data.keys), dtype=np.int)
        return self._minmax.safe(self._data.keys)

    def size(self) -> Vec3i:
        if self._data:
            min, max = self.minmax(True)
            return max - min + 1
        return np.zeros(3, dtype=np.int)

    @classmethod
    def index(cls, item: IndexUnion) -> Index:
        item = np.asarray(item, dtype=np.int)
        if item.shape != (3,):
            raise IndexError(f"Invalid index {item}")
        return tuple(item)

    def get(self, index: Index, default=None) -> Optional[T]:
        return self._data.get(self.index(index), default)

    def __getitem_from_numpy(self, item: np.ndarray, ignore_empty=True) -> Union[T, List[T]]:
        item = np.asarray(item, dtype=np.int)
        if item.shape == (3,):
            return self._data[tuple(item)]
        else:
            assert item.ndim == 2 and item.shape[1] == 3
            if ignore_empty:
                return [d for d in (self._data.get(tuple(i), None) for i in item) if d is not None]
            else:
                return [self._data[tuple(i)] for i in item]

    def sliced_iterator(self, x: Union[int, slice, None] = None, y: Union[int, slice, None] = None,
                        z: Union[int, slice, None] = None) -> PositionIter:
        if not self._data:
            return PositionIter.empty()
        k_min, k_max = self.minmax(True)
        return PositionIter(x, y, z, low=k_min, high=k_max + 1)

    def sliced(self, x: Union[int, slice, None] = None, y: Union[int, slice, None] = None,
               z: Union[int, slice, None] = None, ignore_empty=True) -> Iterator[T]:
        if not self._data:
            return
        if x is None and y is None and z is None:
            yield from self._data.values()
        else:
            it = self.sliced_iterator(x, y, z)
            if ignore_empty:
                for key in it:
                    if key in self._data:
                        yield self._data[key]
            else:
                for key in it:
                    yield self._data.get(key)

    def __getitem__(self, item: Union[IndexUnion, slice, Tuple[slice, ...]]) -> Union[T, List[T]]:
        if isinstance(item, slice):
            return list(self.sliced(item))
        if isinstance(item, tuple):
            try:
                index = np.asarray(item, dtype=np.int)
                if index.shape == (3,):
                    return self._data[self.index(item)]
                raise KeyError(f"invalid key {item}")
            except TypeError:
                pass
            if 0 < len(item) <= 3 and any(isinstance(i, slice) for i in item):
                return list(self.sliced(*item))
            raise KeyError(f"invalid key {item}")
        elif isinstance(item, (list, np.ndarray)):
            return self.__getitem_from_numpy(np.array(item, dtype=int))
        else:
            raise KeyError(f"invalid key {item}")

    def insert(self, index: Index, value: T):
        index = self.index(index)
        self._data[index] = value
        self._minmax.add(index)

    def __setitem__(self, key: Index, value: T):
        self.insert(key, value)

    def __contains__(self, item: Index) -> bool:
        return self.index(item) in self._data

    def setdefault(self, index: Index, default: T) -> T:
        index = self.index(index)
        c = self._data.get(index, None)
        if c is None:
            self._data[index] = default
            self._minmax.add(index)
            return default
        return c

    def create_if_absent(self, index: Index, factory: Callable[[Index], T], *, insert=True) -> T:
        index = self.index(index)
        _data = self._data
        c = _data.get(index, None)
        if c is None:
            c = factory(index)
            if insert:
                _data[index] = c
                self._minmax.add(index)
        return c

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

    def items(self) -> ItemsView[Index, T]:
        return self._data.items()

    def keys(self) -> KeysView[Index]:
        return self._data.keys()

    def values(self) -> ValuesView[T]:
        return self._data.values()

    def __iter__(self) -> Iterable[T]:
        return iter(self._data.values())