Esempio n. 1
0
    def set_primitive_set(self):
        """
        Set up deap set of primitives, needed for genetic programming
        """
        self.pset = gp.PrimitiveSet(self.get_unique_str(), 1)
        self.pset.renameArguments(ARG0=str(self.var))

        # add these symbols into primitive set
        for S in self.series_to_sum.free_symbols - {self.var}:
            self.pset.addTerminal(S, name=str(S))

        # Add basic operations into the
        self.use_func(
            (operator.mul, 2), (operator.div, 2), (operator.sub, 2), (operator.add, 2)
        )

        # find unique number from series
        unique_num = set()
        for s_term in self.partitioned_series:
            unique_num.update(S for S in sympy.postorder_traversal(s_term) if S.is_Number)

        # convert numbers into fractions and extract nominator and denominator separately
        unique_num = itertools.chain(*(sympy.fraction(S) for S in unique_num))
        self.unique_num = sorted(set(unique_num))

        return self
Esempio n. 2
0
def parse(text, splittable_symbols=set(), local_dict=genereate_local_dict()):
    from sympy.core.assumptions import ManagedProperties
    from sympy.core.function import FunctionClass, UndefinedFunction
    from sympy import Tuple
    from types import FunctionType, MethodType
    from sympy.logic.boolalg import BooleanTrue, BooleanFalse
    text = ' '.join(operator_splitter.split(text))
    expr = parse_expr(text,
                      local_dict=local_dict,
                      global_dict={},
                      transformations=get_transformations(splittable_symbols),
                      evaluate=False)
    if any(
            map(
                lambda x: type(x) in
                (BooleanTrue, BooleanFalse, ManagedProperties, FunctionClass,
                 FunctionType, MethodType, Tuple, tuple, float, int, str, bool)
                or type(type(x)) in (UndefinedFunction, ),
                postorder_traversal(expr))):
        raise NameError()
    for symbol in all_symbols(expr):
        if '_' in symbol and '' not in symbol.split('_'):
            continue
        if len(symbol) > 2:
            raise NameError()
        if len(symbol) == 2 and not symbol[-1].isdigit():
            raise NameError()
    return expr
Esempio n. 3
0
    def __new__(cls, *args, **kwargs):
        evaluate = kwargs.get('evaluate', True)

        if not args:
            return VectorZero()

        args = list(map(sympify, args))
        # If for any reasons we create VecAdd(0), I want 0 to be returned.
        # Skipping this check, VectorZero() will be returned instead
        if len(args) == 1 and args[0] == S.Zero:
            return S.Zero

        if evaluate:
            # remove instances of S.Zero and VectorZero
            args = [
                a for a in args if not (isinstance(a, VectorZero) or
                                        (a == S.Zero) or (a == Vector.zero))
            ]
            if len(args) == 0:
                return VectorZero()
            elif len(args) == 1:
                # doesn't make any sense to have 1 argument in VecAdd if
                # evaluate=True
                return args[0]

        obj = AssocOp.__new__(cls, *args, evaluate=evaluate)
        obj = _sanitize_args(obj)

        # print("VecAdd OBJ", obj.func, obj)
        if not isinstance(obj, cls):
            return obj

        # are there any scalars or vectors?
        any_vectors = any([a.is_Vector for a in obj.args])
        all_vectors = all([a.is_Vector for a in obj.args])

        # addition of mixed scalars and vectors is not supported.
        # If there are scalars in the addition, either all arguments
        # are scalars (hence not a vector expression) or there are
        # mixed arguments, hence throw an error
        obj.is_Vector = all_vectors

        if (any_vectors and (not all_vectors)):
            asd = obj.args[1]
            print("####", asd.is_Vector, asd.args)
            print("####", [a.is_Vector for a in asd.args])
            for a in postorder_traversal(asd):
                print(a.func, a.is_Vector, a)
            raise TypeError("VecAdd: Mix of Vector and Scalar symbols:\n\t" +
                            "\n\t".join(
                                str(a.func) + ", " + str(a.is_Vector) + ", " +
                                str(a) for a in obj.args))
        return obj
