Example #1
0
    def get_f_expressions(self, substitute_vars=None):
        if self.f_expr is None:
            return []
        self._substitute(self.f_expr, self.expressions, substitute_vars=substitute_vars)

        return_expressions = []
        # the derivative expression
        dif_eq_code = self.f_expr.get_code(subs=True)
        return_expressions.append(Expression(f'_df{self.var_name}_dt', dif_eq_code))
        # needed variables
        need_vars = tools.get_identifiers(dif_eq_code)
        # get the total return expressions
        for expr in self.expressions[::-1]:
            if expr.var_name in need_vars:
                if expr.substituted_code is None:
                    code = expr.code
                else:
                    code = expr.substituted_code
                return_expressions.append(Expression(expr.var_name, code))
                need_vars |= tools.get_identifiers(code)
        return return_expressions[::-1]
Example #2
0
def contain_unknown_symbol(expr, scope):
    """Examine where the given expression ``expr`` has the unknown symbol in ``scope``.

    Returns
    -------
    res : bool
        True or False.
    """
    ids = tools.get_identifiers(expr)
    for id_ in ids:
        if '.' in id_:
            prefix = id_.split('.')[0].strip()
            if prefix not in scope:
                return True
        if id_ not in scope:
            return True
    return False
Example #3
0
def separate_variables(func_or_code):
    """Separate the expressions in a differential equation for each variable.

    For example, take the HH neuron model as an example:

    >>> eq_code = '''
    >>> def integral(m, h, t, Iext, V):
    >>>    alpha = 0.1 * (V + 40) / (1 - np.exp(-(V + 40) / 10))
    >>>    beta = 4.0 * np.exp(-(V + 65) / 18)
    >>>    dmdt = alpha * (1 - m) - beta * m
    >>>
    >>>    alpha = 0.07 * np.exp(-(V + 65) / 20.)
    >>>    beta = 1 / (1 + np.exp(-(V + 35) / 10))
    >>>    dhdt = alpha * (1 - h) - beta * h
    >>>    return dmdt, dhdt
    >>> '''
    >>> analyser = DiffEqReader()
    >>> analyser.visit(ast.parse(eq_code))
    >>> separate_variables(returns=analyser.returns,
    >>>                    variables=analyser.variables,
    >>>                    right_exprs=analyser.rights,
    >>>                    code_lines=analyser.code_lines)
    {'dhdt': ['alpha = 0.07 * np.exp(-(V + 65) / 20.0)\n',
              'beta = 1 / (1 + np.exp(-(V + 35) / 10))\n',
              'dhdt = alpha * (1 - h) - beta * h\n'],
     'dmdt': ['alpha = 0.1 * (V + 40) / (1 - np.exp(-(V + 40) / 10))\n',
              'beta = 4.0 * np.exp(-(V + 65) / 18)\n',
              'dmdt = alpha * (1 - m) - beta * m\n']}

    Parameters
    ----------
    func_or_code : callable, str
        The callable function or the function code.

    Returns
    -------
    anlysis : dict
        The expressions for each return variable.
    """
    if callable(func_or_code):
        func_or_code = tools.deindent(inspect.getsource(func_or_code))
    assert isinstance(func_or_code, str)
    analyser = DiffEqReader()
    analyser.visit(ast.parse(func_or_code))

    returns = analyser.returns
    variables = analyser.variables
    right_exprs = analyser.rights
    code_lines = analyser.code_lines

    return_requires = OrderedDict([(r, set(tools.get_identifiers(r))) for r in returns])
    code_lines_for_returns = OrderedDict([(r, []) for r in returns])
    variables_for_returns = OrderedDict([(r, []) for r in returns])
    expressions_for_returns = OrderedDict([(r, []) for r in returns])

    length = len(variables)
    reverse_ids = list(reversed([i - length for i in range(length)]))
    for r in code_lines_for_returns.keys():
        for rid in reverse_ids:
            dep = []
            for v in variables[rid]:
                if v in return_requires[r]:
                    dep.append(v)
            if len(dep):
                code_lines_for_returns[r].append(code_lines[rid])
                variables_for_returns[r].append(variables[rid])
                expr = right_exprs[rid]
                expressions_for_returns[r].append(expr)
                for d in dep:
                    return_requires[r].remove(d)
                return_requires[r].update(tools.get_identifiers(expr))
    for r in list(code_lines_for_returns.keys()):
        code_lines_for_returns[r] = code_lines_for_returns[r][::-1]
        variables_for_returns[r] = variables_for_returns[r][::-1]
        expressions_for_returns[r] = expressions_for_returns[r][::-1]

    analysis = tools.DictPlus(
        code_lines_for_returns=code_lines_for_returns,
        variables_for_returns=variables_for_returns,
        expressions_for_returns=expressions_for_returns,
    )
    return analysis
