# Path: soap/common/base.py
# def base_dispatcher(dispatch_name='execute'):
#     class Dispatcher(BaseDispatcher):
#         pass
#     Dispatcher.dispatch_name = dispatch_name
#     return Dispatcher
# 
# Path: soap/common/cache.py
# def cached(f):
#     class NonLocals(object):
#         pass
#     CACHE_CAPACITY = 1000000
#     cache = {}
#     NonLocals.full = False
#     NonLocals.hits = NonLocals.misses = NonLocals.currsize = 0
#     NonLocals.root = []
#     NonLocals.root[:] = [NonLocals.root, NonLocals.root, None, None]
#     PREV, NEXT, KEY, RESULT = range(4)
# 
#     def decorated(*args, **kwargs):
#         if not kwargs:
#             key_tuple = args
#         else:
#             key_tuple = (args, tuple(sorted(kwargs.items(), key=hash)))
#         key = pickle.dumps(key_tuple)
#         link = cache.get(key)
#         if link is not None:
#             p, n, k, r = link
#             p[NEXT] = n
#             n[PREV] = p
#             last = NonLocals.root[PREV]
#             last[NEXT] = NonLocals.root[PREV] = link
#             link[PREV] = last
#             link[NEXT] = NonLocals.root
#             NonLocals.hits += 1
#             return r
#         r = f(*args, **kwargs)
#         if NonLocals.full:
#             NonLocals.root[KEY] = key
#             NonLocals.root[RESULT] = r
#             cache[key] = NonLocals.root
#             NonLocals.root = NonLocals.root[NEXT]
#             del cache[NonLocals.root[KEY]]
#             NonLocals.root[KEY] = NonLocals.root[RESULT] = None
#         else:
#             last = NonLocals.root[PREV]
#             link = [last, NonLocals.root, key, r]
#             cache[key] = last[NEXT] = NonLocals.root[PREV] = link
#             NonLocals.currsize += 1
#             NonLocals.full = (NonLocals.currsize == CACHE_CAPACITY)
#         NonLocals.misses += 1
#         return r
# 
#     def cache_info():
#         return NonLocals.hits, NonLocals.misses, NonLocals.currsize
# 
#     def cache_clear():
#         cache.clear()
#         NonLocals.root[:] = [NonLocals.root, NonLocals.root, None, None]
#         NonLocals.hits = NonLocals.misses = NonLocals.currsize = 0
#         NonLocals.full = False
# 
#     d = functools.wraps(f)(decorated)
#     d.cache_info = cache_info
#     d.cache_clear = cache_clear
#     d.wrapped_func = f
# 
#     global _cached_funcs
#     _cached_funcs.append(d)
# 
#     return d


from soap.common.base import base_dispatcher
from soap.common.cache import cached
    from soap.expression.variable import Variable
    from soap.expression.variable import VariableTuple
    from soap.expression.base import Expression
    from soap.expression.variable import Variable, VariableTuple
    from soap.expression.arithmetic import ArithExpr
    from soap.expression.boolean import BoolExpr
    from soap.expression.operators import BARRIER_OP
    from soap.expression import operators
    from soap.expression.arithmetic import (
        UnaryArithExpr, BinaryArithExpr, TernaryArithExpr, SelectExpr
    )
    from soap.expression.boolean import (
        UnaryBoolExpr, BinaryBoolExpr, TernaryBoolExpr
    )
    from soap.expression.fixpoint import FixExpr
    from soap.expression.linalg import Subscript, AccessExpr, UpdateExpr
    from soap.expression.fixpoint import FixExpr
def is_arith_expr(e):
    """Check if `e` is an expression."""
    return isinstance(e, ArithExpr)


def is_bool_expr(e):
    """Check if `e` is a boolean expression."""
    return isinstance(e, BoolExpr)


def concat_multi_expr(*expr_args):
    """Concatenates multiple expressions into a single expression by using the
    barrier operator.
    """
    me = None
    for e in expr_args:
        me = me | e if me else e
    return me


def split_multi_expr(e):
    """Splits the single expression into multiple expressions."""
    if e.op != BARRIER_OP:
        return [e]
    return split_multi_expr(e.a1) + split_multi_expr(e.a2)


op_expr_cls_map = None



