Source code for cutcutcodec.core.compilation.parse

"""Extracting information from string."""

import math
import numbers
import tokenize
from fractions import Fraction

from sympy.core.basic import Basic
from sympy.core.symbol import Symbol
from sympy.core.sympify import SympifyError, sympify
from sympy.parsing.sympy_parser import implicit_multiplication, parse_expr, standard_transformations


[docs] def parse_to_number(number: str | numbers.Real) -> Fraction | float: """Convert the number into fraction, or inf float. Raises ------ ValueError If is not correct. Examples -------- >>> import math >>> import numpy as np >>> from cutcutcodec.core.compilation.parse import parse_to_number >>> parse_to_number("0") Fraction(0, 1) >>> parse_to_number("2/3") Fraction(2, 3) >>> parse_to_number("-1e-3") Fraction(-1, 1000) >>> parse_to_number(1) Fraction(1, 1) >>> parse_to_number(1.0) Fraction(1, 1) >>> parse_to_number("inf") inf >>> parse_to_number("oo") inf >>> parse_to_number(math.inf) inf >>> parse_to_number("1k") Fraction(1000, 1) >>> parse_to_number("2.3M") Fraction(2300000, 1) >>> """ if isinstance(number, str): number = number.replace("k", "e3").replace("M", "e6") try: return Fraction(number) except ValueError as err_frac: number = number.replace("oo", "inf") try: return float(number) except ValueError as err_float: raise err_float from err_frac if isinstance(number, numbers.Real): try: return Fraction(number) except OverflowError: return math.inf if number > 0 else -math.inf raise TypeError(f"only str and numbers type can be cast, not {number.__class__.__name__}")
[docs] def parse_to_sympy( expr: str | Basic | numbers.Complex, symbols: dict[str, Symbol] = None, ) -> Basic: """Convert the expression in sympy compilable expression. Parameters ---------- expr : str or sympy.Expr The string representation of the equation. Some operators like multiplication can be implicit. symbols : dict[str, sympy.Symbol] A dictionary of local variables to use when parsing. Returns ------- sympy.core.expr.Expr The version sympy of the expression. Raises ------ SyntaxError If the entered expression does not allow to properly define an equation. Examples -------- >>> from cutcutcodec.core.compilation.parse import parse_to_sympy >>> parse_to_sympy(0) 0 >>> parse_to_sympy("1/2 + 1/2*cos(2pi(t - i*j))") 1*cos(2*pi*(-i*j + t))/2 + 1/2 >>> """ if symbols is not None: assert isinstance(symbols, dict), symbols.__class__.__name__ assert all(isinstance(k, str) for k in symbols), symbols if isinstance(expr, str): if not expr: raise SyntaxError("impossible to parse an empty expr") transformations = standard_transformations + (implicit_multiplication,) try: expr = parse_expr( expr, local_dict=symbols, transformations=transformations, evaluate=False, ) except (SympifyError, tokenize.TokenError, TypeError) as err: raise SyntaxError(f"failed to parse {expr}") from err elif isinstance(expr, numbers.Complex): expr = sympify(expr, locals=symbols, evaluate=True) if not isinstance(expr, Basic): raise SyntaxError(f"need to be expression, not {expr.__class__.__name__}") try: str(expr) except AttributeError as err: # ex "1+()" raise SyntaxError("expression parsing is corrupted") from err return expr