import sys
import getopt
import functools
import operator
from queue import Queue

def usage(name):
    sys.stderr.write("Usage: %s [-h] [-m]  [-v LEVEL] [-q PCNF] [-g DEFINITION] [-o OUTPCNF] [-o OUTMAP] " % name)
    sys.stderr.write("  -h                Print this message\n")
    sys.stderr.write("  -v LEVEL          Verbose output level 1: definition detection...\n")
    sys.stderr.write("  -q PCNF           Name of PCNF input file\n")
    sys.stderr.write("  -g DEFINITION     Name of DEFINITION input file\n")
    sys.stderr.write("  -o OUTPCNF        Name of Output PCNF file\n")
    sys.stderr.write("  -b OUTMAP         Name of Output map file: (var, newvar, type)\n")
    sys.stderr.write("  -m                Move definitions in output PCNF\n")

def trim(s):
    while len(s) > 0 and s[-1] in '\r\n':
        s = s[:-1]
    return s

class QbfException(Exception):

    def __init__(self, value):
        self.value = value

    def __str__(self):
        return "QBF Exception: " + str(self.value)

class DefinitionException(Exception):

    def __init__(self, value):
        self.value = value

    def __str__(self):
        return "Definition Exception: " + str(self.value)

class Definition():

  def __init__(self, d_outlit, d_clauses, d_inputs, d_type):
    self.outlit   = d_outlit
    self.clauses  = d_clauses
    self.inputs   = d_inputs
    self.type     = d_type