Esempio n. 4
0
 def _compute_transform(self, F, s, x, **hints):
     from sympy import postorder_traversal
     global _allowed
     if _allowed is None:
         from sympy import (exp, gamma, sin, cos, tan, cot, cosh, sinh, tanh,
                            coth, factorial, rf)
         _allowed = set([exp, gamma, sin, cos, tan, cot, cosh, sinh, tanh, coth,
                         factorial, rf])
     for f in postorder_traversal(F):
         if f.is_Function and f.has(s) and f.func not in _allowed:
             raise IntegralTransformError('Inverse Mellin', F,
                                  'Component %s not recognised.' % f)
     strip = self.fundamental_strip
     return _inverse_mellin_transform(F, s, x, strip, **hints)
Esempio n. 5
0
 def _compute_transform(self, F, s, x, **hints):
     from sympy import postorder_traversal
     global _allowed
     if _allowed is None:
         from sympy import (exp, gamma, sin, cos, tan, cot, cosh, sinh,
                            tanh, coth, factorial, rf)
         _allowed = set([
             exp, gamma, sin, cos, tan, cot, cosh, sinh, tanh, coth,
             factorial, rf
         ])
     for f in postorder_traversal(F):
         if f.is_Function and f.has(s) and f.func not in _allowed:
             raise IntegralTransformError(
                 'Inverse Mellin', F, 'Component %s not recognised.' % f)
     strip = self.fundamental_strip
     return _inverse_mellin_transform(F, s, x, strip, **hints)
def expr_to_postfix(expr, mul_add_arity_fixed=False):
    """
    Returns postorder traversal (i.e. in polish notation) of the symbolic expression
    """

    post = []
    post_arity = []
    for expr_node in snp.postorder_traversal(expr):
        if expr_node.func.is_symbol:
            post.append(expr_node.name)
            post_arity.append(len(expr_node.args))

        elif expr_node.is_Function or expr_node.is_Add or expr_node.is_Mul or expr_node.is_Pow:
            if mul_add_arity_fixed and (expr_node.is_Add or expr_node.is_Mul):
                for i in range(len(expr_node.args) - 1):
                    post.append(type(expr_node).__name__)
                    post_arity.append(2)
            else:
                post.append(type(expr_node).__name__)
                post_arity.append(len(expr_node.args))
        elif expr_node.is_constant():
            post.append(float(expr_node))
            post_arity.append(len(expr_node.args))
    return post, post_arity
Esempio n. 7
0
 def symbolic_norm(C):
     """
     Get "norm" of sympy expression to characterize complexity of complexity of C
     """
     return sum(not(S.is_Atom) for S in sympy.postorder_traversal(C))
Esempio n. 8
0
def all_symbols(expr):
    for sub_expr in postorder_traversal(expr):
        if hasattr(sub_expr, 'is_symbol') and sub_expr.is_symbol:
            yield str(sub_expr)
