# Path: misc.py
# def flipSide(side):
# def _interleave(a, xs):
# 
# Path: calculus/symbol.py
# class Symbol:
# class StringSymbol(Symbol):
#   def __init__(self, type):
#   def _generate_id(self):
#   def __eq__(self, other):
#   def __ne__(self):
#   def __hash__(self):
#   def __repr__(self):
#   def __init__(self, s, type, infix = None):
#   def __repr__(self):
# 
# Path: calculus/variable.py
# class Variable(GeneralizedVariable):
#   def __init__(self):
#     self._generate_id()
# 
#   def _generate_id(self):
#     global n_variables
#     self._id = n_variables
#     n_variables += 1
# 
#   def updateVariables(self):
#     return Variable()
# 
#   def __eq__(self, other):
#     return self.__class__ == other.__class__ and self._id == other._id
#   def __ne__(self, other):
#     return not(self == other)
#   def __hash__(self):
#     return hash(self._id)
# 
#   def applied_variables(self):
#     return Set([])
# 
#   def __repr__(self):
#     return "<abstract variable %s>"%(self._id,)
# 
#   def substituteVariable(self, a, b):
#     if self == a:
#       return b
#     else:
#       return self
# 
#   def freeVariables(self):
#     return Set([self])
# 
# Path: lib/common_symbols.py



from misc import left, right
from calculus import symbol
from calculus.variable import Variable
from lib import common_symbols
from sets import Set
  def forwardAssociateOther(self):
    # A % (B % C) ---> (A % B) % C
    return self.backwardAssociate().invert()

  def backwardAssociateOther(self):
    # A % (B % C) ---> (A % B) % C
    return self.forwardAssociate().invert()

class And(Conjunction):
  # f is a function taking each object B to a list ys
  # return a list of all pairs (a, X) such that
  #   a is an arrow self -> B|self
  #   X is in f(B)
  #   B == Always(C) for some C
  def produceFiltered(self, f):
    result = []
    # (X|Y) --> (X|(B|Y)) --> (X|(Y|B)) --> ((X|Y)|B) --> (B|(X|Y))
    result.extend([(self.forwardOnRight(a.forwardFollow(lambda x:
      x.forwardCommute())).forwardFollow(lambda x:
        x.forwardAssociateOther().forwardFollow(lambda x:
          x.forwardCommute())), X) for a, X in self.right.produceFiltered(f)])
    # (X|Y) --> ((B|X)|Y) --> (B|(X|Y))
    result.extend([(self.forwardOnLeft(a).forwardFollow(lambda x:
          x.forwardAssociate()), X) for a, X in self.left.produceFiltered(f)])
    return result

  def getSide(self, side):
    if side == left:
      return self.left
    else:

# Path: misc.py
# def flipSide(side):
# def _interleave(a, xs):
# 
# Path: calculus/symbol.py
# class Symbol:
# class StringSymbol(Symbol):
#   def __init__(self, type):
#   def _generate_id(self):
#   def __eq__(self, other):
#   def __ne__(self):
#   def __hash__(self):
#   def __repr__(self):
#   def __init__(self, s, type, infix = None):
#   def __repr__(self):
# 
# Path: calculus/variable.py
# class Variable(GeneralizedVariable):
#   def __init__(self):
#     self._generate_id()
# 
#   def _generate_id(self):
#     global n_variables
#     self._id = n_variables
#     n_variables += 1
# 
#   def updateVariables(self):
#     return Variable()
# 
#   def __eq__(self, other):
#     return self.__class__ == other.__class__ and self._id == other._id
#   def __ne__(self, other):
#     return not(self == other)
#   def __hash__(self):
#     return hash(self._id)
# 
#   def applied_variables(self):
#     return Set([])
# 
#   def __repr__(self):
#     return "<abstract variable %s>"%(self._id,)
# 
#   def substituteVariable(self, a, b):
#     if self == a:
#       return b
#     else:
#       return self
# 
#   def freeVariables(self):
#     return Set([self])
# 
# Path: lib/common_symbols.py



# Path: calculus/basic/formula.py
from misc import left, right
from calculus import symbol
from calculus.variable import Variable
from lib import common_symbols
from sets import Set

  def forwardAssociateOther(self):
    # A % (B % C) ---> (A % B) % C
    return self.backwardAssociate().invert()

  def backwardAssociateOther(self):
    # A % (B % C) ---> (A % B) % C
    return self.forwardAssociate().invert()

class And(Conjunction):
  # f is a function taking each object B to a list ys
  # return a list of all pairs (a, X) such that
  #   a is an arrow self -> B|self
  #   X is in f(B)
  #   B == Always(C) for some C
  def produceFiltered(self, f):
    result = []
    # (X|Y) --> (X|(B|Y)) --> (X|(Y|B)) --> ((X|Y)|B) --> (B|(X|Y))
    result.extend([(self.forwardOnRight(a.forwardFollow(lambda x:
      x.forwardCommute())).forwardFollow(lambda x:
        x.forwardAssociateOther().forwardFollow(lambda x:
          x.forwardCommute())), X) for a, X in self.right.produceFiltered(f)])
    # (X|Y) --> ((B|X)|Y) --> (B|(X|Y))
    result.extend([(self.forwardOnLeft(a).forwardFollow(lambda x:
          x.forwardAssociate()), X) for a, X in self.left.produceFiltered(f)])
    return result

  def getSide(self, side):
    if side == left:
      return self.left
    else:

      assert(side == right)