class QBF_Definition_Processor():

  verbosity = 0         # level of verbose output

  # QBF information
  nvar = 0
  nvar_orig = 0
  ncls = 0
  nqlevels = 0
  variable_clauses = {} # map: vid -> list of clsids
  variable_qlevel  = {} # map: vid -> qlevel (quantification level) id
  clauses = []          # list of clauses, clause is list of integers
  quantifiers = []      # list of pairs ("a|e", [vids])

  # Definition information
  ndefinitions = 0
  definitions = []            # list of definitions
  is_definition_out    = []   # vid -> 1 if vid is output of a definition, 0 otherwise
  variable_d_out = {}   # map: vid -> definition that vid is the output of
  variable_g_in  = {}   # map: vid -> definitions that vid is the input of

  # XOR definition information
  nxor_definitions = 0
  xor_definitions = []          # list of xor definitions (d_out, d_clauses, d_inputs)
                          #   d_out is the temporary definition output giving by the definition
                          #   definition. This may change in xor definition processing
  variable_xor_definitions = {} # map: vid   -> xor definition ids with vid in defining clauses
  clauses_xor_definitions  = {} # map: clsid -> xor definition id with clsid in definition

  # Definition processing information
  ndefinitions_moved = 0      # number of definition outputs moved to lower qlevel
                        # variables in defining clauses (not proper definitions in qbf)
  total_nlevels_moved=0 # sum of diff in level for each variable moved
  var_map = [0]         # map old variable IDs to new values (when introducing
                        # new Tseiten variables
  reverse_var_map = [0]
  actual_move_type = {}
  restrictDefinitions = False

  one_sided_moves                 = 0
  definitions_out_of_order        = 0
  definitions_on_universal        = 0
  definitions_notdefined          = 0
  definitions_one_sided_incorrect = 0
  nxor_moved                      = 0
  nsemantic_moved                 = 0

  last_level = []       # LDomino check on movement of variables in last Qlevel
  var_moved = None

  candidate_lists = None # move algorithm
  seen_n = None
  seen_xor = None

  proof = None
  writeProof = False
  prove_no_write = False

  def __init__(self, qbfName, proofName = None, verbosity = 0, prove_no_write = False, restrictDefinitions = False, pseudo = False, tool = None):
    if not proofName is None:
      self.proof = open(proofName, 'w')
      self.writeProof = True
    self.prove_no_write = prove_no_write
    self.restrictDefinitions = restrictDefinitions
    self.pseudo = pseudo
    self.tool = tool

    self.read_qbf(qbfName)
    for i in range(1,self.nvar+1):
      self.var_map.append(i)
      self.reverse_var_map.append(i)
    self.verbosity = verbosity

    for i in self.quantifiers[-2][1]: # variables in last level
      self.last_level.append(i)
    self.var_moved = [0]*(self.nvar+1)
    self.nvar_orig = self.nvar

  #####################################################################################
  # PARSING FUNCTIONS
  # QBF, DEFINITIONS
  #####################################################################################

  # Parser adapted from PGBDDQ, Randy E. Bryant
  # Read quantifiers and clauses into QBF information
  # Quantifier levels (qlevels) are read as even numbers 0,2,4,..
  #   odd numbered qlevels reserved for moved T-Levels
  def read_qbf(self, fname):
    file = open(fname, 'r')
    lineNumber = 0
    qlevel = 0
    clscnt = 0
    getting_quantifiers = False

    for line in file:
      lineNumber += 1
      line = trim(line)
      if len(line) == 0:
        continue
      elif line[0] == 'c':
        continue
      elif line[0] == 'p':
        fields = line[1:].split()
        if len(fields) != 3 or fields[0] != 'cnf':
            raise QbfException("Line %d.  Bad header line '%s'.  Not qbf" % (lineNumber, line))
        try:
          self.nvar = int(fields[1])
          self.ncls = int(fields[2])
        except Exception:
          raise QbfException("Line %d.  Bad header line '%s'.  Invalid number of variables or clauses" % (lineNumber, line))
        self.is_definition_out = [0] * (self.nvar +1)
        getting_quantifiers = True

      elif line[0] == 'a' or line[0] == 'e':
        if not getting_quantifiers:
          raise QbfException("Line %d.  Quantifier out of order line '%s'.  Not qbf" % (lineNumber, line))
        try:
            vars = [int(s) for s in line[1:].split()]
        except:
            raise QbfException("Line %d.  Non-integer field" % lineNumber)
        if vars[-1] != 0:
            raise QbfException("Line %d.  Quantifier line should end with 0" % lineNumber)
        vars = vars[:-1]
        self.quantifiers.append((line[0],vars[:])) # Original quantifier level (Even index 0,2,4,...)
        self.quantifiers.append(('e',[])) # T-level following original quantifier level (Odd index 1,3,5,...)
        for v in vars: # check variable not in a previous qlevel
          if v in self.variable_qlevel:
            raise QbfException("Line %d.  %d in two quantifier levels.  Not qbf" % (lineNumber, v))
          self.variable_qlevel[v] = qlevel
        qlevel += 2 # reserve odds for T-Level
      else:
        getting_quantifiers = False
        # Check formatting
        try:
          lits = [int(s) for s in line.split()]
        except:
          raise QbfException("Line %d.  Non-integer field" % lineNumber)
        # Last one should be 0
        if lits[-1] != 0:
          raise QbfException("Line %d.  Clause line should end with 0" % lineNumber)
        lits = lits[:-1]
        vars = sorted([abs(l) for l in lits])
        if len(vars) == 0:
          raise QbfException("Line %d.  Empty clause" % lineNumber)
        if vars[-1] > self.nvar or vars[0] == 0:
          raise CnfException("Line %d.  Out-of-range literal" % lineNumber)
        for i in range(len(vars) - 1):
          if vars[i] == vars[i+1]:
            raise QbfException("Line %d.  Opposite or repeated literal" % lineNumber)
        match = True
        if vars[-1] in self.variable_clauses:
          for clsidP in self.variable_clauses[vars[-1]]:
            litsP = self.clauses[clsidP]
            if len(litsP) < len(lits):
              match = False
              continue
            match = True
            for l in litsP:
              if l not in lits:
                match = False
                break
            if match: break
          if match: # Do not accept repeated clauses
            self.ncls -= 1
            continue

        self.clauses.append(lits)
        for v in vars:
            if v in self.variable_clauses:
                self.variable_clauses[v].append(clscnt)
            else:
               self.variable_clauses[v] = [clscnt]
        clscnt += 1

    if clscnt != self.ncls:
      raise QbfException("Line %d: Got %d clauses.  Expected %d" % (lineNumber, clscnt, self.ncls))

    self.nqlevels = qlevel

    file.close()

  # Read definitions into Definitions information
  # input format:
  #   'DefinitionType' <Int> 'OutLit' <Int>
  #   clauses (not 0 terminated)
  #   'endG'
  #
  # Definition Types:
  # 0: exotic (not pattern matched; semantic check)
  # 1: equivalence
  # 2: and
  # 3: or
  # 4: xor (full pattern in cnftools: not, xor, nxor, maj3, etc..)
  # 5: ite
  # 10: Monotonic
  #
  # XOR/Equivalence/Semantic/Monotonic definitions read into XOR information
  def read_definitions(self, fname):
    file = open(fname, 'r')
    lineNumber = 0
    definitioncnt = 0
    d_out = 0
    d_type = 0
    d_clauses = []
    d_inputs = []
    is_mon_out = [0] * self.ncls
    is_xor_clause = [0] * self.ncls

    broken_clause = False # Clause not found in input QBF
    xorcnt = 0
    scrap_definition = False
    repeated_XOR = False
    for line in file:
      lineNumber += 1
      line = trim(line)
      if len(line) == 0:
        continue
      elif line[0] == 'c':
        continue
      elif line[0:8] == 'GateType': # Start of new definition
        scrap_definition = False
        broken_clause = False
        repeated_XOR = False
        fields = line.split()
        d_type = int(fields[1])
        d_out = int(fields[3])

        if self.quantifiers[self.variable_qlevel[abs(d_out)]][0] == 'a' and (d_type == 2 or d_type == 3 or d_type == 5): # definitionoutput is universal lit
          self.definitions_on_universal += 1
          scrap_definition = True
        if self.quantifiers[self.variable_qlevel[abs(d_out)]][0] == 'a' and d_type == 10:
          self.definitions_on_universal += 1

        d_clauses = []
        d_inputs = []
      elif broken_clause: continue # consume lines until next new definition
      elif scrap_definition: continue
      elif repeated_XOR: continue
      elif line[0:4] == 'endG':    # end of a definition
        if d_type == 10: is_mon_out[abs(d_out)] = 1

        d_inputs = list(set(d_inputs))
        d_inputs.remove(abs(d_out))        # input variables of definition

        if d_type == 1 or d_type == 4 or d_type == 0 or d_type == 10: # Possibly XOR type definition
          self.xor_definitions.append(Definition(d_out, d_clauses, d_inputs, d_type))
          for v in d_inputs + [abs(d_out)]: # map vid to xor definition
            if v in self.variable_xor_definitions:
              self.variable_xor_definitions[v].append(xorcnt)
            else:
              self.variable_xor_definitions[v] = [xorcnt]
          xorcnt += 1
        else:
          self.definitions.append(Definition(d_out, d_clauses, d_inputs, d_type))
          for v in d_inputs: # map vid to definition as input
            if v in self.variable_g_in:
              self.variable_g_in[v].append(definitioncnt)
            else:
              self.variable_g_in[v] = [definitioncnt]
          self.is_definition_out[abs(d_out)] = 1
          definitioncnt += 1
      else: # read in a defining clause for current definition
        try:
          lits = [int(s) for s in line.split()]
        except:
          raise DefinitionException("Line %d.  Non-integer field" % lineNumber)
        clsID = self.find_cls(lits) # Find clause in current clause db
        if clsID == -1:             # clause not found, this definition is broken
          broken_clause = True
          print("e Broken clause in definition file Line %d." % lineNumber)
          continue
        if clsID in d_clauses:
          broken_clause = True
          print("e Repeated clause %d." % lineNumber) # Should never occur
          continue # no repeated clauses
        if d_type == 1 or d_type == 4 or d_type == 0: # avoid rereading same definition (monotonic excluded because def may be different)
          if is_xor_clause[clsID] == 1:
            repeated_XOR = True
            continue
          is_xor_clause[clsID] = 1
          self.clauses_xor_definitions[clsID] = xorcnt
        d_clauses.append(clsID)
        d_inputs += [abs(l) for l in lits]

    file.close()
    self.ndefinitions = definitioncnt
    self.nxor_definitions = xorcnt

  # Return clsid in current db: self.clauses
  #  -1 if not found
  def find_cls(self, lits):
    min_occ = len(self.variable_clauses[abs(lits[0])])
    min_var = abs(lits[0])
    # get variable with least occurences before checking for exact match
    for l in lits[1:]:
      v = abs(l)
      if len(self.variable_clauses[v]) < min_occ:
        min_var = v
        min_occ = len(self.variable_clauses[v])
    # TDOD: clause mask for faster check
    for cls in self.variable_clauses[min_var]:
      eq = True
      if len(self.clauses[cls]) != len(lits): continue
      for l in self.clauses[cls]:
        if l not in lits:
          eq = False
          break
      if eq: return cls
    return -1

  #####################################################################################
  # DEFINITION PROCESSING FUNCTIONS
  # MOVE DEFINITION OUTPUTS IN ORDER, CHECK DEFINITIONS ARE VALID
  #####################################################################################

  # in_l <= out_l
  def q_distance(self, in_l, out_l) :
    cnt = 0
    for i in range(in_l,out_l):
      if self.quantifiers[i][0] == 'a': cnt += 1
    return cnt

  def propagate_definition_move(self,moved_g):
    if moved_g in self.variable_g_in:
      for gidx in self.variable_g_in[moved_g]:
        g = self.definitions[gidx]
        (inner_l, inner_v) = self.get_innermost_level([self.var_map[i] for i in g.inputs])
        out_l = self.variable_qlevel[abs(g.outlit)]
        if out_l - inner_l > 1: # dist == 1 for pseudo
          if self.is_T_level(inner_l): self.candidate_lists[inner_l].append((gidx, False))
          else: self.candidate_lists[inner_l+1].append((gidx, False)) # +1 for T-level
        elif out_l - inner_l < 0:
          self.definitions_out_of_order += 1
        elif self.pseudo and (out_l - inner_l == 1) and self.is_T_level(inner_l):
          self.candidate_lists[inner_l].append((gidx, False))
    if moved_g in self.variable_xor_definitions:
      for gidx in self.variable_xor_definitions[moved_g]:
        if self.seen_xor[gidx] == 1: continue
        g = self.xor_definitions[gidx]
        (out_l, out_v) = self.get_innermost_level([self.var_map[i] for i in (g.inputs+[abs(g.outlit)])])
        (inner_l, inner_v) = self.get_innermost_level([self.var_map[i] for i in (g.inputs+[abs(g.outlit)]) if i != out_v])
        inner_v = self.reverse_var_map[inner_v]
        out_v = self.reverse_var_map[out_v]
        if inner_l == out_l or inner_l == out_l-1: continue
        if self.is_definition_out[out_v] == 1: continue
        if out_l - inner_l > 1: # dist == 1 for pseudo
          if not (out_v == abs(g.outlit)):
            self.xor_definitions[gidx].inputs.append(abs(g.outlit))
            self.xor_definitions[gidx].inputs.remove(out_v)
            if g.type == 10: self.definitions_out_of_order += 1 # check mono but not for XOR
          self.xor_definitions[gidx].outlit = out_v # lost sign on output variable for XOR
          if self.is_T_level(inner_l): self.candidate_lists[inner_l].append((gidx, True))
          else: self.candidate_lists[inner_l+1].append((gidx, True)) # +1 for T-level
        elif self.pseudo and (out_l - inner_l == 1) and self.is_T_level(inner_l):
          if inner_v not in self.xor_definitions[gidx].inputs:
            self.xor_definitions[gidx].inputs.append(inner_v)
            self.xor_definitions[gidx].inputs.remove(out_v)
          self.xor_definitions[gidx].outlit = out_v # lost sign on output variable for XOR
          self.candidate_lists[inner_l].append((gidx, True))

  def move(self,gidx, is_xor, level):
    # find level to be moved
    if is_xor == 1:
      g = self.xor_definitions[gidx]
    else:
      g = self.definitions[gidx]
    d_out = abs(g.outlit)

    (inner_l, inner_v) = self.get_innermost_level([self.var_map[i] for i in g.inputs])
    if inner_l != level and inner_l+1 != level:
      print("e candidate level and actual level do not match for d_out %d" % (g.outlit))

    dist = self.q_distance(level,self.variable_qlevel[d_out])
    if dist < 1 and not self.pseudo:
      return False

    # check not universal variable for XOR
    if self.quantifiers[self.variable_qlevel[abs(d_out)]][0] == 'a':
      self.definitions_on_universal += 1
      return False

    proved = self.prove_definition_move(gidx, self.variable_qlevel[d_out], level, is_xor) # correct input?

    if not proved:
      self.nvar -= 1
      return False

    self.total_nlevels_moved += dist
    self.ndefinitions_moved += 1
    self.var_moved[d_out] = 1
    self.is_definition_out[d_out] = 1 # for XOR definitions
    self.actual_move_type[d_out] = g.type
    if g.type == 4 : self.nxor_moved += 1
    if g.type == 0: self.nsemantic_moved += 1

    return True

  def get_innermost_level(self, vars):
    levels = [self.variable_qlevel[v] for v in vars]
    inner_l = 0
    inner_v = 0
    for i in range(len(vars)):
      if levels[i] >= inner_l:
        inner_v = vars[i]
        inner_l = levels[i]
    return (inner_l, inner_v)

  def is_T_level(self,level): return (level % 2 == 1)

  def move_by_level(self):
    self.seen_n = [0] * self.ndefinitions
    self.seen_xor = [0] * self.nxor_definitions
    self.candidate_lists = []
    for i in range(self.nqlevels): self.candidate_lists.append([])

    # initialize candidate_lists
    for gidx in range(self.ndefinitions):
      g = self.definitions[gidx]
      (inner_l, inner_v) = self.get_innermost_level([self.var_map[i] for i in g.inputs])
      out_l = self.variable_qlevel[abs(g.outlit)]
      if out_l - inner_l > 0:
        self.candidate_lists[inner_l+1].append((gidx, False)) # +1 for T-level
      elif out_l - inner_l < 0:
        self.definitions_out_of_order += 1
    for gidx in range(self.nxor_definitions):
      g = self.xor_definitions[gidx]
      (out_l, out_v) = self.get_innermost_level([self.var_map[i] for i in (g.inputs+[abs(g.outlit)])])
      (inner_l, inner_v) = self.get_innermost_level([self.var_map[i] for i in (g.inputs+[abs(g.outlit)]) if i != out_v])
      if inner_l == out_l or inner_l == out_l-1: continue
      if self.is_definition_out[out_v] == 1: continue
      if out_l - inner_l > 0:
        if not (out_v == abs(g.outlit)):
            self.xor_definitions[gidx].inputs.append(abs(g.outlit))
            self.xor_definitions[gidx].inputs.remove(out_v)
            if g.type == 10: self.definitions_out_of_order += 1 # check mono but not for XOR
        self.xor_definitions[gidx].outlit = out_v # lost sign on output variable for XOR
        self.candidate_lists[inner_l+1].append((gidx, True)) # +1 for T-level

    # move by level
    for level in range(0,self.nqlevels-2): # will skip non T-levels which have no candidates...
      while len(self.candidate_lists[level]) > 0:
        (gidx,is_xor) = self.candidate_lists[level].pop(0)
        if is_xor :
          if self.seen_xor[gidx] == 1: continue
          else: self.seen_xor[gidx] = 1
          if self.var_moved[abs(self.xor_definitions[gidx].outlit)] == 1: continue
        if not is_xor:
          if self.seen_n[gidx] == 1: continue
          else: self.seen_n[gidx] = 1
          if self.var_moved[abs(self.definitions[gidx].outlit)] == 1: continue
        moved = self.move(gidx,is_xor,level)
        if moved:
          if is_xor == 1: self.propagate_definition_move(abs(self.xor_definitions[gidx].outlit))
          else:self.propagate_definition_move(abs(self.definitions[gidx].outlit))

  def prove_definition_move(self, gidx, old_level, max_level, is_xor):
    if is_xor == 1: g = self.xor_definitions[gidx]
    else: g = self.definitions[gidx]
    d_outlit = g.outlit
    d_out = abs(d_outlit)
    d_clauses = g.clauses
    d_inputs = [self.var_map[i] for i in g.inputs]
    d_type = g.type
    self.nvar += 1
    new_var = self.nvar
    one_sided = True
    one_sided_lit = 0
    sign_l = int(d_outlit/(abs(d_outlit)))
    aux = (d_type not in [1,2,3]) or (len(d_clauses) != 2 or len(d_inputs) != 1)
    bic = d_type != 1 or (len(d_clauses) != 2 or len(d_inputs) != 1)

    new_d_clauses = []
    old_d_clauses = []
    clause_updates = []
    delete_list = []
    proof_list = []

    bicond1 = None
    bicond2 = None

    # STEP 1: ADD Defining clauses for x' = new_var
    for clsid in d_clauses:
      cls = self.clauses[clsid]
      if d_type == 10 and (d_out not in cls and -d_out not in cls):
        return False # incorrectly using it as an XOR, i.e., clauses do not define d_out
      if one_sided: # check if one-sided definition
        if one_sided_lit == 0:
          one_sided_lit = [v for v in cls if abs(v) == d_out][0]
        else:
          lit = [v for v in cls if abs(v) == d_out][0]
          if lit != one_sided_lit:
            one_sided = False
      new_cls = cls[:]
      if d_out in new_cls:
        new_cls.remove(d_out)
        new_cls = [new_var] + new_cls
      else:
        new_cls.remove(-d_out)
        new_cls = [-new_var] + new_cls
      old_d_clauses.append(cls)
      new_d_clauses.append(new_cls)

      proof_list.append((0,new_cls[:]))
      clause_updates.append((clsid,new_cls[:])) # cannot add them right away in case process fails

    aux = aux and not one_sided

    # STEP 2: ADD BiEquivalence x <-> x' clauses
    if one_sided: # definition output appears as one sided literal (not fully-defined)
      bicond1 = [sign_l*new_var, -1*d_outlit]
      proof_list.append((0,bicond1))
      bic = False

    if bic: # add first side
      bicond2 = [new_var,-d_out]
      proof_list.append((0,bicond2))

    if aux: # derive other side
      aux_clauses = self.biconditional_aux_resolvents(d_out, new_var, old_d_clauses, new_d_clauses, d_inputs)
      if len(aux_clauses) == 0:
        self.print_verb("c Failed finding auxilliary clauses for %d" % (d_out),1)
        self.definitions_notdefined += 1
        return False

      last_clause = aux_clauses[-1]
      if last_clause != [d_out, -new_var] and last_clause != [ -new_var, d_out]:
        self.print_verb("c Failed finding auxilliary clauses for %d" % (d_out),1)
        self.definitions_notdefined += 1
        return False
      # ADD Auxiliary clauses
      for cls in aux_clauses[:-1]:
        proof_list.append((0,cls))

    if bic: # ADD other implication
      bicond1 = [d_out, -new_var]
      proof_list.append((0,bicond1))

    if aux: # REMOVE Auxiliary clauses
      aux_clauses = aux_clauses[:-1]
      aux_clauses.reverse()
      for cls in aux_clauses:
        proof_list.append((1,cls))

    # STEP 3: ADD/DELETE Remaining clauses
    for clsID in self.variable_clauses[d_out]:
      if clsID in d_clauses: continue
      cls = self.clauses[clsID]
      new_cls = [int (v/abs(v)) * new_var if abs(v) == d_out else v for v in cls]
      g_temp = new_var
      if -new_var in new_cls:
        g_temp = -new_var
        new_cls.remove(-new_var)
      else: new_cls.remove(new_var)
      new_cls = [g_temp] + new_cls

      g_temp = d_out
      old_cls = cls[:]
      if -d_out in old_cls:
        g_temp = -d_out
        old_cls.remove(-d_out)
      else: old_cls.remove(d_out)
      old_cls = [g_temp] + old_cls

      proof_list.append((0,new_cls))

      clause_updates.append((clsID,new_cls[:]))
      if one_sided:
        tcls = cls[:]
        g_temp = d_out
        if -d_out in tcls:
          if -one_sided_lit != -d_out: #not actually one-sided (w.r.t. remaining clauses)
            self.definitions_one_sided_incorrect += 1
            return False
          g_temp = -d_out
          tcls.remove(-d_out)
        else:
          if -one_sided_lit != d_out: #not actually one-sided
            self.definitions_one_sided_incorrect += 1
            return False
          tcls.remove(d_out)
        tcls = [g_temp] + tcls
        delete_list.append(tcls)
      else:proof_list.append((1,old_cls))

    # STEP 4: DELETE BiEquivalence
    if bic:
      bicond2 = [-d_out, new_var] # change order fo QRAT check
      bicond1 = [d_out, -new_var]
      proof_list.append((1,bicond1))
      proof_list.append((1,bicond2))

    # STEP 5: DELETE Defining clauses of x
    for clsid in d_clauses:
      cls = self.clauses[clsid]
      g_temp = d_out
      if -d_out in cls:
        g_temp = -d_out
        cls.remove(-d_out)
      else: cls.remove(d_out)
      cls = [g_temp] + cls
      proof_list.append((1,cls[:]))

    if one_sided:
      for d in delete_list:
        proof_list.append((1,d))
      proof_list.append((1,[bicond1[1],bicond1[0]]))

    if not self.prove_no_write:
      for d,c in proof_list: self.write_clause(self.proof,c,d==1)

    # UPDATE CLAUSE DICTIONARY
    for (clsid,new_cls) in clause_updates:
      self.clauses[clsid] = new_cls

    self.variable_clauses[new_var] = self.variable_clauses[d_out]
    self.quantifiers[old_level][1].remove(d_out)
    self.quantifiers[max_level][1].append(new_var)
    self.variable_qlevel[new_var] = max_level
    self.var_map[d_out] = new_var
    self.var_map.append(new_var)
    self.reverse_var_map.append(d_out)

    if one_sided: self.one_sided_moves += 1

    return True

  #####################################################################################
  # DEFINING VARIABLE ELIMINATION
  #####################################################################################

  # Definition is not Eq, AND, OR
  # Need auxillary clauses to prove biconditional between old definition variable
  #  and new definition variable
  #
  # Use basic variable elimination technique for Q-resolution proof, eliminating
  #   inputs until only the two definition outputs are left
  def biconditional_aux_resolvents(self, d_out, new_var, old_d_clauses, new_d_clauses, d_inputs):
    pos_old_g = [cls for cls in old_d_clauses if d_out in cls]
    neg_new_g = [cls for cls in new_d_clauses if -new_var in cls]
    clauses = pos_old_g + neg_new_g
    nclauses = len(clauses)
    orig_clauses = nclauses
    active_caluses = [1] * nclauses
    variable_clauses = {}
    for idx in d_inputs + [d_out, new_var]: variable_clauses[idx] = [[],[]]
    for clsidx in range(len(clauses)):
      for l in clauses[clsidx]:
        variable_clauses[abs(l)][int(l>0)].append(clsidx)
    bps = [0] * orig_clauses
    aux_clauses = []
    found = False
    res_cnt = 0
    step_first = True
    # eliminate inputs one at a time with var. elim. by distribution
    for g_in in d_inputs:
#      print("Eliminating %d" % (g_in))
      pos_clauses = variable_clauses[g_in][1]
      ned_clauses = variable_clauses[g_in][0]
#      print(pos_clauses)
#      print(ned_clauses)
      for p_clause in pos_clauses:
        if not active_caluses[p_clause]: continue
        p_lits = clauses[p_clause]
        for n_clause in ned_clauses:
          if not active_caluses[n_clause]: continue
          n_lits = clauses[n_clause]
#          print("RESOLVING")
#          print(p_lits)
#          print(n_lits)
          resolventT = p_lits + n_lits
          resolventT.remove(g_in)
          resolventT.remove(-g_in)
          if step_first: # only consider resolvents containing both -new_var and d_out
            if not d_out in resolventT or not -new_var in resolventT:
              continue
          resolvent = []
          taut = False
          for r in resolventT:
            if r not in resolvent: resolvent.append(r)
            if -r in resolvent:
              taut = True
              break
          if not taut:
            for l in resolvent:
              variable_clauses[abs(l)][int(l>0)].append(nclauses)
#            print(resolvent)
            clauses.append(resolvent)
            aux_clauses.append(resolvent)
            active_caluses.append(1)
            bps.append([p_clause,n_clause])
            nclauses += 1
            if resolvent == [d_out, -new_var]:
              found = True
              break
        if found: break
      for clsid in pos_clauses + ned_clauses:
        active_caluses[clsid] = 0
      if found: break
      step_first = False

    # get derivation chain
    if len(aux_clauses) < 1 or aux_clauses[-1] != [-new_var, d_out] and aux_clauses[-1] != [d_out,-new_var] : # Failed
      return aux_clauses

    derivation_chain = [aux_clauses[-1]]
    front = bps[-1]
    seen = [0] * nclauses
    while front:
      clsid = front.pop(0)
      if clsid < orig_clauses: continue
      if seen[clsid] == 1: continue
      derivation_chain.append(clauses[clsid])
      front += bps[clsid]
      seen[clsid] = 1

    derivation_chain.reverse()

    return derivation_chain

  #######################################################################################
  # WRITING AND MISCL. FUNCTIONS
  #######################################################################################

  def write_qbf(self, fname):
    file = open(fname, 'w')
    file.write("p cnf %d %d\n" % (self.nvar, self.ncls))
    for (qt, ql) in self.quantifiers:
      self.print_verb(ql,1)
      if ql == []: continue
      ilist = ql + [0]
      slist = [str(i) for i in ilist]
      slist = [qt] + slist
      istring = " ".join(slist)
      file.write(istring + '\n')
    for lits in self.clauses:
      ilist = lits + [0]
      slist = [str(i) for i in ilist]
      istring = " ".join(slist)
      file.write(istring + '\n')

  # -- Definition output --
  # Written in order from inputs to outputs
  # for each definition,
  # DefinitionInputs:
  # DefinitionInputTseitens:
  # DefinitionOutput:
  def write_definitions(self, fname):
    file = open(fname, 'w')
    init_definitions = self.initial_definitions()
    seen = [0] * (self.nvar+1) # definition output seen in bfs
    support = {}
    q = Queue()
    for gidx in init_definitions: q.put(gidx)
    # BFS across definitions, following input to output ordering
    while not q.empty():
      gidx = q.get()
      g = self.definitions[gidx]
      d_outlit = g.outlit
      d_out = abs(d_outlit)
      d_inputs = g.inputs
      variables = d_inputs + [d_out]
      if seen[d_out]: continue
      # check other inputs
      if any([not seen[v] for v in d_inputs if self.is_definition_out[v]]):
        continue # other input definitions need to be processed (seen) first
      seen[d_out] = 1 # definition has been processed
      # add new definitions where d_out is input
      if d_out in self.variable_g_in:
        for ng in self.variable_g_in[d_out]: q.put(ng)
      # Move in qnf
      self.write_definition(gidx, file)

  def write_definition(self,gidx,file):
    g = self.definitions[gidx]
    d_outlit = g.outlit
    d_out = abs(d_outlit)
    d_inputs = g.inputs
    ilist = d_inputs
    slist = [str(i) for i in ilist]
    istring = " ".join(slist)
    file.write("DefinitionInputs: " + istring + "\n")
    tseitens = [v for v in d_inputs if self.is_definition_out[v]]
    ilist = tseitens
    slist = [str(i) for i in ilist]
    istring = " ".join(slist)
    file.write("DefinitionInputTseitens: "+ istring + "\n")
    file.write("DefinitionOutput: %d\n\n" % (d_outlit))

  def write_comment(self, file, comment):
    file.write("c "+comment+"\n")

  def write_clause(self, file, clause, delete = False):
    ilist = clause + [0]
    slist = [str(i) for i in ilist]
    if delete : slist = ['d'] + slist
    istring = " ".join(slist)
    file.write(istring + '\n')
  def print_stats(self):
    if self.tool == "cnf-mv":
      header = ["Tool", "Not LU Existential", "Not LU Universal", "Not One-Sided", "One-Sided Moved"]
      line ='%-10s %-20s %-20s %-20s %-20s' % (header[0],header[1],header[2],header[3], header[4])
      print("-")
      print(line)
    line ='%-10s %-20s %-20s %-20s %-20s' % (self.tool , self.definitions_out_of_order,self.definitions_on_universal,self.definitions_one_sided_incorrect+self.definitions_notdefined, self.one_sided_moves)
    print(line)

#    print("Statistics")
#    print("Number of definitions: "+str(self.ndefinitions))
#    print("Number of XORs and Semantic and Monotonic: "+str(self.nxor_definitions))
#    print("Number of definitions moved: "+str(self.ndefinitions_moved))
#    print("Number of definitions incorrect out of order: "+str(self.definitions_out_of_order))
#    print("Number of definitions incorrect on universal: "+str(self.definitions_on_universal))
#    print("Number of definitions incorrect not defined: "+str(self.definitions_notdefined))
#    print("Number of definitions incorrect one-sided: "+str(self.definitions_one_sided_incorrect))
#    if self.ndefinitions_moved > 0:
#      print("Total difference in levels for moved variables: "+str(self.total_nlevels_moved))
#      print("Average difference in levels for moved variables: "+str(self.total_nlevels_moved/self.ndefinitions_moved))
#      print("One-sided moves: "+str(self.one_sided_moves))

  def print_verb(self, st, verb):
    if verb <= self.verbosity:
      print(st)

  def print_var_map(self, fname):
    file = open(fname, 'w')
    for i in range(1,self.nvar_orig+1):
      if self.var_moved[i] == 1: file.write(str(i) +" "+str(self.var_map[i])+" " +str(self.actual_move_type[i]) +"\n")

#######################################################################################
# MAIN FUNCTION
#######################################################################################

def run(name, args):
    qbfName = None
    definitionName = None
    outqbfName = None
    outdefinitionName = None
    proofName = None
    prove_no_write = False
    move_definitions = False
    restrictDefinitions = False
    verbosity = 0
    var_map_name = None
    pseudo = False
    tool = None

    optlist, args = getopt.getopt(args, "swhdrmv:q:o:g:l:p:b:t:")
    for (opt, val) in optlist:
        if opt == '-h':
          usage(name)
          return
        elif opt == '-q':
          qbfName = val
        elif opt == '-g':
          definitionName = val
        elif opt == '-o':
          outqbfName = val
        elif opt == '-b':
          var_map_name = val
        elif opt == '-l':
          outdefinitionName = val
        elif opt == '-p':
          proofName = val
        elif opt == '-m':
          move_definitions = True
        elif opt == '-v':
          verbosity = int(val)
        elif opt == '-w':
          prove_no_write = True
        elif opt == '-r':
          restrictDefinitions = True
        elif opt == '-s':
          pseudo = True
        elif opt == '-t':
          tool = val

    qbf = QBF_Definition_Processor(qbfName, proofName, verbosity, prove_no_write,restrictDefinitions, pseudo, tool)

    qbf.read_definitions(definitionName)

    if move_definitions:
      qbf.move_by_level()

    if not outqbfName is None:
      qbf.write_qbf(outqbfName)

    if not outdefinitionName is None:
      qbf.write_definitions(outdefinitionName)

    if not var_map_name is None:
      qbf.print_var_map(var_map_name)

    qbf.print_stats()

if __name__ == "__main__":
    run(sys.argv[0], sys.argv[1:])


from helpers.http_wrapper import https_get
from helpers.payload import Payload
import json
import time
import logging

URL_TEMPLATE = "https://graph.microsoft.com/v1.0/me/drive/root:{0}:/children"

RETRY_WAIT = 5 #In case of potentially recoverable error the time lapse between tries