Example #4
0
def separate_variables(func_or_code):
    """Separate the expressions in a differential equation for each variable.

  For example, take the HH neuron model as an example:

  >>> eq_code = '''
  >>> def derivative(V, m, h, n, t, C, gNa, ENa, gK, EK, gL, EL, Iext):
  >>>     alpha = 0.1 * (V + 40) / (1 - bp.math.exp(-(V + 40) / 10))
  >>>     beta = 4.0 * bp.math.exp(-(V + 65) / 18)
  >>>     dmdt = alpha * (1 - m) - beta * m
  >>>
  >>>     alpha = 0.07 * bp.math.exp(-(V + 65) / 20.)
  >>>     beta = 1 / (1 + bp.math.exp(-(V + 35) / 10))
  >>>     dhdt = alpha * (1 - h) - beta * h
  >>>
  >>>     alpha = 0.01 * (V + 55) / (1 - bp.math.exp(-(V + 55) / 10))
  >>>     beta = 0.125 * bp.math.exp(-(V + 65) / 80)
  >>>     dndt = alpha * (1 - n) - beta * n
  >>>
  >>>     I_Na = (gNa * m ** 3.0 * h) * (V - ENa)
  >>>     I_K = (gK * n ** 4.0) * (V - EK)
  >>>     I_leak = gL * (V - EL)
  >>>     dVdt = (- I_Na - I_K - I_leak + Iext) / C
  >>>
  >>>     return dVdt, dmdt, dhdt, dndt
  >>> '''
  >>> separate_variables(eq_code)
  {'code_lines_for_returns': {'dVdt': ['I_Na = gNa * m ** 3.0 * h * (V - ENa)\n',
                                       'I_K = gK * n ** 4.0 * (V - EK)\n',
                                       'I_leak = gL * (V - EL)\n',
                                       'dVdt = (-I_Na - I_K - I_leak + Iext) / C\n'],
                              'dhdt': ['alpha = 0.07 * bp.math.exp(-(V + 65) / 20.0)\n',
                                       'beta = 1 / (1 + bp.math.exp(-(V + 35) / 10))\n',
                                       'dhdt = alpha * (1 - h) - beta * h\n'],
                              'dmdt': ['alpha = 0.1 * (V + 40) / (1 - '
                                       'bp.math.exp(-(V + 40) / 10))\n',
                                       'beta = 4.0 * bp.math.exp(-(V + 65) / 18)\n',
                                       'dmdt = alpha * (1 - m) - beta * m\n'],
                              'dndt': ['alpha = 0.01 * (V + 55) / (1 - '
                                       'bp.math.exp(-(V + 55) / 10))\n',
                                       'beta = 0.125 * bp.math.exp(-(V + 65) / 80)\n',
                                       'dndt = alpha * (1 - n) - beta * n\n']},
   'expressions_for_returns': {'dVdt': ['gNa * m ** 3.0 * h * (V - ENa)',
                                        'gK * n ** 4.0 * (V - EK)',
                                        'gL * (V - EL)',
                                        '(-I_Na - I_K - I_leak + Iext) / C'],
                               'dhdt': ['0.07 * bp.math.exp(-(V + 65) / 20.0)',
                                        '1 / (1 + bp.math.exp(-(V + 35) / 10))',
                                        'alpha * (1 - h) - beta * h'],
                               'dmdt': ['0.1 * (V + 40) / (1 - '
                                        'bp.math.exp(-(V + 40) / 10))',
                                        '4.0 * bp.math.exp(-(V + 65) / 18)',
                                        'alpha * (1 - m) - beta * m'],
                               'dndt': ['0.01 * (V + 55) / (1 - '
                                        'bp.math.exp(-(V + 55) / 10))',
                                        '0.125 * bp.math.exp(-(V + 65) / 80)',
                                        'alpha * (1 - n) - beta * n']},
   'variables_for_returns': {'dVdt': [['I_Na'], ['I_K'], ['I_leak'], ['dVdt']],
                             'dhdt': [['alpha'], ['beta'], ['dhdt']],
                             'dmdt': [['alpha'], ['beta'], ['dmdt']],
                             'dndt': [['alpha'], ['beta'], ['dndt']]}}

  Parameters
  ----------
  func_or_code : callable, str
      The callable function or the function code.

  Returns
  -------
  anlysis : dict
      The expressions for each return variable.
  """
    if callable(func_or_code):
        if tools.is_lambda_function(func_or_code):
            raise errors.AnalyzerError(
                f'Cannot analyze lambda function: {func_or_code}.')
        func_or_code = tools.deindent(inspect.getsource(func_or_code))
    assert isinstance(func_or_code, str)
    analyser = DiffEqReader()
    analyser.visit(ast.parse(func_or_code))

    returns = analyser.returns
    variables = analyser.variables
    right_exprs = analyser.rights
    code_lines = analyser.code_lines

    return_requires = OrderedDict([(r, set(tools.get_identifiers(r)))
                                   for r in returns])
    code_lines_for_returns = OrderedDict([(r, []) for r in returns])
    variables_for_returns = OrderedDict([(r, []) for r in returns])
    expressions_for_returns = OrderedDict([(r, []) for r in returns])

    length = len(variables)
    reverse_ids = list(reversed([i - length for i in range(length)]))
    for r in code_lines_for_returns.keys():
        for rid in reverse_ids:
            dep = []
            for v in variables[rid]:
                if v in return_requires[r]:
                    dep.append(v)
            if len(dep):
                code_lines_for_returns[r].append(code_lines[rid])
                variables_for_returns[r].append(variables[rid])
                expr = right_exprs[rid]
                expressions_for_returns[r].append(expr)
                for d in dep:
                    return_requires[r].remove(d)
                return_requires[r].update(tools.get_identifiers(expr))
    for r in list(code_lines_for_returns.keys()):
        code_lines_for_returns[r] = code_lines_for_returns[r][::-1]
        variables_for_returns[r] = variables_for_returns[r][::-1]
        expressions_for_returns[r] = expressions_for_returns[r][::-1]

    analysis = tools.DictPlus(
        code_lines_for_returns=code_lines_for_returns,
        variables_for_returns=variables_for_returns,
        expressions_for_returns=expressions_for_returns,
    )
    return analysis
Example #5
0
 def identifiers(self):
     return tools.get_identifiers(self.code)