Esempio n. 9
0
def general_symbolic(target, eqn=None, arg_map=None):
    r'''
    A general function to interpret a sympy equation and evaluate the linear
    components of the source term.

    Parameters
    ----------
    target : OpenPNM object
        The OpenPNM object where the result will be applied.

    eqn : sympy symbolic expression for the source terms
        e.g. y = a*x**b + c

    arg_map : Dict mapping the symbols in the expression to OpenPNM data
        on the target. Must contain 'x' which is the independent variable.
        e.g. arg_map={'a':'pore.a', 'b':'pore.b', 'c':'pore.c', 'x':'pore.x'}

    Example
    ----------
    >>> import openpnm as op
    >>> from openpnm.models.physics import generic_source_term as gst
    >>> import scipy as sp
    >>> import sympy
    >>> pn = op.network.Cubic(shape=[5, 5, 5], spacing=0.0001)
    >>> water = op.phases.Water(network=pn)
    >>> water['pore.a'] = 1
    >>> water['pore.b'] = 2
    >>> water['pore.c'] = 3
    >>> water['pore.x'] = sp.random.random(water.Np)
    >>> a, b, c, x = sympy.symbols('a,b,c,x')
    >>> y = a*x**b + c
    >>> arg_map = {'a':'pore.a', 'b':'pore.b', 'c':'pore.c', 'x':'pore.x'}
    >>> water.add_model(propname='pore.general',
    ...                 model=gst.general_symbolic,
    ...                 eqn=y, arg_map=arg_map,
    ...                 regen_mode='normal')
    >>> assert 'pore.general.rate' in water.props()
    >>> assert 'pore.general.S1' in water.props()
    >>> assert 'pore.general.S1' in water.props()
    '''
    # First make sure all the symbols have been allocated dict items
    for arg in postorder_traversal(eqn):
        if srepr(arg)[:6] == 'Symbol':
            key = srepr(arg)[7:].strip('(').strip(')').strip("'")
            if key not in arg_map.keys():
                raise Exception('argument mapping incomplete, missing '+key)
    if 'x' not in arg_map.keys():
        raise Exception('argument mapping must contain "x" for the ' +
                        'independent variable')
    # Get the data
    data = {}
    args = {}
    for key in arg_map.keys():
        data[key] = target[arg_map[key]]
        # Callable functions
        args[key] = symbols(key)
    r, s1, s2 = _build_func(eqn, **args)
    r_val = r(*data.values())
    s1_val = s1(*data.values())
    s2_val = s2(*data.values())
    values = {'S1': s1_val, 'S2': s2_val, 'rate': r_val}
    return values
Esempio n. 10
0
def general_symbolic(target, eqn=None, arg_map=None):
    r'''
    A general function to interpret a sympy equation and evaluate the linear
    components of the source term.

    Parameters
    ----------
    target : OpenPNM object
        The OpenPNM object where the result will be applied.

    eqn : sympy symbolic expression for the source terms
        e.g. y = a*x**b + c

    arg_map : Dict mapping the symbols in the expression to OpenPNM data
        on the target. Must contain 'x' which is the independent variable.
        e.g. arg_map={'a':'pore.a', 'b':'pore.b', 'c':'pore.c', 'x':'pore.x'}

    Example
    ----------
    >>> import openpnm as op
    >>> from openpnm.models.physics import generic_source_term as gst
    >>> import scipy as sp
    >>> import sympy as _syp
    >>> pn = op.network.Cubic(shape=[5, 5, 5], spacing=0.0001)
    >>> water = op.phases.Water(network=pn)
    >>> water['pore.a'] = 1
    >>> water['pore.b'] = 2
    >>> water['pore.c'] = 3
    >>> water['pore.x'] = sp.random.random(water.Np)
    >>> a, b, c, x = _syp.symbols('a,b,c,x')
    >>> y = a*x**b + c
    >>> arg_map = {'a':'pore.a', 'b':'pore.b', 'c':'pore.c', 'x':'pore.x'}
    >>> water.add_model(propname='pore.general',
    ...                 model=gst.general_symbolic,
    ...                 eqn=y, arg_map=arg_map,
    ...                 regen_mode='normal')
    >>> assert 'pore.general.rate' in water.props()
    >>> assert 'pore.general.S1' in water.props()
    >>> assert 'pore.general.S1' in water.props()
    '''
    # First make sure all the symbols have been allocated dict items
    for arg in _syp.postorder_traversal(eqn):
        if _syp.srepr(arg)[:6] == 'Symbol':
            key = _syp.srepr(arg)[7:].strip('(').strip(')').strip("'")
            if key not in arg_map.keys():
                raise Exception('argument mapping incomplete, missing '+key)
    if 'x' not in arg_map.keys():
        raise Exception('argument mapping must contain "x" for the ' +
                        'independent variable')
    # Get the data
    data = {}
    args = {}
    for key in arg_map.keys():
        data[key] = target[arg_map[key]]
        # Callable functions
        args[key] = _syp.symbols(key)
    r, s1, s2 = _build_func(eqn, **args)
    r_val = r(*data.values())
    s1_val = s1(*data.values())
    s2_val = s2(*data.values())
    values = {'S1': s1_val, 'S2': s2_val, 'rate': r_val}
    return values