## This will list all the files
def listfiles(path, headers):
    logging.debug("listfiles(): Starting list files operation...")

    uri = URL_TEMPLATE.format(path)

    logging.debug("listfiles(): Listing Remote Path: %s",path)

    page_number = 0
    retry_count=0

    item_list = list()

    ## Loop until there are further pages
    while(True):

        response = https_get(uri, headers=headers)

        # Used to simulate very rare error
        #if(page_number == 1 and retry_count == 0):
        #    response = Payload(503, "Simulation Error","")

        logging.debug("listfiles(): Status: {} and reason: {}".format(response.get_status_code(), response.get_status_message()))

        ## Sucessfull response - Lets process it
        if(response.get_status_code() == 200):
            retry_count=0
            page_number = page_number + 1

            data_parsed = json.loads(response.get_payload())

            logging.debug("listfiles() - Page Number: %s", page_number)
            number_items = data_parsed["@odata.count"]
            logging.debug("listfiles() - Total Items: %s", number_items)

            next_link = None

            if('@odata.nextLink' in data_parsed.keys()):
                next_link = data_parsed["@odata.nextLink"]
                logging.debug("listfiles() - THERE ARE ADDITIONAL PAGES. Next link: %s", next_link)

            else:
                logging.debug("listfiles() - no further pages")
                next_link = None

            ## Mapping just the relevant fields
            for item in data_parsed["value"]:
                created_date_time = item["createdDateTime"]
                last_modified_datetime = item["lastModifiedDateTime"]
                ctag = item["cTag"]
                etag = item["eTag"]
                item_id = item["id"]
                name = item["name"]
                item_type = ""  # folder/file
                size = 0 #only return size for files

                #Determine item type for the listing
                if("folder" in item):
                    item_type = "folder"

                if("file" in item):
                    item_type = "file"
                    size = item["size"]

                item_data= { "type": item_type,
                            "id": item_id,
                            "name": name,
                            "size": size,
                            "ctag": ctag,
                            "etag": etag,
                            "created": created_date_time,
                            "lastmodified": last_modified_datetime
                }
                item_list.append(item_data)

            logging.debug("listfiles(): Page completed: %s", page_number)

            #Check if we exit the paging when it ends or not
            if(next_link == None):
                logging.debug("listfiles(): Total number of items returned: %s", len(item_list))
                return { "status":True,
                        "message":"Success",
                        "itemlist":item_list
                }
            else:
                uri = next_link #Prepare the URL for the next page

        # Status: 503 and reason: Service Unavailable
        # This is a recoverable error.
        elif(response.get_status_code() == 503):
            retry_count = retry_count + 1
            time.sleep(RETRY_WAIT) #Sleep 5 seconds before retry
            logging.warn("listfiles(): 503 Error - Sleeping 5 seconds and retrying")

        ## The specified path does not exist
        elif(response.get_status_code() == 404):
            return {
                    "status": False,
                    "message":"Path not found."
                }

        elif(response.get_status_code() == 401):
            return {
                    "status": False,
                    "message":"Unauthorized."
                }

        # There were exceptions on the http which exceeded the interval between retried and we had to abort.
        elif(response.get_status_code() == 0):
            return {
                    "status": False,
                    "message":response.get_status_message()
                }
        else:
            return {
                    "status": False,
                    "message": response.get_status_message()
                }

        if(retry_count > 3):
            return {
                    "status": False,
                    "message":"Failure after number of retries exceeded"
                }


from data.dataset.utility import Indexer
from data.dataset.abstract_dataset import AbstractDataset

class MultilexnormDataset(AbstractDataset):
    def __init__(self, args, inputs, outputs):
        super().__init__(args, inputs, outputs)
        self.inputs = inputs
        self.outputs = outputs

        valid_indices = [[i for i, word in enumerate(sentence) if self.filter(word)] for sentence in inputs]
        self.indexer = Indexer(valid_indices)

    def __getitem__(self, index):
        sentence_index, word_index = self.indexer.get_indices(index)

        out = self.outputs[sentence_index][word_index]
        raw = self.inputs[sentence_index]

        raw = raw[:word_index] + ["<extra_id_0>", raw[word_index], "<extra_id_1>"] + raw[word_index+1:]
        raw = ' '.join(raw)

        return raw, out, sentence_index, word_index

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


"""
Author: angles
Date and time: 23/07/16 - 17:25
"""
import tensorflow as tf
import numpy as np

def make_grid(weights):
    # The number of input channels has to be 1 or 3 (grayscale or RGB)
    # Notice that it shows all the filters only if the nb_filters is a perfect square
    nb_filters = weights.get_shape().dims[3]
    filters = tf.split(3, nb_filters, weights)
    for index in range(nb_filters):
        filters[index] = tf.pad(filters[index], [[1, 1], [1, 1], [0, 0], [0, 0]])
    side = int(np.sqrt(nb_filters.value))
    grid_rows = []
    for idx_row in range(side):
        grid_rows.append(tf.concat(0, filters[side * idx_row:side * (idx_row + 1)]))
    grid_transposed = tf.concat(1, grid_rows)
    grid = tf.transpose(grid_transposed, [3, 0, 1, 2])
    return grid

"""
# For testing with debugger:
weights_shape = [3, 3, 3, 64]
msr_init_std = np.sqrt(2 / (5 * 5 * 16))
# Microsoft Research weights initialization when using the ReLU as non-linearity
weights_init = tf.random_normal(weights_shape, mean=0, stddev=msr_init_std)
weights = tf.get_variable('weights', initializer=weights_init)
grid = make_grid(weights)
"""


"""empty message

Revision ID: 757b49c77662
Revises: 6af3389a2870
Create Date: 2018-12-03 11:40:36.775188

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = '757b49c77662'
down_revision = '6af3389a2870'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_index(op.f('ix_business_id'), 'business', ['id'], unique=False)
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_index(op.f('ix_business_id'), table_name='business')
    # ### end Alembic commands ###


#  Desenvolva uma função que recebe a idade de uma pessoa e informe se essa pessoa é:
# 		1. Eleitor obrigatório (18 anos completos e menos de 70 anos de idade)
# 		2. Eleitor facultativo (16 anos completos e menos de 18 anos ou 70 anos de idade
#       ou mais).
# 		3. Não tem direito a voto (menor de 16 anos).
#
# Fluxo de exceção:
#
# O programa deve verificar se a idade da pessoa é maior do que zero.

def ler_entrada():
    try:
        return int(input("Informe a idade: "))
    except ValueError as err:
        raise ValueError({"error": "Idade invalida", "msg": err.args[0]})

def validar_entrada(idade):
    if idade < 0:
        raise ValueError({"error": "Idade inválida", "msg": "A idade deve ser igual ou maior que zero"})
    return

def verificar_idade(idade):
    if idade < 16:
        return "Não tem direito a voto."
    elif idade < 18 or idade >= 70:
        return "Eleitor facultativo."
    else:
        return "Eleitor obrigatório."

def impressao(idade):
    resultado = verificar_idade(idade)
    print(resultado)

try:
    idade = ler_entrada()
    validar_entrada(idade)
    impressao(idade)

except ValueError as err:
    print(err)


#!/usr/bin/python3
def divisible_by_2(my_list=[]):
    if my_list is None:
        return
    n_list = []
    for m in my_list:
        if m % 2 == 0:
            n_list.append(True)
        else:
            n_list.append(False)
    return (n_list)


import numpy as np
import tensorflow as tf
import random
import time
from sklearn.metrics import confusion_matrix

from models.CNNModels import Net
from utils import log, extract_minibatch
from config.config import DEFAULT_LOG_ENV, NB_OF_EPOCHS_FOR_BAYESIAN

def train_model(X, Y, valX, valY,
                net: Net,
                model_ckpt_path,
                batch_size=128,
                epochs=50,
                save_step=10,
                display_step=1,
                restore=False,
                model_ckpt_path_to_restore=None,
                cost_sensitive_loss=False,
                cost_matrix=np.array([[0, 1.1, 1.3], [1.1, 0, 1.1], [1.3, 1.1, 0]]),
                is_bayesian=False,
                **kwargs):
    """
    :param X: samples, encoded images
    :param Y: one-hot-encoded labels
    :param valX: same as above used for validation
    :param valY: same as above used for validation
    :param net: Net object
    :param model_ckpt_path: path to save the checkpoints
    :param batch_size: size of one batch
    :param epochs: number of total epochs to train
    :param save_step: model will be saved every save_step epochs, set to 0 to save only at the end, set to -1 to never save
    :param display_step: display lags every display_step epochs
    :param restore: set to True to restore a previous model
    :param model_ckpt_path_to_restore:  path to use to restore a model checkpoint
    :param cost_sensitive_loss: boolean, will implement cost sensitive cross entropy loss function if true.
     See Kukar and Kononenko (1998) for details.
    :param cost_matrix: a matrix of size output_dimension by output_dimension, default to be identity. (i,j)-th element is a
                         penalty factor assigned for misclassifying i to j. It used to combine sample prior
                         (distribution of classes in the training sample) to compute expected penalty of misclassifying i-th class.
                         See Kukar and Kononenko (1998) for details
    :param is_bayesian: boolean, if true, will ensemble the result from the last NB_OF_EPOCHS_FOR_BAYESIAN epochs of training
    :return:
            1. prediction of validation data based on current model
            2. Training loss of current model
            3. validation loss of current model
    """

    # Get sample distribution to calculate expected penalty
    sample_size, _, image_size, channel_size = X.shape

    # number of batches
    nb_of_batches_training = max(int(sample_size / batch_size), 1)

    # calculate expected penalty if we consider a cost sensitive  loss
    if cost_sensitive_loss:
        sample_prior = Y.sum(axis=0) / len(Y)
        expected_penalty = np.dot(cost_matrix, sample_prior) / (1 - sample_prior)
    else:
        expected_penalty = None
    kwargs.update({'expected_penalty': expected_penalty})

    if restore:
        tf.reset_default_graph()
        sess = tf.Session()
        graph = tf.get_default_graph()
        net.restore_importants_ops(sess, model_ckpt_path_to_restore)
        return _run_epochs(restore, sess, net, X, Y, valX, valY, sample_size, epochs, nb_of_batches_training,
                           batch_size, display_step, save_step, model_ckpt_path, is_bayesian)

    else:
        with tf.Graph().as_default():
            with tf.variable_scope(net.name, reuse=None):
                net.build_operations(**kwargs)
                with tf.Session() as sess:
                    sess.run(net.init)
                    return _run_epochs(restore, sess, net, X, Y, valX, valY, sample_size, epochs,
                                       nb_of_batches_training, batch_size, display_step, save_step, model_ckpt_path,
                                       is_bayesian)

def _run_epochs(restore, sess, net, X, Y, valX, valY, sample_size, epochs,
                nb_of_batches_training, batch_size, display_step,
                save_step, model_ckpt_path, is_bayesian):
    """
    Runs the training, See train_model docstring for details
    """
    writer = tf.summary.FileWriter('logs', sess.graph)

    dropout = net.get_dropout()

    training_loss, val_loss, pred = [], [], []
    for e in range(epochs):
        # Display the epoch beginning
        if (e + 1) % display_step == 0:
            text_to_print = '\n***************** Epoch: {:03d}/{:03d} *****************'.format(e + 1,
                                                                                epochs)
            log(text_to_print, DEFAULT_LOG_ENV)

        epoch_start_time = time.time()

        # Shuffle dataset before doing an epoch of training # todo see if we delete it
        Z = list(zip(X, Y))
        random.shuffle(Z)
        X, Y = zip(*Z)

        cc, aa = 0, 0
        for b in range(nb_of_batches_training):
            x_b, y_b = extract_minibatch(X, Y, batch_size=batch_size, current_batch=b)
            _, __, c, a = sess.run([net.optimizer, net.global_step, net.loss, net.accuracy],
                                   feed_dict={net.x: x_b, net.y: y_b, net.phase_train: True, net.dropout: dropout})
            # Make evaluation on a batch basis
            cc += (c * len(y_b))  # len(y_b) since the last batch can be of size smaller than batch size
            aa += (a * len(y_b))
            if (b + 1) % max(int(0.1 * nb_of_batches_training), 1) == 0:
                log('Batch {}/{} done ***  CumLoss'
                    ': {:.4f} CumAccuracy: {:.4f}'.format(b + 1, nb_of_batches_training,
                                                          cc / (batch_size * (b + 1)),
                                                          aa / (batch_size * (b + 1))), DEFAULT_LOG_ENV)

        epoch_loss, epoch_acc = cc / float(sample_size), aa / float(sample_size)
        training_loss.append(epoch_loss)

        # run validation in batches to avoid memory problems
        size_1_image = np.prod(valX[0].shape)
        limit_size = (10 * batch_size) * 42 * 42 * 5
        size_batch = int(limit_size / size_1_image) + 1
        output_val, epoch_val_loss = np.zeros((0, 3)), 0.
        nb_batches = round(len(X) / size_batch)
        log('To avoid killing the kernel, we run predictions in {} batches'.format(nb_batches),
            environment=DEFAULT_LOG_ENV)
        for batch in range(0, len(X), size_batch):
            X_batch, Y_batch = valX[batch:batch + size_batch], valY[batch:batch + size_batch]
            if X_batch.shape[0] == 0:
                break
            pred_batch, epoch_val_loss_batch = sess.run([net.output, net.loss],
                                                        feed_dict={net.x: X_batch, net.y: Y_batch,
                                                                   net.phase_train: False, net.dropout: 0.})
            output_val = np.concatenate([output_val, pred_batch])
            epoch_val_loss += epoch_val_loss_batch
        epoch_val_loss /= nb_batches

        conf_matrix = get_confusion_matrix(valY, output_val)
        rows_conf_matrix = ['{}\n'.format(row_i) for row_i in conf_matrix]
        log('Confusion Matrix : \n ' + ''.join(rows_conf_matrix), environment=DEFAULT_LOG_ENV)
        pred.append(output_val)
        val_loss.append(epoch_val_loss)
        epoch_val_acc = np.trace(conf_matrix) / np.sum(conf_matrix)

        # Displaying training info for the epoch
        if (e + 1) % display_step == 0:
            text_to_print = "Training time: {}  ======== Loss: {:.4f} Accuracy: {:.4f} val_acc: {:.4f} ".format(
                round(time.time() - epoch_start_time, 2), epoch_loss, epoch_acc, epoch_val_acc)
            log(text_to_print, DEFAULT_LOG_ENV)

        # Saving the model
        if save_step >= 1 and (e + 1) % save_step == 0:
            net.save(sess, model_ckpt_path, verbose=True, epoch=e + 1, write_meta_graph=(not restore))

        # Adding values to summary
        summary_str = sess.run(net.summary_op,
                               feed_dict={net.x: x_b, net.y: y_b, net.phase_train: True, net.dropout: dropout})
        writer.add_summary(summary_str, sess.run(net.global_step))
    if save_step >= 0:
        net.save(sess, model_ckpt_path, verbose=True, epoch=epochs, write_meta_graph=True)

    writer.close()

    if is_bayesian:
        # Sample from the last NB_OF_EPOCHS_FOR_BAYESIAN epochs to form Bayesian learning:
        return (np.mean(pred[-NB_OF_EPOCHS_FOR_BAYESIAN:], axis=0), training_loss, val_loss)
    else:
        return (pred[-1], training_loss, val_loss)

def get_confusion_matrix(ytrue, ypred):
    """
    Create confusion matrix based on true results ytrue and predicted result ypred
    """
    ytrue = np.argmax(ytrue, axis=1)
    ypred = np.argmax(ypred, axis=1)
    return confusion_matrix(ytrue, ypred)


import argparse

parser = argparse.ArgumentParser()

parser.add_argument('--input_pdb', metavar='PATH', default=None,
                    help='initialize first 2 GNN layers with pretrained weights')
parser.add_argument('--output_pt', metavar='PATH', default=None,
                    help='evaluate a trained model')
args = parser.parse_args()

from pyrosetta import *

import numpy as np

np.set_printoptions(threshold=np.inf)
init_cmd = list()
init_cmd.append("-multithreading:interaction_graph_threads 1 -multithreading:total_threads 1")
init_cmd.append("-hb_cen_soft")
init_cmd.append("-detect_disulf -detect_disulf_tolerance 2.0")
init_cmd.append("-relax:dualspace true -relax::minimize_bond_angles -default_max_cycles 200")
init_cmd.append("-mute all")
init_cmd.append("-constant_seed")
init_cmd.append("-read_only_ATOM_entries")
init(" ".join(init_cmd))

def extractSS(pose):
    dssp = rosetta.core.scoring.dssp.Dssp(pose)
    dssp.insert_ss_into_pose(pose)
    fp = open(args.output_pt, 'w')
    for ires in range(1, pose.size()+1):
        SS = pose.secstruct(ires)
        print(str(ires)+'\t'+SS, file=fp)

def main():
    init_pose=pose_from_pdb(args.input_pdb)
    extractSS(init_pose)

if __name__== "__main__":
    main()


import tabulator
import json
import re
from pathlib import Path

fp = re.compile('\w+', re.UNICODE)

def fingerprint(x):
    return ''.join(fp.findall(x.upper()))

if __name__ == '__main__':
    # How to get places.csv from a nominatim server?
    # # kubectl exec -it nominatim-5d6889fd59-lxps7 -- su nominatim -c "psql -c \"\\copy (select hstore_to_json(name) from place where type in ('village', 'town', 'city', 'locality')) to stdout with csv\"" > places.csv
    # How to get official list of towns?
    # # https://data.gov.il/dataset/citiesandsettelments
    langs = {}
    s = tabulator.Stream('tools/yeshuvim.csv', headers=1)
    s.open()
    for item in s.iter(keyed=True):
        langs.setdefault('he', []).append(item['שם_ישוב'].strip().replace('(', 'XXX').replace(')', '(').replace('XXX', ')').replace('  ', ' '))
        langs.setdefault('en', []).append(item['שם_ישוב_לועזי'].strip().title().replace('  ', ' '))

    s = tabulator.Stream('tools/places.csv')
    s.open()
    for item in s.iter():
        if len(item) == 0: continue
        item = json.loads(item[0])
        for k, v in item.items():
            if k.startswith('name'):
                langs.setdefault(k[5:], []).append(v.strip(', '))

    combinations = {
        'he': ('he', ''),
        'ar': ('ar', 'he', ''),
        'en': ('en', 'he', ''),
        'es': ('es', 'en', ''),
        'fr': ('fr', 'en', ''),
        'ru': ('ru', 'en', ''),
    }
    suggestions = {}
    for k, v in combinations.items():
        print('COMBINATION', k)
        s = []
        for lang in v:
            for w in langs[lang]:
                if w:
                    fw = fingerprint(w)
                    found = False
                    for ww in s:
                        if ww == w:
                            found = True
                            break
                        if fingerprint(ww) == fw:
                            found = True
                            print('Matched %s based on fingerprint (kept %s)' % (w, ww))
                            break
                    if not found:
                        s.append(w)
        suggestions[k] = s

    for k, v in suggestions.items():
        print(k, len(v), v[:10])

    f_out = Path('src/app/city-suggestions.ts')
    f_out.open('w').write('''
/* tslint:disable */
export const citySuggestions = {};
'''.format(json.dumps(
        suggestions, ensure_ascii=False, sort_keys=True, indent=2)
        )
    )


import subprocess

def get_disk_list():
    """Return a list of available disk drives in Windows."""
    output = subprocess.check_output("wmic logicaldisk get name", shell=True).decode("utf-8")
    disk_list = output.split("\n")[1:-1]
    return disk_list

def create_partition(disk, size, file_system):
    """Create a new partition on the specified disk with the specified size and file system."""
    command = f"diskpart /s script.txt"
    with open("script.txt", "w") as script:
        script.write(f"select disk {disk}\n")
        script.write(f"create partition primary size={size}\n")
        script.write(f"format fs={file_system} quick\n")
    subprocess.call(command, shell=True)

def delete_partition(disk, partition):
    """Delete the specified partition on the specified disk."""
    command = f"diskpart /s script.txt"
    with open("script.txt", "w") as script:
        script.write(f"select disk {disk}\n")
        script.write(f"select partition {partition}\n")
        script.write("delete partition\n")
    subprocess.call(command, shell=True)

def main():
    """Main function to interact with the user and perform partition operations."""
    print("Welcome to the Partition Manager")
    print("Available disk drives:", get_disk_list())
    disk = input("Enter the disk drive to use (e.g. C):")
    while True:
        print("1. Create Partition")
        print("2. Delete Partition")
        print("3. Quit")
        choice = input("Enter your choice:")
        if choice == "1":
            size = input("Enter the size of the partition (e.g. 100MB):")
            file_system = input("Enter the file system to use (e.g. NTFS):")
            create_partition(disk, size, file_system)
        elif choice == "2":
            partition = input("Enter the partition to delete (e.g. 1):")
            delete_partition(disk, partition)
        elif choice == "3":
            break
        else:
            print("Invalid choice, try again.")

if __name__ == "__main__":
    main()


"""Upload img in Blog