# Path: soap/common/base.py
# def base_dispatcher(dispatch_name='execute'):
#     class Dispatcher(BaseDispatcher):
#         pass
#     Dispatcher.dispatch_name = dispatch_name
#     return Dispatcher
# 
# Path: soap/common/cache.py
# def cached(f):
#     class NonLocals(object):
#         pass
#     CACHE_CAPACITY = 1000000
#     cache = {}
#     NonLocals.full = False
#     NonLocals.hits = NonLocals.misses = NonLocals.currsize = 0
#     NonLocals.root = []
#     NonLocals.root[:] = [NonLocals.root, NonLocals.root, None, None]
#     PREV, NEXT, KEY, RESULT = range(4)
# 
#     def decorated(*args, **kwargs):
#         if not kwargs:
#             key_tuple = args
#         else:
#             key_tuple = (args, tuple(sorted(kwargs.items(), key=hash)))
#         key = pickle.dumps(key_tuple)
#         link = cache.get(key)
#         if link is not None:
#             p, n, k, r = link
#             p[NEXT] = n
#             n[PREV] = p
#             last = NonLocals.root[PREV]
#             last[NEXT] = NonLocals.root[PREV] = link
#             link[PREV] = last
#             link[NEXT] = NonLocals.root
#             NonLocals.hits += 1
#             return r
#         r = f(*args, **kwargs)
#         if NonLocals.full:
#             NonLocals.root[KEY] = key
#             NonLocals.root[RESULT] = r
#             cache[key] = NonLocals.root
#             NonLocals.root = NonLocals.root[NEXT]
#             del cache[NonLocals.root[KEY]]
#             NonLocals.root[KEY] = NonLocals.root[RESULT] = None
#         else:
#             last = NonLocals.root[PREV]
#             link = [last, NonLocals.root, key, r]
#             cache[key] = last[NEXT] = NonLocals.root[PREV] = link
#             NonLocals.currsize += 1
#             NonLocals.full = (NonLocals.currsize == CACHE_CAPACITY)
#         NonLocals.misses += 1
#         return r
# 
#     def cache_info():
#         return NonLocals.hits, NonLocals.misses, NonLocals.currsize
# 
#     def cache_clear():
#         cache.clear()
#         NonLocals.root[:] = [NonLocals.root, NonLocals.root, None, None]
#         NonLocals.hits = NonLocals.misses = NonLocals.currsize = 0
#         NonLocals.full = False
# 
#     d = functools.wraps(f)(decorated)
#     d.cache_info = cache_info
#     d.cache_clear = cache_clear
#     d.wrapped_func = f
# 
#     global _cached_funcs
#     _cached_funcs.append(d)
# 
#     return d


# Path: soap/expression/common.py
from soap.common.base import base_dispatcher
from soap.common.cache import cached
    from soap.expression.variable import Variable
    from soap.expression.variable import VariableTuple
    from soap.expression.base import Expression
    from soap.expression.variable import Variable, VariableTuple
    from soap.expression.arithmetic import ArithExpr
    from soap.expression.boolean import BoolExpr
    from soap.expression.operators import BARRIER_OP
    from soap.expression import operators
    from soap.expression.arithmetic import (
        UnaryArithExpr, BinaryArithExpr, TernaryArithExpr, SelectExpr
    )
    from soap.expression.boolean import (
        UnaryBoolExpr, BinaryBoolExpr, TernaryBoolExpr
    )
    from soap.expression.fixpoint import FixExpr
    from soap.expression.linalg import Subscript, AccessExpr, UpdateExpr
    from soap.expression.fixpoint import FixExpr

def is_arith_expr(e):
    """Check if `e` is an expression."""
    return isinstance(e, ArithExpr)


def is_bool_expr(e):
    """Check if `e` is a boolean expression."""
    return isinstance(e, BoolExpr)


def concat_multi_expr(*expr_args):
    """Concatenates multiple expressions into a single expression by using the
    barrier operator.
    """
    me = None
    for e in expr_args:
        me = me | e if me else e
    return me


def split_multi_expr(e):
    """Splits the single expression into multiple expressions."""
    if e.op != BARRIER_OP:
        return [e]
    return split_multi_expr(e.a1) + split_multi_expr(e.a2)


op_expr_cls_map = None



@cached