Esempio n. 11
0
    def __boolean_rule_decode__(self, variable, expression):

        # Results of sympy's expression parsing:
        # gene = X and 1 => X
        # gene = X or 1 => 1 (sympy's BooleanTrue)
        # gene = X and 0 => 0 (sympy's BooleanFalse)
        # gene = X or 0 => X
        # gene = 1 => 1 (sympy's one)
        # gene = 0 => 0 (sympy's zero)
        # gene = X > 10 => (X, 1 (sympy's number)), namely two args

        # if expression is atom and defines a variable always On or Off, add a On/Off row
        if expression.is_Atom:

            if expression.is_Boolean or expression.is_Number:

                if isinstance(expression, BooleanFalse) or isinstance(
                        expression, Zero):

                    # add row and set mip bounds to 0;0
                    self.__add_row__([(variable, 1)], a_ub=0)
                    return

                elif isinstance(expression, BooleanTrue) or isinstance(
                        expression, One):

                    # add row and set mip bounds to 1;1
                    self.__add_row__([(variable, 1)], a_lb=1)
                    return

                else:
                    print("Either the target result is undetermined or "
                          "something is wrong with expression: {}".format(
                              str(expression)))

                    # add row and set mip bounds to 0;1
                    self.__add_row__([(variable, 1)])
                    return

            # elif expression.is_Number:
            #
            #     if isinstance(expression, Zero):
            #
            #         # add row and set mip bounds to 0;0
            #         self.__add_row__([(variable, 1)], a_ub=0)
            #         return
            #
            #     elif isinstance(expression, One):
            #
            #         # add row and set mip bounds to 1;1
            #         self.__add_row__([(variable, 1)], a_lb=1)
            #         return
            #
            #     else:
            #         print("Either the target result is undetermined or "
            #               "something is wrong with expression: {}".format(str(expression)))
            #
            #         # add row and set mip bounds to 0;1
            #         self.__add_row__([(variable, 1)])
            #         return

            else:

                # Else it must be a symbol or nothing
                # The rest of the function can handle it
                pass

        traversal_results = {}
        last_index = 0

        # postorder_traversal recursively iterates an expression in the reverse order
        # e.g. expr = A and (B or C)
        # list(postorder_traversal(expr)) # [C, B, A, B | C, A & (B | C)]
        for arg in postorder_traversal(expression):

            if isinstance(arg, Or):

                # Following Boolean algebra, an Or (a = b or c) can be translated as: a = b + c - b*c
                # Alternatively, an Or can be written as lb < b + c - a < ub

                # So, for the mid term expression a = b or c
                # We have therefore the equation: -2 <= 2*b + 2*c – 4*a <= 1

                # add Or variable / column
                # or_col_idx = self.__add_column__('mid_term_' + str(self.A.shape[1]))
                or_col_idx = self.__add_column__('mid_term_' +
                                                 str(len(self.A[0])))

                # Or left and right operators
                op_l = traversal_results[arg.args[0]]
                op_r = traversal_results[arg.args[1]]

                # add Or row and set mip bounds to -2;1
                self.__add_row__([(or_col_idx, -4), (op_l, 2), (op_r, 2)],
                                 a_lb=-2,
                                 a_ub=1)
                traversal_results[arg] = or_col_idx
                last_index = or_col_idx

                # building a nested Or subexpression
                for sub_arg in range(2, len(arg.args)):
                    # add Or variable / column
                    # or_col_idx = self.__add_column__('mid_term_' + str(self.A.shape[1]))
                    or_col_idx = self.__add_column__('mid_term_' +
                                                     str(len(self.A[0])))

                    # Or left (last Or) and right operators
                    op_l = traversal_results[arg]
                    op_r = traversal_results[arg.args[sub_arg]]

                    # add Or row and set mip bounds to -2;1
                    self.__add_row__([(or_col_idx, -4), (op_l, 2), (op_r, 2)],
                                     a_lb=-2,
                                     a_ub=1)
                    traversal_results[arg] = or_col_idx
                    last_index = or_col_idx

            elif isinstance(arg, And):

                # Following Boolean algebra, an And (a = b and c) can be translated as: a = b*c
                # Alternatively, an And can be written as lb < b + c - a < ub

                # So, for the mid term expression a = b and c
                # We have therefore the equation: -1 <= 2*b + 2*c – 4*a <= 3

                # add And variable / column
                # and_col_idx = self.__add_column__('mid_term_' + str(self.A.shape[1]))
                and_col_idx = self.__add_column__('mid_term_' +
                                                  str(len(self.A[0])))

                # And left and right operators
                op_l = traversal_results[arg.args[0]]
                op_r = traversal_results[arg.args[1]]

                # add And row and set mip bounds to -1;3
                self.__add_row__([(and_col_idx, -4), (op_l, 2), (op_r, 2)],
                                 a_lb=-1,
                                 a_ub=3)
                traversal_results[arg] = and_col_idx
                last_index = and_col_idx

                # building a nested And subexpression
                for sub_arg in range(2, len(arg.args)):
                    # add And variable / column
                    # and_col_idx = self.__add_column__('mid_term_' + str(self.A.shape[1]))
                    and_col_idx = self.__add_column__('mid_term_' +
                                                      str(len(self.A[0])))

                    # And left (last And) and right operators
                    op_l = traversal_results[arg]
                    op_r = traversal_results[arg.args[sub_arg]]

                    # add Or row and set mip bounds to -2;1
                    self.__add_row__([(and_col_idx, -4), (op_l, 2), (op_r, 2)],
                                     a_lb=-1,
                                     a_ub=3)
                    traversal_results[arg] = and_col_idx
                    last_index = and_col_idx

            elif isinstance(arg, Not):

                # Following Boolean algebra, an Not (a = not b) can be translated as: a = 1 - b
                # Alternatively, an Not can be written as a + b = 1

                # So, for the mid term expression a = not b
                # We have therefore the equation: 1 < a + b < 1

                # add Not variable / column
                # not_col_idx = self.__add_column__('mid_term_' + str(self.A.shape[1]))
                not_col_idx = self.__add_column__('mid_term_' +
                                                  str(len(self.A[0])))

                # Not right operators
                op_r = traversal_results[arg.args[0]]

                # add Not row and set mip bounds to 1;1
                self.__add_row__([(not_col_idx, 1), (op_r, 1)], a_lb=1)
                traversal_results[arg] = not_col_idx
                last_index = not_col_idx

            elif isinstance(arg, StrictGreaterThan) or isinstance(
                    arg, GreaterThan):

                # Following Propositional logic, a predicate (a => r > value) can be translated as: r - value > 0
                # Alternatively, flux predicate a => r>value can be a(value + tolerance - r_UB) + r < value + tolerance
                # & a(r_LB - value - tolerance) + r > r_LB

                # So, for the mid term expression a => r > value
                # We have therefore the equations: a(value + tolerance - r_UB) + r < value + tolerance
                # & a(r_LB - value - tolerance) + r > r_LB

                # In matlab: c * (Vmax - const) + v <= Vmax
                # In matlab: const <= c * (const - Vmin) + v

                # In matlab: compareVal = -compareVal - epsilon
                # In matlab: matrix_values = [vmax - compare_vale, 1] (-inf, vmax)
                # In matlab: matrix_values = [compare_vale - vmin, 1] (compareVal, inf)

                # add Greater variable / column
                # greater_col_idx = self.__add_column__('mid_term_' + str(self.A.shape[1]))
                greater_col_idx = self.__add_column__('mid_term_' +
                                                      str(len(self.A[0])))

                # Greater left operators
                # op_l can be growth, ph, ...
                # otherwise, it can be a reaction or a boundary reaction associated with a metabolite
                # Either way, they should be already in the matrix

                if arg.args[0].is_Symbol:
                    op_l = traversal_results[arg.args[0]]
                    c_val = arg.args[1]

                else:
                    op_l = traversal_results[arg.args[1]]
                    c_val = arg.args[0]

                _lb, _ub = self.lbs[op_l], self.ubs[op_l]

                # add Greater row (a(value + tolerance - r_UB) + r < value + tolerance) and set mip bounds to
                # -inf;comparison_val
                self.__add_row__([(greater_col_idx, c_val + _SRFBA_TOL - _ub),
                                  (op_l, 1)],
                                 a_lb=-999999999,
                                 a_ub=c_val + _SRFBA_TOL)
                # self.__add_row__([(greater_col_idx, _ub + c_val), (op_l, 1)], a_lb=-999999, a_ub=_ub)

                # add Greater row (a(r_LB - value - tolerance) + r > r_LB) and set mip bounds to lb;inf
                self.__add_row__([(greater_col_idx, _lb - c_val - _SRFBA_TOL),
                                  (op_l, 1)],
                                 a_lb=_lb,
                                 a_ub=999999999)
                # self.__add_row__([(greater_col_idx, - c_val - _lb), (op_l, 1)], a_lb=-c_val, a_ub=999999)

                traversal_results[arg] = greater_col_idx
                last_index = greater_col_idx

            elif isinstance(arg, StrictLessThan) or isinstance(arg, LessThan):

                # Following Propositional logic, a predicate (a => r < value) can be translated as: r - value < 0
                # Alternatively, flux predicate a => r<value can be a(value + tolerance - r_LB) + r > value + tolerance
                # & a(r_UB - value - tolerance) + r < r_UB

                # So, for the mid term expression a => r > value
                # We have therefore the equations: a(value + tolerance - r_LB) + r > value + tolerance
                # & a(r_UB - value - tolerance) + r < r_UB

                # In matlab: c * (const - Vmax) + v <= const
                # In matlab: Vmin <= c * (Vmin - const) + v

                # In matlab: compareVal = -compareVal + epsilon
                # In matlab: matrix_values = [compareVal-vmax, 1] (-inf, compareVal)
                # In matlab: matrix_values = [vmin-compareVal, 1] (vmin, inf)

                # add Less variable / column
                # less_col_idx = self.__add_column__('mid_term_' + str(self.A.shape[1]))
                less_col_idx = self.__add_column__('mid_term_' +
                                                   str(len(self.A[0])))

                # Less left operators
                # op_l can be growth, ph, ...
                # otherwise, it can be a reaction or a boundary reaction associated with a metabolite
                # Either way, they should be already in the matrix

                if arg.args[0].is_Symbol:
                    op_l = traversal_results[arg.args[0]]
                    c_val = arg.args[1]

                else:
                    op_l = traversal_results[arg.args[1]]
                    c_val = arg.args[0]

                _lb, _ub = self.lbs[op_l], self.ubs[op_l]

                # add Less row (a(value + tolerance - r_LB) + r > value + tolerance) and set mip bounds to
                # -inf;-comparison_val
                self.__add_row__([(less_col_idx, c_val + _SRFBA_TOL - _lb),
                                  (op_l, 1)],
                                 a_lb=c_val + _SRFBA_TOL,
                                 a_ub=999999999)
                # self.__add_row__([(less_col_idx, -c_val - _ub), (op_l, 1)], a_lb=-999999, a_ub=-c_val)

                # add Less row (a(r_UB - value - tolerance) + r < r_UB) and set mip bounds to lb;inf
                self.__add_row__([(less_col_idx, _ub - c_val - _SRFBA_TOL),
                                  (op_l, 1)],
                                 a_lb=-999999999,
                                 a_ub=_ub)
                # self.__add_row__([(less_col_idx, _lb + c_val), (op_l, 1)], a_lb=_lb, a_ub=999999)

                traversal_results[arg] = less_col_idx
                last_index = less_col_idx

            else:

                # If the argument is not an And, Or, Not or Relational
                # it must be a symbol or a number from the flux predicates

                # If it is a symbol, it must be added to the matrix
                if arg.is_Symbol:

                    # However, some things should be handle before adding the variable:

                    # special case of ph
                    # ph can be treated as a reaction
                    # as other reactions, the lower and upper bounds can be set to the initial state or vary between
                    # 0 and 14
                    # the row bounds (a_lb and a_ub) must be equal to zero as it is done on the reactions
                    if arg.name.lower() == 'ph':

                        if arg.name in self.initial_state:
                            arg_idx = self.__add_column__(
                                arg.name,
                                self.initial_state[arg.name],
                                self.initial_state[arg.name],
                                v_type='continuous')
                            traversal_results[arg] = arg_idx
                            last_index = arg_idx

                        else:
                            arg_idx = self.__add_column__(arg.name,
                                                          0,
                                                          14,
                                                          v_type='continuous')
                            traversal_results[arg] = arg_idx
                            last_index = arg_idx

                    # special case of growth (always positive)
                    # growth can be treated as a reaction
                    # as other reactions, the lower and upper bounds can be set to the initial state or vary between
                    # 0.1 and infinite (always positive)
                    # the row bounds (a_lb and a_ub) must be equal to zero as it is done on the reactions
                    elif arg.name.lower() == 'growth':

                        if arg.name in self.initial_state:
                            arg_idx = self.__add_column__(
                                arg.name,
                                self.initial_state[arg.name],
                                self.initial_state[arg.name],
                                v_type='continuous')
                            traversal_results[arg] = arg_idx
                            last_index = arg_idx

                        else:
                            arg_idx = self.__add_column__(arg.name,
                                                          0 + _SRFBA_TOL,
                                                          999999,
                                                          v_type='continuous')
                            traversal_results[arg] = arg_idx
                            last_index = arg_idx

                    else:

                        var_id = arg.name

                        if var_id in self._aliases_map:
                            var_id = self._aliases_map[var_id]

                        if var_id in self.metabolic_regulatory_reactions:

                            # if the arg is a reaction, the real reaction index should be returned
                            reaction = self._metabolic_regulatory_reactions[
                                var_id].cbm_model_id

                            rxn_idx = self.__add_column__(reaction)
                            traversal_results[arg] = rxn_idx
                            last_index = rxn_idx

                        elif var_id in self.metabolic_regulatory_metabolites:

                            # if the arg is a metabolite, the associated reaction index should be returned

                            reaction = self.cbm_simulation_interface.get_boundary_reaction(
                                self._metabolic_regulatory_metabolites[
                                    arg.name].cbm_model_id)

                            if not reaction:
                                # The metabolite does not have a reaction associated with it. This is bad sign though
                                reaction = var_id

                            rxn_idx = self.__add_column__(reaction)
                            traversal_results[arg] = rxn_idx
                            last_index = rxn_idx

                        elif var_id in self.targets:
                            # if the arg is in targets only the column is added, as in the next iterations the row
                            # will be created.

                            tg_idx = self.__add_column__(var_id)
                            traversal_results[arg] = tg_idx
                            last_index = tg_idx

                        else:

                            # if the args of a sympy's expression are regulators or genes,
                            # which are not defined in self.targets or self.reactions, they will never be created
                            # elsewhere they must be added to the MILP matrix as columns
                            # The state can be inferred from the initial state if the variables are in the initial
                            # state else, the variables are considered as unknown

                            if var_id in self.initial_state:

                                arg_idx = self.__add_column__(
                                    var_id, self.initial_state[var_id],
                                    self.initial_state[var_id])
                                traversal_results[arg] = arg_idx
                                last_index = arg_idx

                            else:
                                arg_idx = self.__add_column__(var_id)
                                traversal_results[arg] = arg_idx
                                last_index = arg_idx

        # add gene row which means that the gene variable in the mip matrix is associated with the last mid term
        # expression, namely the whole expression
        # set mip bounds to 0;0
        self.__add_row__([(variable, 1), (last_index, -1)], a_ub=0)
        return