Revision ID: c2c7704dbc13
Revises: d1add5e3e65e
Create Date: 2017-06-27 10:41:26.856029

"""

# revision identifiers, used by Alembic.
revision = 'c2c7704dbc13'
down_revision = 'd1add5e3e65e'

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import JSON

field = 'media_url'

def upgrade():
    op.add_column('blogpost', sa.Column(field, sa.String))
    op.add_column('blogpost', sa.Column('info', JSON))

def downgrade():
    op.drop_column('blogpost', field)
    op.drop_column('blogpost', 'info')


from . import Operation

DB_NAME = "contactbook.txt"
TEMPLATE = {
    "id":"XXXX",
    "name":255*" ",
    "number":255*" ",
    "address":255*" ",
    "email":255*" "
}

def init_console():
    try:
        with open(DB_NAME, "r") as file:
            print("Database available, init done.")
    except:
        print("Database not found, please create a new database")
        Operation.create_first_data()


import sys
import paho.mqtt.client as mqtt
import time
import threading
from Crypto.Cipher import AES
import base64

# https://www.itread01.com/content/1547711886.html
class prpcrypt():
    def __init__(self, key):
        self.key = key
        self.mode = AES.MODE_CBC

    def encrypt(self, text):
        iv = '0102030405060708'
        pad = lambda s: s + (16 - len(s)%16) * chr(16 - len(s)%16)
        text = pad(text)

        cipher = AES.new(self.key.encode('utf8'), self.mode, iv.encode('utf8'))
        encryptedbytes = cipher.encrypt(text.encode('utf8'))

        encodestrs = base64.b64encode(encryptedbytes)
        enctext = encodestrs.decode('utf8')
        return enctext

    def decrypt(self, text):
        iv = '0102030405060708'
        text = text.encode('utf8')
        encodebytes = base64.decodebytes(text)

        cipher = AES.new(self.key.encode('utf8'), self.mode, iv.encode('utf8'))
        text_decrypted = cipher.decrypt(encodebytes)
        unpad = lambda s: s[0:-s[-1]]
        text_decrypted = unpad(text_decrypted)
        text_decrypted = text_decrypted.decode('utf8')
        return text_decrypted

def main():
    MQTTTopicServerIP = "192.168.137.219"
    MQTTTopicServerPort = 1883
    MQTTTopicName = "wsn_lab/test"
    pc = prpcrypt(key = '0000000107062533')

    Message = input('>>')

    EncryptMessage = pc.encrypt(str(Message))
    # d = pc.decrypt(EncryptMessage)

    mqttc = mqtt.Client("python_pub")
    mqttc.connect(MQTTTopicServerIP, MQTTTopicServerPort)
    print(EncryptMessage)
    mqttc.publish(MQTTTopicName, EncryptMessage)

if __name__ == '__main__': main()


import platform
from configparser import ConfigParser
import os
from os.path import dirname, abspath

# Settings
parser = ConfigParser()
fileConfig = os.path.join(dirname(abspath(__file__)), "settings.ini")
parser.read(fileConfig)

ffmpegConf = parser["GENERAL"]["ffmpeg"]
DemConf = parser["GENERAL"]["DTM_file"]
min_buffer_size = int(parser["GENERAL"]["min_buffer_size"])

Platform_lyr = parser["LAYERS"]["Platform_lyr"]
Beams_lyr = parser["LAYERS"]["Beams_lyr"]
Footprint_lyr = parser["LAYERS"]["Footprint_lyr"]
FrameCenter_lyr = parser["LAYERS"]["FrameCenter_lyr"]
FrameAxis_lyr = parser["LAYERS"]["FrameAxis_lyr"]
Point_lyr = parser["LAYERS"]["Point_lyr"]
Line_lyr = parser["LAYERS"]["Line_lyr"]
Polygon_lyr = parser["LAYERS"]["Polygon_lyr"]
frames_g = parser["LAYERS"]["frames_g"]
Trajectory_lyr = parser["LAYERS"]["Trajectory_lyr"]
epsg = parser["LAYERS"]["epsg"]
Reverse_geocoding_url = parser["GENERAL"]["Reverse_geocoding_url"]
dtm_buffer = int(parser["GENERAL"]["DTM_buffer_size"])

# Geo variables
EARTH_MEAN_RADIUS = 6371008.8
WGS84String = "WGS84"
encoding = "utf-8"
defaultTargetWidth = 200.0

# Klv variables
UASLocalMetadataSet = b"\x06\x0e+4\x02\x0b\x01\x01\x0e\x01\x03\x01\x01\x00\x00\x00"
KlvHeaderKeyOther = b"\x06\x0e+4\x02\x01\x01\x01\x0e\x01\x01\x02\x01\x01\x00\x00"

# OS variables
isWindows = platform.system() == "Windows"

if isWindows:
    ffmpeg_path = os.path.join(ffmpegConf, "ffmpeg.exe")
    ffprobe_path = os.path.join(ffmpegConf, "ffprobe.exe")
else:
    ffmpeg_path = os.path.join(ffmpegConf, "ffmpeg")
    ffprobe_path = os.path.join(ffmpegConf, "ffprobe")


import os
import sys
import time

from Modules import colorama

colorama.init()

class Log(object):
    class LogError(Exception):
        pass

    # Logging "labels" - first indice is the debug level, second is the console colour
    labels = {
        # Top levels
        "INFO": (0, -1, "CYAN"),
        "WARNING": (0, -1, "YELLOW"),
        "ERROR": (0, -1, "RED"),

        # Basic logging
        "CONNECT": (1, -1, "GREEN"),
        "DISCONNECT": (1, -1, "RED"),
        "LOOKUP": (1, -1, "MAGENTA"),
        "AUTHORISED": (1, -1, "GREEN"),

        # Connection/channel logging
        "JOIN": (2, 4, "RED"),
        "PART": (2, 4, "RED"),

        # Stalker logging
        "PRIVMSG": (3, 4, "RED"),
        "MODE": (3, 4, "RED"),
        "NOTICE": (3, 4, "RED"),

        # Annoyingly verbose
        "COMMAND": (4, 4, "RED"),
        "PONG": (4, 4, "MAGENTA"),

        # Insanely verbose
        "RAW": (5, -1, "WHITE")
    }

    def __init__(self, directory, debug):
        # Reset properties
        self._handle = None
        self._directory = directory
        self._name = directory + time.strftime("%Y-%m-%d %H-%M-%S") + ".txt"
        self.debug = debug

        # Open log file
        self.open()

    def __del__(self):
        try:
            self._handle.close()
        except AttributeError:
            pass

    def open(self):
        if not os.access(self._directory, os.W_OK):
            raise Log.LogError("Directory '{0}' is not writable".format(self._directory))

        try:
            self._handle = open(self._name, "wb", 0)
        except IOError as error:
            raise Log.LogError("File '{0}' could not be opened for writing ({1})".format(self._name, error))

    def write(self, buffer):
        return self._handle.write(buffer.encode("utf-8"))

    def custom(self, label, text):
        output = False

        if label in self.labels:
            if self.labels[label][0] <= self.debug:
                if self.labels[label][1] == -1 or self.debug <= self.labels[label][1]:
                    output = True
        else:
            output = True

        if output:
            console_buffer = "[{0}] {1}[{2}]{3} {4}".format(
                time.strftime("%H:%M:%S"),
                getattr(colorama.Fore, self.labels[label][2]),
                label,
                colorama.Fore.RESET,
                text
            )

            # Specifically for log output; includes no colour chars
            file_buffer = "[{0}] [{1}] {2}\n".format(
                time.strftime("%H:%M:%S"),
                label,
                text
            )

            print(console_buffer)
            return self.write(file_buffer)

    def info(self, text):
        return self.custom("INFO", text)

    def warning(self, text):
        return self.custom("WARNING", text)

    def error(self, text):
        self.custom("ERROR", text)
        return sys.exit(1)


import pandas
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import time

# 1 Загрузите набор данных ex1data1.txt из текстового файла.

dataFrame = pandas.read_csv("ex1data1.txt", header=None, names=["population", "incomes"])
print(dataFrame.head())

population = dataFrame["population"].values
incomes = dataFrame["incomes"].values

# 2 Постройте график зависимости прибыли ресторана от населения города, в котором он расположен.

dataFrame.plot(kind='scatter', x='population', y='incomes', color='red')
plt.show()

# 3 Реализуйте функцию потерь J(θ) для набора данных ex1data1.txt.

def calcHypotesis(theta,  x):
    return theta[0] + theta[1] * x

def costFunction(theta, x, y):
    return sum((calcHypotesis(theta, x_i) - y_i) ** 2 for x_i, y_i in zip(x, y)) / len(x) * 2

# 4 Реализуйте функцию градиентного спуска для выбора параметров модели.
# Постройте полученную модель (функцию) совместно с графиком из пункта 2.

def derivative_theta0(theta, x, y, alpha):
    return alpha * sum(calcHypotesis(theta, x_i) - y_i for x_i, y_i in zip(x, y)) / len(x)

def derivative_theta1(theta, x, y, alpha):
    return alpha * sum((calcHypotesis(theta, x_i) - y_i) * x_i for x_i, y_i in zip(x, y)) / len(x)

def gradient_descent (X, Y, iterations = 400, alpha = 0.01 , theta = [0, 0]):
    i = 0
    history = []

    cost = costFunction(theta, X, Y)
    history.append(np.array([cost, np.array(theta)]))

    for it_number in range(iterations):
        tmptheta = theta
        tmptheta[0] = theta[0] - derivative_theta0(theta, X, Y, alpha)
        tmptheta[1] = theta[1] - derivative_theta1(theta, X, Y, alpha)

        cost = costFunction(theta, X, Y)
        history.append(np.array([cost, np.array(theta)]))

    return np.array(theta), cost, np.array(history)

theta, cost, history = gradient_descent(population, incomes, 2000, 0.01, [0, 0])

print(f'Cost: {cost}')
print(f'Theta: {theta}')

cost_history = history[:, 0]
cost_history = np.delete(cost_history, [0, 1])

plt.figure(figsize=(10, 6))
plt.plot(range(cost_history.size), cost_history, 'o-')
plt.grid(True)
plt.xlabel("Iterations")
plt.ylabel("Cost function values")
plt.show()

pred_incomes = calcHypotesis(theta, population)

plt.figure(figsize=(10,6))
plt.plot(population, incomes, '.', color='red')
plt.plot(population, pred_incomes, 'b-', color='green', label = 'Hypotesis: h(x) = %0.2f + %0.2fx'%(theta[0],theta[1]))
plt.grid(True)
plt.ylabel('Incomes')
plt.xlabel('Population')
plt.legend()
plt.show()

# 5 Постройте трехмерный график зависимости функции потерь от параметров модели (θ0 и θ1) как в виде поверхности,
# так и в виде изолиний (contour plot).

theta_ = theta.reshape(-1, 1)

x_3d = np.arange(-4.2, 1, 0.02)
y_3d = np.arange(-0.1, 1.5, 0.02)

plot_x, plot_y = np.meshgrid(x_3d, y_3d)
plot_z = np.array([costFunction(np.array([plot_x[i], plot_y[i]]), population, incomes) for i in range(len(plot_x))])

# выбираем каждый 20 элемент после 5ого
tmp_his = np.concatenate([history[0:5], history[5::20]])

graph_cost_history = np.vstack(tmp_his[:, 0]).astype(np.float).reshape(-1)

tmp = np.vstack(tmp_his[:, 1]).astype(np.float)

theha_0_history = tmp[:, 0].reshape(-1)
theha_1_history = tmp[:, 1].reshape(-1)

fig = plt.figure(figsize=(12,12))
ax = plt.axes(projection='3d')

ax.plot_surface(plot_x, plot_y, plot_z,  rstride=1, cstride=1, linewidth=0, cmap = 'jet', edgecolor='none', alpha=.9)
ax.plot(*theta_, np.array([cost]), 'r*', markersize=14, zorder = 10)
ax.plot(theha_0_history, theha_1_history, graph_cost_history, marker = '.', color = 'r', alpha = .4, zorder = 9)

ax.set_xlabel(r'$\theta_0$', fontsize=18)
ax.set_ylabel(r'$\theta_1$', fontsize=18)
ax.set_zlabel('Cost func', fontsize=18)
ax.view_init(25, 65)

x_3d = np.arange(-4.2, 1, 0.02)
y_3d = np.arange(-0.1, 1.5, 0.02)

plot_x, plot_y = np.meshgrid(x_3d, y_3d)

plot_z = np.array(list(costFunction(np.array([plot_x[i], plot_y[i]]), population, incomes) for i in range(len(plot_x))))
plt.show()

fig = plt.figure(figsize=(10,6))
ax = plt.axes()
cnt = ax.contour(plot_x, plot_y, plot_z, 100, cmap='jet')

#Angles needed for quiver plot
anglesx = theha_0_history[1:] - theha_0_history[:-1]
anglesy = theha_1_history[1:] - theha_1_history[:-1]

ax.quiver(theha_0_history[:-1], theha_1_history[:-1], anglesx, anglesy, scale_units = 'xy', angles = 'xy', scale = 1, color = 'r', alpha = .9)

plt.show()

# 6 Загрузите набор данных ex1data2.txt из текстового файла.

original_df = pandas.read_csv('ex1data2.txt', header=None, names=['area', 'rooms', 'price'])
print(original_df.head())

Y = original_df['price'].values.astype('float64')
print(Y.shape)

# 7 Произведите нормализацию признаков. Повлияло ли это на скорость сходимости градиентного спуска?
# Ответ дайте в виде графика.

def gd_old(X, Y, iterations=200, alpha=0.01):
    features_count = X.shape[1]

    theta = np.zeros(features_count)

    def h(theta, x):
        sum = 0
        for i in range(len(theta)):
            sum += theta[i] * x[i]
        return sum

    def cost_f(theta, X, Y):
        m = len(Y)
        sum = 0
        for i in range(m):
            sum += (h(theta, X[i]) - Y[i]) ** 2

        return sum / (2 * m)

    def der_theta(theta, X, Y, alpha, theta_idx):
        m = len(Y)
        sum = 0
        for i in range(m):
            sum += (h(theta, X[i]) - Y[i]) * X[i][theta_idx]

        return (alpha / m) * sum

    ## GD algorithm
    theta_history = np.zeros([iterations + 1, features_count])
    cost_history = np.zeros(iterations + 1)  # .reshape(1, -1) if required

    cost = cost_f(theta, X, Y)

    cost_history[0] = cost
    theta_history[0] = theta

    for it_idx in range(iterations):
        tmptheta = np.copy(theta)

        for theta_idx in range(features_count):
            tmptheta[theta_idx] = theta[theta_idx] - der_theta(theta, X, Y, alpha, theta_idx)

        theta = np.copy(tmptheta)

        cost = cost_f(theta, X, Y)

        cost_history[it_idx + 1] = cost
        theta_history[it_idx + 1] = theta

    return theta, cost, theta_history, cost_history

de_normalized_df = original_df.drop('price', axis=1)
print(de_normalized_df.head())

X_denorm = de_normalized_df.copy()
X_denorm.insert(0, '', 1)
X_denorm = X_denorm.values.astype('float64')

print(X_denorm[0: 2])

# Mean normalization
normalized_df = (de_normalized_df-de_normalized_df.mean())/(de_normalized_df.max()-de_normalized_df.min())
print(normalized_df.head())

X_norm = normalized_df.copy()
X_norm.insert(0, '', 1)
X_norm = X_norm.values.astype('float64')

print(X_norm[0: 2])

# RuntimeWarning: overflow encountered in double_scalars
theta, cost, _, denorm_cost_history = gd_old(X_denorm, Y)

print(f'Cost: {cost}')
print(f'Theta: {theta}')

theta, cost, _, norm_cost_history = gd_old(X_norm, Y)

print(f'Cost: {cost}')
print(f'Theta: {theta}')

plt.figure(figsize=(10,6))

plt.plot(range(len(denorm_cost_history)), denorm_cost_history, label='Денормальизованные данные')
plt.plot(range(len(norm_cost_history)), norm_cost_history, label='Нормальизованные данные')

plt.grid(True)
plt.xlabel("Итерации")
plt.ylabel("Значение функции стоимости")
plt.legend()
plt.show()

# 8 Реализуйте функции потерь J(θ) и градиентного спуска для случая многомерной линейной регрессии
# с использованием векторизации.

def h(theta, x):
    return np.dot(x, theta.T)

def cost_f(theta, X, Y):
    m = len(Y)
    results = h(theta, X) - Y
    return (np.dot(results.T, results) / (2 * m)).item()

def gd_vec(X, Y_un_resh, iterations=200, alpha=0.01):
    Y = Y_un_resh.reshape(-1, 1)

    features_count = X.shape[1]
    m = Y.size

    theta = np.zeros([1, features_count])

    theta_history = np.zeros([iterations + 1, features_count])
    cost_history = np.zeros(iterations + 1)

    cost = cost_f(theta, X, Y)

    cost_history[0] = cost
    theta_history[0] = theta

    for it_idx in range(iterations):
        dt = np.dot((h(theta, X) - Y).T, X)
        theta = theta - (alpha / m) * dt

        cost = cost_f(theta, X, Y)

        cost_history[it_idx + 1] = cost
        theta_history[it_idx + 1] = theta

    return theta, cost, theta_history, cost_history

theta, cost, theta_history, cost_history = gd_old(X_norm, Y)

print(f'Cost: {cost}')
print(f'Theta: {theta}')

theta, cost, theta_history, cost_history = gd_vec(X_norm, Y)

print(f'Cost: {cost}')
print(f'Theta: {theta}')

# 9 Покажите, что векторизация дает прирост производительности.

start = time.time()
theta, _, _, _ = gd_old(X_norm, Y, 9000, 0.1)
end = time.time()
print("Time:")
print(end - start)
print(theta)

start = time.time()
theta, _, _, _ = gd_vec(X_norm, Y, 9000, 0.1)
end = time.time()
print("Time:")
print(end - start)
print(theta)

# 10 Попробуйте изменить параметр ɑ (коэффициент обучения).
# Как при этом изменяется график функции потерь в зависимости от числа итераций градиентного спуск?
# Результат изобразите в качестве графика.

loss = {}
iterations_count = 120

for alpha in [0.01, 0.05, 0.1, 0.5, 1, 2]:
    _, _, _, cost_history = gd_vec(X_norm, Y, iterations_count, alpha)
    loss[str(alpha)] = cost_history

plt.figure(figsize=(10,6))

iter_range = range(iterations_count + 1)

for alpha, cost_series in loss.items():
    plt.plot(iter_range, cost_series, label=r'$ \alpha $: %s'%(alpha))

plt.grid(True)
plt.xlabel("Итерации")
plt.ylabel("Значение функции стоимости")
plt.legend()
plt.show()

# 11 Постройте модель, используя аналитическое решение, которое может быть получено методом наименьших квадратов.
# Сравните результаты данной модели с моделью, полученной с помощью градиентного спуска.

def normal_equation(X, Y):
    return np.dot(np.dot(np.linalg.inv(np.dot(X.T, X)), X.T), Y)

start = time.time()
normal_equation(X_norm, Y)
end = time.time()
print("Time:")
print(end - start)
print(theta)

start = time.time()
theta, _, _, _ = gd_vec(X_norm, Y, 9000, 0.1)
end = time.time()
print("Time:")
print(end - start)
print(theta)


import sys
import numpy as np
import matplotlib.pyplot as matplot

def main():

    user_input = sys.stdin.read()

    global MEM
    global PC
    global EE
    global RF
    global x_list
    global y_list
    global cycle

    x_list = []
    y_list = []
    cycle=0
    # Memory contains (code + variables)
    # Memory ~ RAM
    # heavy programs use more RAM on your laptop because they have big code + more variables
    MEM =   Memory(user_input.strip())

    # ProgramCounter object keeps track of what line of code is running
    PC  =   ProgramCounter(0)

    # ExecutionEngine ~ ALU of the CPU
    # All major processing is done here
    EE  =   ExecutionEngine()

    # Register file stores all registers.
    # It is different and disjoint from Memory/RAM.
    RF  =   RegisterFile()

    halted = False

    while not halted:
        # Fetch instruction
        instruction = MEM.get(PC)

        # Execute instruction and get new states
        halted, new_PC = EE.execute(instruction)

        # Print Program Counter
        PC.dump()

        # Print all registers
        RF.dump()

        # Change Program Counter to next instruction
        PC.update(new_PC)

    # Print all contents of memory
    MEM.dump()

    plotgraph(x_list, y_list)

# ================================
# CLASSES
# ================================

class Memory():
    def __init__(self, user_input):
        # Load the program into Memory
        code_space = list(map(convertToDecimal, user_input.split("\n")))

        # Create space in Memory for variables
        variable_space = [0]*256

        # Cut to 512 bytes of space
        # 256 cells * 16 bits = 4096 bits = 512 bytes
        self.data = (code_space + variable_space)[:256] # Slice to size of 256

    def get(self, address):
        # INPUT: ADDRESS as (binary string OR decimal integer)
        # OUTPUT: Data at input address

        # Example
        # INPUT: "0000...101" or 5
        # OUTPUT: Data at address 5
        if type(address) == str:
            address = convertToDecimal(address)
        if type(address) == ProgramCounter:
            address = address.value

        addpoint(cycle, address)

        return self.data[address]

    def set(self, address, value):
        # INPUT1: ADDRESS as (binary string OR decimal integer)
        # INPUT2: data

        # USE: stores data into Memory at address

        # Example: Both of the following inputs are equivalent
        # - (5,123)
        # - ("0000000000000101", 123)
        if type(address) == str:
            address = convertToDecimal(address)
        self.data[address] = value

        addpoint(cycle, address)

    def dump(self):
        # Print contents of memory as output
        print()
        for memory in self.data:
            print(convertToBinary(memory))

class ProgramCounter():
    def __init__(self, value):
        # Value -> Value of ProgramCounter
        # Value is an integer between [0,255]
        self.value = value

    def dump(self):
        # Print PC.value as output
        # Please refer PDF to check format

        print(convertToBinary(self.value)[8:], end=" ")

    def update(self, new_PC):
        # Set PC to next instruction
        self.value = new_PC

        global cycle
        cycle +=1

class ExecutionEngine():
    def __init__(self):
        # "instructions" has been defined at the end of this class
        # instruction_map maps numbers to instructions
        # 0 -> add
        # 1 -> sub
        # ...
        # 17 -> je
        # 18 -> hlt
        self.instruction_map = dict(enumerate(ExecutionEngine.instructions))

        # new_state tells what change the instruction has bought
        # halted tells if CPU should halt
        # PC tells which is the next instruction that should be run
        # TypeE instructions bring drastic changes to PC
        self.new_state = {'halted': False, 'PC': 0}

    def execute(self, instruction):
        # execute() does the following.
        # 1. take in instruction (opcode + unused_bits + operands)
        # 2. identify type of instruction
        # 3. call appropriate unit (add, sub, jmp, hlt, ...)

        # EXAMPLE INPUT: 83
        # Binary of 83: 00000_00_001_010_011
        # opcode = 00000 (ADD instruction)
        # unused_bits = 00
        # reg1 = 001 (R1)
        # reg2 = 010 (R2)
        # reg3 = 011 (R3)

        # OUTPUT: executes ADD(00_001_010_011)
        # Note: underscores (_) are for clarity. not actually there.
        instruction = convertToBinary(instruction)

        opcode, tail = instruction[:5],instruction[5:]
        executor = self.instruction_map[convertToDecimal(opcode)]

        # Call appropriate function
        executor(self, tail)

        # Return new CPU states to main() function
        return self.new_state['halted'], self.new_state['PC']

    # ================================
    # INDIVIDUAL INSTRUCTION EXECUTION
    # ================================

    def ADD(self, tail):
        # Type A

        # INPUT: ADD("00001010011")

        # Here,
        # unused-bits_reg1_reg2_reg3 = 00_001_010_011

        # OUTPUT:
        # set reg1 to "RF.get(reg2) + RF.get(reg3)"

        # Can be done through
        # RF.set(target_register, data)

        # which, here, is
        # RF.set(reg1, RF.get(reg2) + RF.get(reg3))
        unused_bits = tail[0:2]

        destination = tail[2:5]
        source1 = tail[5:8]
        source2 = tail[8:11]

        RF.clearFlags()
        result = RF.get(source1) + RF.get(source2)

        if result > 65535:
            result %= 65536
            RF.setOverflow()

        RF.set(destination, result)
        self.new_state['halted'] = False
        self.new_state['PC'] = PC.value + 1

    def SUB(self, tail):
        # Type A
        unused_bits = tail[0:2]

        destination = tail[2:5]
        source1 = tail[5:8]
        source2 = tail[8:11]

        RF.clearFlags()
        result = RF.get(source1) - RF.get(source2)

        if result < 0:
            result = 0
            RF.setOverflow()

        RF.set(destination, result)
        self.new_state['halted'] = False
        self.new_state['PC'] = PC.value + 1

    def MOV_IMMEDIATE(self, tail):
        # Type B

        unused_bits = None

        destination = tail[0:3]
        source = tail[3:11]

        RF.clearFlags()
        result = convertToDecimal(source)

        RF.set(destination, result)
        self.new_state['halted'] = False
        self.new_state['PC'] = PC.value + 1

    def MOV_REGISTER(self, tail):
        # Type C

        unused_bits = tail[0:5]

        destination = tail[5:8]
        source = tail[8:11]

        result = RF.get(source)
        RF.clearFlags()

        RF.set(destination, result)
        self.new_state['halted'] = False
        self.new_state['PC'] = PC.value + 1

    def LD(self, tail):
        # Type D

        unused_bits = None

        destination = tail[0:3]
        source = tail[3:11]

        RF.clearFlags()
        result = MEM.get(source)

        RF.set(destination, result)
        self.new_state['halted'] = False
        self.new_state['PC'] = PC.value + 1

    def ST(self, tail):
        # Type D

        unused_bits = None

        source = tail[0:3]
        destination = tail[3:11]

        RF.clearFlags()
        result = RF.get(source)

        MEM.set(destination, result)
        self.new_state['halted'] = False
        self.new_state['PC'] = PC.value + 1

    def MUL(self, tail):
        # Type A

        unused_bits = tail[0:2]

        destination = tail[2:5]
        source1 = tail[5:8]
        source2 = tail[8:11]

        RF.clearFlags()
        result = RF.get(source1) * RF.get(source2)

        if result > 65535:
            result %= 65536
            RF.setOverflow()

        RF.set(destination, result)
        self.new_state['halted'] = False
        self.new_state['PC'] = PC.value + 1

    def DIV(self, tail):
        # Type C

        unused_bits = tail[0:5]

        source1 = tail[5:8]
        source2 = tail[8:11]

        RF.clearFlags()

        R0 = RF.get(source1)//RF.get(source2)
        R1 = RF.get(source1)%RF.get(source2)

        RF.set("0" , R0)
        RF.set("1" , R1)

        self.new_state['halted'] = False
        self.new_state['PC'] = PC.value + 1

    def RS(self, tail):
        # Type B

        unused_bits = None

        destination = tail[0:3]
        shift = tail[3:11]

        RF.clearFlags()
        result = RF.get(destination) >> convertToDecimal(shift)

        RF.set(destination, result)
        self.new_state['halted'] = False
        self.new_state['PC'] = PC.value + 1

    def LS(self, tail):
        # Type B

        unused_bits = None

        destination = tail[0:3]
        shift = tail[3:11]

        RF.clearFlags()
        result = RF.get(destination) << convertToDecimal(shift)

        RF.set(destination, result)
        self.new_state['halted'] = False
        self.new_state['PC'] = PC.value + 1

    def XOR(self, tail):
        # Type A

        unused_bits = tail[0:2]

        destination = tail[2:5]
        source1 = tail[5:8]
        source2 = tail[8:11]

        RF.clearFlags()
        result = RF.get(source1) ^ RF.get(source2)

        #print ('{0:b}'.format(result))
        RF.set(destination, result)
        self.new_state['halted'] = False
        self.new_state['PC'] = PC.value + 1

    def OR(self, tail):
        # Type A

        unused_bits = tail[0:2]

        destination = tail[2:5]
        source1 = tail[5:8]
        source2 = tail[8:11]

        RF.clearFlags()
        result = RF.get(source1) | RF.get(source2)
        #print ('{0:b}'.format(result))
        RF.set(destination, result)
        self.new_state['halted'] = False
        self.new_state['PC'] = PC.value + 1

    def AND(self, tail):
        # Type A

        unused_bits = tail[0:2]

        destination = tail[2:5]
        source1 = tail[5:8]
        source2 = tail[8:11]

        RF.clearFlags()
        result = RF.get(source1) & RF.get(source2)
        #print ('{0:b}'.format(result))
        RF.set(destination, result)
        self.new_state['halted'] = False
        self.new_state['PC'] = PC.value + 1

    def NOT(self, tail):
        # Type C

        unused_bits = tail[0:5]

        destination = tail[5:8]
        source = tail[8:11]

        RF.clearFlags()
        result = ~ RF.get(source) % 65536

        RF.set(destination, result)
        self.new_state['halted'] = False
        self.new_state['PC'] = PC.value + 1

    def CMP(self, tail):
        # Type C

        unused_bits = tail[0:5]

        source1 = tail[5:8]
        source2 = tail[8:11]

        RF.clearFlags()
        result = cmp(RF.get(source1), RF.get(source2))

        RF.setCMP(result)
        self.new_state['halted'] = False
        self.new_state['PC'] = PC.value + 1

    def JMP(self, tail):
       # Type E

        unused_bits = tail[0:3]

        memory_address = tail[3:11]

        result = convertToDecimal(memory_address)
        RF.clearFlags()

        self.new_state['halted'] = False
        self.new_state['PC'] = result

    def JLT(self, tail):
        # Type E

        unused_bits = tail[0:3]

        memory_address = tail[3:11]

        if RF.getCMP() == -1:
            # if last "CMP reg1, reg2" was reg1 < reg2
            # JLT -> Jump if Less Than
            result = convertToDecimal(memory_address)
        else:
            result = PC.value + 1
        RF.clearFlags()

        self.new_state['halted'] = False
        self.new_state['PC'] = result

    def JGT(self, tail):
        # Type E
        unused_bits = tail[0:3]

        memory_address = tail[3:11]

        if RF.getCMP() == +1:
            result = convertToDecimal(memory_address)
        else:
            result = PC.value + 1
        RF.clearFlags()

        self.new_state['halted'] = False
        self.new_state['PC'] = result

    def JE(self, tail):
        # Type E

        unused_bits = tail[0:3]

        memory_address = tail[3:11]

        if RF.getCMP() == 0:
            result = convertToDecimal(memory_address)
        else:
            result = PC.value + 1
        RF.clearFlags()

        self.new_state['halted'] = False
        self.new_state['PC'] = result

    def HLT(self, tail):
        # Type F

        unused_bits = None
        RF.clearFlags()

        self.new_state['halted'] = True
        self.new_state['PC'] = PC.value + 1

    # ====================================================================
    # Class level variables for ExecutionEngine:
    # 1. instructions
    # ====================================================================

    # List of all instructions, in order
    instructions = [ADD,SUB,MOV_IMMEDIATE,MOV_REGISTER,LD,ST,MUL,DIV,RS,LS,XOR,OR,AND,NOT,CMP,JMP,JLT,JGT,JE,HLT]

class RegisterFile():
    def __init__(self):
        # List of 8 registers
        self.data = [0]*8

    def dump(self):
        # Fancy way of printing all registers to output

        # it just prints the list in binary format
        print(' '.join(map(convertToBinary, self.data)), end=' \n')

    def get(self, address):
        # INPUT: binary string OR integer

        # INPUT: address = "000..00101"
        # OUTPUT: Data in R5

        # INPUT: address = 5
        # OUTPUT: Data in R5
        if type(address) == str:
            address = convertToDecimal(address)
        return self.data[address]

    def set(self, address, value):
        # INPUT1: binary string OR integer address
        # INPUT2: integer value to be stored as data

        # INPUT: address = "000..00101", value = 123
        # OUTPUT: Set Data in R5 = 123

        # INPUT: address = 5
        # OUTPUT: Set Data in R5 = 123

        if type(address) == str:
            address = convertToDecimal(address)
        self.data[address] = value

    def clearFlags(self):
        # Just set all bits of FLAGS to 0
        self.data[7] =0

    def setCMP(self, value):
        # INPUT: +1
        # OUTPUT: set Greater Than bit

        # INPUT: 0
        # OUTPUT: set Equal To bit

        # INPUT: -1
        # OUTPUT: set Lesser Than bit

        if value == 0:
            # E bit
            offset = 0
        elif value == 1:
            # G bit
            offset = 1
        elif value == -1:
            # L bit
            offset = 2

        self.data[-1] |= 1<<offset

    def getCMP(self):
        # OUTPUT:
        # +1 if G bit is set (Greater than)
        # 0 if E bit is set (Equal to)
        # -1 if E bit is set (Lesser to)

        if self.data[-1] & 1<<0:
            # E bit
            return 0
        elif self.data[-1] & 1<<1:
            # G bit
            return 1
        if self.data[-1] & 1<<2:
            # L bit
            return -1

    def setOverflow(self):
        # OUTPUT:
        # Sets 3rd bit of FLAGS to 1
        # 3rd bit in FLAGS if OVERFLOW bit

        self.data[-1] |= 1<<3

# ================================
# HELPER FUNCTIONS
# ================================

def convertToDecimal(x):
    # INPUT: "010"
    # output: 2
    x = int(x)

    decimal, i, n = 0, 0, 0
    while(x!= 0):
        dec = x%10
        decimal = decimal + dec * pow(2, i)
        x = x//10
        i += 1

    return decimal

def convertToBinary(x, n=16):
    # Convert x into an n-bit string
    # INPUT: (x=5, n=8)
    # output: "00000101"
    a = x
    #this will print a in binary
    bnr = bin(a).replace('0b','')
    x = bnr[::-1] #this reverses an array
    while len(x) < n:
        x += '0'
    bnr = x[::-1]

    return bnr

def cmp(a, b):
    # INPUT: 2 integers

    # OUTPUT:
    # +1 if a > b
    # 0 if a == b
    # -1 if a < b

    # EXAMPLE:
    # cmp(3,10) = -1 because 3 < 10
    return (a > b) - (a < b)

def addpoint(x,y):
    x_list.append(x)
    y_list.append(y)

def plotgraph(x_list, y_list):
    matplot.scatter(x_list, y_list, c='red')
    matplot.title('Memory Access trace Scatter plot')
    matplot.xlabel('Cycle Number')
    matplot.ylabel('Memory Address')
    matplot.show()
    matplot.savefig("Graph.jpg")

# ================================
# END
# ================================

if __name__ == "__main__":
    main()


import json
from typing import Sequence

from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, ReplyKeyboardRemove, ReplyKeyboardMarkup
from telegram.ext import ContextTypes, CallbackContext, ConversationHandler, CommandHandler, CallbackQueryHandler, MessageHandler, filters

from Constants.NumericConstants import MAX_FAILS

from Controllers.UserController import UserController
from Controllers.ReservationController.ConversationStates import ConversationStates

from Models.Reservation import Reservation
from Models.Person import Person
from Helpers.Helper import Helper

# Reservation management controller
class ReservationController:

    @staticmethod
    async def select_person_for_reservation(update: Update, context: ContextTypes.DEFAULT_TYPE):
        telegram_id = update.effective_user.id
        persons = Person.get_all_persons_by_telegram_id( telegram_id )
        persons_reply_markup: Sequence[Sequence[str]] = [[]]
        answer = "*✒ A que persona vas a reservar?:* \n------------------------------------------\n"

        if( not persons ):
            await update.message.reply_text(":( Usted no ha registrado a ninguna persona todavia")
            return

        persons_reply_markup, answer = Helper.get_persons_keyboard_from_user(update, context)

        await update.message.reply_text(answer, parse_mode="Markdown", reply_markup=ReplyKeyboardMarkup(persons_reply_markup))
        return ConversationStates.CREATE_RESERVATION

    @staticmethod
    async def get_reservations(update: Update, context: ContextTypes.DEFAULT_TYPE):
        telegram_id = update.effective_user.id
        reservations = Reservation.get_all_reservations_by_telegram_id(telegram_id)

        if(not reservations):
            await update.message.reply_text("🚧 *No tienes ninguna reserva*", parse_mode="Markdown")
            return

        for reservation in reservations:
            ( reservation_id, arrival_order, name) = reservation
            action = { "name": "CANCEL_RESERVATION", "pk": reservation_id }
            cancel_reservation_button = InlineKeyboardButton("🚫🚌 Cancelar", callback_data=json.dumps(action))
            failNumber = "" if arrival_order <= MAX_FAILS else f"⚠ *Fallo:* {arrival_order - MAX_FAILS}"
            await update.message.reply_text(
                f"🪪 {name}\n*🔢 Turno:* {arrival_order}\n",
                parse_mode="Markdown",
                reply_markup=InlineKeyboardMarkup([[cancel_reservation_button]])
            )

        if( update.message.text == "/reservar_todos" ):
            await update.message.reply_text("✅ Todas las personas han sido reservadas con exito!")

    @staticmethod
    async def create_reservation_for_all_person(update: Update, context: ContextTypes.DEFAULT_TYPE):
        telegram_id = update.effective_user.id
        persons = Person.get_all_persons_by_telegram_id( telegram_id )
        await UserController.register_user(update, context)
        for person in persons:
            (id, *_) = person
            if( not Reservation.exist_person(id) ):
                Reservation.create_reservation( telegram_id, id )
        await ReservationController.get_reservations(update, context)

    # Create a unique reservation by User
    @staticmethod
    async def create_reservation(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:

        telegram_id = update.message.from_user.id
        person_name = update.message.text

        person = Person.get_person_id_by_name_from_telegram_id(telegram_id, person_name)

        if(not person):
            await update.message.reply_text(f"🫤 Lo siento, no hay personas registradas con el nombre {person_name}", reply_markup=ReplyKeyboardRemove())
            return ConversationHandler.END

        person_id, = person
        await UserController.register_user(update, context)
        if( not Reservation.exist_person(person_id) ):
            Reservation.create_reservation(telegram_id, person_id)
            await update.message.reply_text(f"✅ Se ha creado una reserva satisfactoriamente para: {person_name}", reply_markup=ReplyKeyboardRemove())
        else:
            await update.message.reply_text("😉 Ya esa persona estaba reservada: ", reply_markup=ReplyKeyboardRemove())
        reservation_id, arrival_order, name = Reservation.get_reservation_by_user_id_and_name(telegram_id, person_name)

        action = { "name": "CANCEL_RESERVATION", "pk": reservation_id }
        cancel_reservation_button = InlineKeyboardButton("🚫🚌 Cancelar", callback_data=json.dumps(action))
        failNumber = "" if arrival_order <= MAX_FAILS else f"⚠ *Fallo:* {arrival_order - MAX_FAILS}"

        await update.message.reply_text(
            f"🪪 {person_name}\n*🔢 Turno:* {arrival_order}\n{failNumber}",
            parse_mode="Markdown",
            reply_markup=InlineKeyboardMarkup([[cancel_reservation_button]])
        )
        return ConversationHandler.END

    @staticmethod
    async def cancel_reservation(update: Update, context: CallbackContext):
        await update.effective_message.delete()
        action = update.callback_query.data

        if( not Helper.is_json( action ) ):
            return

        name, pk = json.loads(action).values()

        if( name != "CANCEL_RESERVATION" ):
            return

        reservation = Reservation.get_reservation_by_id(pk)

        if(not reservation):
            await update.effective_message.reply_text(f"⛔🕘 Esa reservación ya no existe, vuelva a reservar")
            return

        reservation_id, arrival_order, name = Reservation.get_reservation_by_id(pk)
        Reservation.delete_by_id(reservation_id)
        await update.effective_message.reply_text(f"✅ La reservacion de {name} se ha cancelado con exito ! \n 🗑 Eliminado el turno: {arrival_order}")

    # CANCEL_OPERATION
    @staticmethod
    async def cancel_operations(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
        await update.message.reply_text( "Operacion Cancelada", reply_markup=ReplyKeyboardRemove() )
        return ConversationHandler.END

reservation_conversation_handler = ConversationHandler(
    entry_points=[
        CommandHandler("reservas", ReservationController.get_reservations),
        CommandHandler("reservar_todos", ReservationController.create_reservation_for_all_person),
        CommandHandler("reservar", ReservationController.select_person_for_reservation)
    ],
    states={
        ConversationStates.CREATE_RESERVATION: [MessageHandler(filters.TEXT & ~filters.COMMAND, ReservationController.create_reservation)]
    },
    fallbacks=[
        CommandHandler("cancel", ReservationController.cancel_operations),
        MessageHandler(filters.ALL, ReservationController.cancel_operations)
    ]
)

reservation_callback_query = CallbackQueryHandler(ReservationController.cancel_reservation)