Exemple #1
0
    def __new__(cls, expr, variables, point, **assumptions):
        if not ordered_iter(variables, Tuple):
            variables = [variables]
        variables = Tuple(*sympify(variables))

        if uniq(variables) != variables:
            repeated = repeated = [
                v for v in set(variables) if list(variables).count(v) > 1
            ]
            raise ValueError('cannot substitute expressions %s more than '
                             'once.' % repeated)

        if not ordered_iter(point, Tuple):
            point = [point]
        point = Tuple(*sympify(point))

        if len(point) != len(variables):
            raise ValueError('Number of point values must be the same as '
                             'the number of variables.')

        # it's necessary to use dummy variables internally
        new_variables = Tuple(*[
            arg.as_dummy() if arg.is_Symbol else C.Dummy(str(arg))
            for arg in variables
        ])
        expr = sympify(expr).subs(tuple(zip(variables, new_variables)))

        if expr.is_commutative:
            assumptions['commutative'] = True

        obj = Expr.__new__(cls, expr, new_variables, point, **assumptions)
        return obj
Exemple #2
0
 def __new__(cls, function, limits):
     fun = sympify(function)
     if not ordered_iter(fun) or len(fun) != 2:
         raise ValueError("Function argument should be (x(t), y(t)) but got %s" % str(function))
     if not ordered_iter(limits) or len(limits) != 3:
         raise ValueError("Limit argument should be (t, tmin, tmax) but got %s" % str(limits))
     return GeometryEntity.__new__(cls, tuple(sympify(fun)), tuple(sympify(limits)))
Exemple #3
0
    def __new__(cls, expr, variables, point, **assumptions):
        if not ordered_iter(variables, Tuple):
            variables = [variables]
        variables = Tuple(*sympify(variables))

        if uniq(variables) != variables:
            repeated = repeated = [ v for v in set(variables)
                                    if list(variables).count(v) > 1 ]
            raise ValueError('cannot substitute expressions %s more than '
                             'once.' % repeated)

        if not ordered_iter(point, Tuple):
            point = [point]
        point = Tuple(*sympify(point))

        if len(point) != len(variables):
            raise ValueError('Number of point values must be the same as '
                             'the number of variables.')

        # it's necessary to use dummy variables internally
        new_variables = Tuple(*[ arg.as_dummy() if arg.is_Symbol else
            C.Dummy(str(arg)) for arg in variables ])
        expr = sympify(expr).subs(tuple(zip(variables, new_variables)))

        if expr.is_commutative:
            assumptions['commutative'] = True

        obj = Expr.__new__(cls, expr, new_variables, point, **assumptions)
        return obj
Exemple #4
0
def test_iterable_ordered_iter():
    ordered = [list(), tuple(), Tuple(), Matrix([[]])]
    unordered = [set()]
    not_sympy_iterable = [{}, '', u'']
    assert all(ordered_iter(i) for i in ordered)
    assert all(not ordered_iter(i) for i in unordered)
    assert all(iterable(i) for i in ordered + unordered)
    assert all(not iterable(i) for i in not_sympy_iterable)
    assert all(iterable(i, exclude=None) for i in not_sympy_iterable)
Exemple #5
0
def test_iterable_ordered_iter():
    ordered = [list(), tuple(), Tuple(), Matrix([[]])]
    unordered = [set()]
    not_sympy_iterable = [{}, '']
    assert all(ordered_iter(i) for i in ordered)
    assert all(not ordered_iter(i) for i in unordered)
    assert all(iterable(i) for i in ordered + unordered)
    assert all(not iterable(i) for i in not_sympy_iterable)
    assert all(iterable(i, exclude=None) for i in not_sympy_iterable)
Exemple #6
0
 def __new__(cls, function, limits):
     fun = sympify(function)
     if not ordered_iter(fun) or len(fun) != 2:
         raise ValueError(
             "Function argument should be (x(t), y(t)) but got %s" %
             str(function))
     if not ordered_iter(limits) or len(limits) != 3:
         raise ValueError(
             "Limit argument should be (t, tmin, tmax) but got %s" %
             str(limits))
     return GeometryEntity.__new__(cls, tuple(sympify(fun)),
                                   tuple(sympify(limits)))
Exemple #7
0
    def _interpret_args(args):
        interval_wrong_order = "PlotInterval %s was given before any function(s)."
        interpret_error = "Could not interpret %s as a function or interval."

        functions, intervals = [], []
        if isinstance(args[0], GeometryEntity):
            for coords in list(args[0].arbitrary_point()):
                functions.append(coords)
            intervals.append(PlotInterval.try_parse(args[0].plot_interval()))
        else:
            for a in args:
                i = PlotInterval.try_parse(a)
                if i is not None:
                    if len(functions) == 0:
                        raise ValueError(interval_wrong_order % (str(i)))
                    else:
                        intervals.append(i)
                else:
                    if ordered_iter(a, include=str):
                        raise ValueError(interpret_error % (str(a)))
                    try:
                        f = sympify(a)
                        functions.append(f)
                    except:
                        raise ValueError(interpret_error % str(a))

        return functions, intervals
Exemple #8
0
    def __setitem__(self, i, args):
        """
        Parses and adds a PlotMode to the function
        list.
        """
        if not (isinstance(i, (int, Integer)) and i >= 0):
            raise ValueError("Function index must "
                             "be an integer >= 0.")

        if isinstance(args, PlotObject):
            f = args
        else:
            if (not ordered_iter(args)) or isinstance(args, GeometryEntity):
                args = [args]
            if len(args) == 0:
                return # no arguments given
            kwargs = dict(bounds_callback=self.adjust_all_bounds)
            f = PlotMode(*args, **kwargs)

        if f:
            self._render_lock.acquire()
            self._functions[i] = f
            self._render_lock.release()
        else:
            raise ValueError("Failed to parse '%s'."
                    % ', '.join(str(a) for a in args))
Exemple #9
0
    def __new__(cls, label, range=None, **kw_args):

        if isinstance(label, basestring):
            label = Symbol(label, integer=True)
        label, range = map(sympify, (label, range))

        if not label.is_integer:
            raise TypeError("Idx object requires an integer label")

        elif ordered_iter(range, include=Tuple):
            assert len(range) == 2, "Idx got range tuple with wrong length"
            for bound in range:
                if not (bound.is_integer or abs(bound) is S.Infinity):
                    raise TypeError("Idx object requires integer bounds")
            args = label, Tuple(*range)
        elif isinstance(range, Expr):
            if not (range.is_integer or range is S.Infinity):
                raise TypeError("Idx object requires an integer dimension")
            args = label, Tuple(S.Zero, range - S.One)
        elif range:
            raise TypeError("range must be  tuple or integer sympy expression")
        else:
            args = label,

        obj = Expr.__new__(cls, *args, **kw_args)
        return obj
Exemple #10
0
    def __new__(cls, label, range=None, **kw_args):

        if isinstance(label, basestring):
            label = Symbol(label, integer=True)
        label, range = map(sympify, (label, range))

        if not label.is_integer:
            raise TypeError("Idx object requires an integer label")

        elif ordered_iter(range, include=Tuple):
            assert len(range) == 2, "Idx got range tuple with wrong length"
            for bound in range:
                if not (bound.is_integer or abs(bound) is S.Infinity):
                    raise TypeError("Idx object requires integer bounds")
            args = label, Tuple(*range)
        elif isinstance(range, Expr):
            if not (range.is_integer or range is S.Infinity):
                raise TypeError("Idx object requires an integer dimension")
            args = label, Tuple(S.Zero, range-S.One)
        elif range:
            raise TypeError("range must be  tuple or integer sympy expression")
        else:
            args = label,

        obj = Expr.__new__(cls, *args, **kw_args)
        return obj
Exemple #11
0
    def __setitem__(self, i, args):
        """
        Parses and adds a PlotMode to the function
        list.
        """
        if not (isinstance(i, (int, Integer)) and i >= 0):
            raise ValueError("Function index must " "be an integer >= 0.")

        if isinstance(args, PlotObject):
            f = args
        else:
            if (not ordered_iter(args)) or isinstance(args, GeometryEntity):
                args = [args]
            if len(args) == 0:
                return  # no arguments given
            kwargs = dict(bounds_callback=self.adjust_all_bounds)
            f = PlotMode(*args, **kwargs)

        if f:
            self._render_lock.acquire()
            self._functions[i] = f
            self._render_lock.release()
        else:
            raise ValueError("Failed to parse '%s'." %
                             ', '.join(str(a) for a in args))
Exemple #12
0
    def _interpret_args(args):
        interval_wrong_order = "PlotInterval %s was given before any function(s)."
        interpret_error = "Could not interpret %s as a function or interval."

        functions, intervals = [], []
        if isinstance(args[0], GeometryEntity):
            for coords in list(args[0].arbitrary_point()):
                functions.append(coords)
            intervals.append(PlotInterval.try_parse(args[0].plot_interval()))
        else:
            for a in args:
                i = PlotInterval.try_parse(a)
                if i is not None:
                    if len(functions) == 0:
                        raise ValueError(interval_wrong_order % (str(i)))
                    else:
                        intervals.append(i)
                else:
                    if ordered_iter(a, include=str):
                        raise ValueError(interpret_error % (str(a)))
                    try:
                        f = sympify(a)
                        functions.append(f)
                    except:
                        raise ValueError(interpret_error % str(a))

        return functions, intervals
Exemple #13
0
 def _eval_args(cls, args):
     # _eval_args has the right logic for the controls argument.
     controls = args[0]
     gate = args[1]
     if not ordered_iter(controls):
         controls = (controls, )
     controls = UnitaryOperator._eval_args(controls)
     _validate_targets_controls(chain(controls, gate.targets))
     return (controls, gate)
Exemple #14
0
 def _eval_args(cls, args):
     # _eval_args has the right logic for the controls argument.
     controls = args[0]
     gate = args[1]
     if not ordered_iter(controls, include=Tuple):
         controls = (controls,)
     controls = UnitaryOperator._eval_args(controls)
     _validate_targets_controls(chain(controls,gate.targets))
     return (controls, gate)
Exemple #15
0
    def __new__(cls, label, shape=None, **kw_args):
        if isinstance(label, basestring):
            label = Symbol(label)

        obj = Expr.__new__(cls, label, **kw_args)
        if ordered_iter(shape):
            obj._shape = Tuple(*shape)
        else:
            obj._shape = shape
        return obj
Exemple #16
0
 def __getitem__(self, indices, **kw_args):
     if ordered_iter(indices, include=Tuple):
         # Special case needed because M[*my_tuple] is a syntax error.
         if self.shape and len(self.shape) != len(indices):
             raise IndexException("Rank mismatch")
         return Indexed(self, *indices, **kw_args)
     else:
         if self.shape and len(self.shape) != 1:
             raise IndexException("Rank mismatch")
         return Indexed(self, indices, **kw_args)
Exemple #17
0
    def __new__(cls, label, shape=None, **kw_args):
        if isinstance(label, basestring):
            label = Symbol(label)

        obj = Expr.__new__(cls, label, **kw_args)
        if ordered_iter(shape):
            obj._shape = Tuple(*shape)
        else:
            obj._shape = shape
        return obj
Exemple #18
0
 def __getitem__(self, indices, **kw_args):
     if ordered_iter(indices, include=Tuple):
         # Special case needed because M[*my_tuple] is a syntax error.
         if self.shape and len(self.shape) != len(indices):
             raise IndexException("Rank mismatch")
         return Indexed(self, *indices, **kw_args)
     else:
         if self.shape and len(self.shape) != 1:
             raise IndexException("Rank mismatch")
         return Indexed(self, indices, **kw_args)
Exemple #19
0
    def __init__(self, *args, **kwargs):
        # initialize style parameter
        style = kwargs.pop('style', '').lower()

        # allow alias kwargs to override style kwarg
        if kwargs.pop('none', None) is not None: style = 'none'
        if kwargs.pop('frame', None) is not None: style = 'frame'
        if kwargs.pop('box', None) is not None: style = 'box'
        if kwargs.pop('ordinate', None) is not None: style = 'ordinate'

        if style in ['', 'ordinate']:
            self._render_object = PlotAxesOrdinate(self)
        elif style in ['frame', 'box']:
            self._render_object = PlotAxesFrame(self)
        elif style in ['none']:
            self._render_object = None
        else: raise ValueError(("Unrecognized axes "
                                "style %s.") % (style))

        # initialize stride parameter
        stride = kwargs.pop('stride', 0.25)
        try: stride = eval(stride)
        except: pass
        if ordered_iter(stride):
            assert len(stride) == 3
            self._stride = stride
        else:
            self._stride = [stride, stride, stride]
        self._tick_length = float(kwargs.pop('tick_length', 0.1))

        # setup bounding box and ticks
        self._origin = [0,0,0]
        self.reset_bounding_box()

        def flexible_boolean(input, default):
            if input in [True, False]:
                return input
            if input in ['f','F','false','False']: return False
            if input in ['t','T','true','True']: return True
            return default

        # initialize remaining parameters
        self.visible      =  flexible_boolean(kwargs.pop('visible',''), True)
        self._overlay     =  flexible_boolean(kwargs.pop('overlay',''), True)
        self._colored     =  flexible_boolean(kwargs.pop('colored',''), False)
        self._label_axes  =  flexible_boolean(kwargs.pop('label_axes', ''), False)
        self._label_ticks =  flexible_boolean(kwargs.pop('label_ticks', ''), True)

        # setup label font
        self.font_face = kwargs.pop('font_face', 'Arial')
        self.font_size = kwargs.pop('font_size', 28)

        # this is also used to reinit the
        # font on window close/reopen
        self.reset_resources()
Exemple #20
0
 def _set_color(self, v):
     try:
         if v is not None:
             if ordered_iter(v):
                 v = ColorScheme(*v)
             else: v = ColorScheme(v)
         if repr(v) == repr(self._color): return
         self._on_change_color(v)
         self._color = v
     except Exception, e:
         raise RuntimeError(("Color change failed. "
                          "Reason: %s" % (str(e))))
Exemple #21
0
 def _set_color(self, v):
     try:
         if v is not None:
             if ordered_iter(v):
                 v = ColorScheme(*v)
             else:
                 v = ColorScheme(v)
         if repr(v) == repr(self._color): return
         self._on_change_color(v)
         self._color = v
     except Exception, e:
         raise RuntimeError(("Color change failed. "
                             "Reason: %s" % (str(e))))
Exemple #22
0
 def _eval_args(cls, args):
     targets = args[0]
     if not ordered_iter(targets):
         targets = (targets,)
     targets = Gate._eval_args(targets)
     _validate_targets_controls(targets)
     mat = args[1]
     if not isinstance(mat, Matrix):
         raise TypeError("Matrix expected, got: %r" % mat)
     dim = 2 ** len(targets)
     if not all([dim == shape for shape in mat.shape]):
         raise IndexError("Number of targets must match the matrix size: %r %r" % (targets, mat))
     return (targets, mat)
Exemple #23
0
 def _eval_args(cls, args):
     targets = args[0]
     if not ordered_iter(targets):
         targets = (targets, )
     targets = Gate._eval_args(targets)
     _validate_targets_controls(targets)
     mat = args[1]
     if not isinstance(mat, Matrix):
         raise TypeError('Matrix expected, got: %r' % mat)
     dim = 2**len(targets)
     if not all([dim == shape for shape in mat.shape]):
         raise IndexError(
             'Number of targets must match the matrix size: %r %r' %\
             (targets, mat)
         )
     return (targets, mat)
Exemple #24
0
def gosper_sum(f, k):
    """
    Gosper's hypergeometric summation algorithm.

    Given a hypergeometric term ``f`` such that::

    .. math::

        s_n = \sum_{k=0}^{n-1} f_k

    and $f(n)$ doesn't depend on $n$, returns $g_{n} - g(0)$ where
    $g_{n+1} - g_n = f_n$, or ``None`` if $s_n$ can not be expressed
    in closed form as a sum of hypergeometric terms.

    **Examples**

    >>> from sympy.concrete.gosper import gosper_sum
    >>> from sympy.functions import factorial
    >>> from sympy.abc import n, k

    >>> gosper_sum((4*k + 1)*factorial(k)/factorial(2*k + 1), (k, 0, n))
    (-n! + 2*(2*n + 1)!)/(2*n + 1)!

    **References**

    .. [1] Marko Petkovsek, Herbert S. Wilf, Doron Zeilberger, A = B,
           AK Peters, Ltd., Wellesley, MA, USA, 1997, pp. 73--100

    """
    indefinite = False

    if ordered_iter(k):
        k, a, b = k
    else:
        indefinite = True

    g = gosper_term(f, k)

    if g is None:
        return None

    if indefinite:
        result = f*g
    else:
        result = (f*(g+1)).subs(k, b) - (f*g).subs(k, a)

    return factor(result)
Exemple #25
0
def __qsympify_sequence_helper(seq):
    """
       Helper function for _qsympify_sequence
       This function does the actual work.
    """
    #base case. If not a list, do Sympification
    if not ordered_iter(seq):
        if isinstance(seq, Matrix):
            return seq
        elif isinstance(seq, basestring):
            return Symbol(seq)
        else:
            return sympify(seq)

    #if list, recurse on each item in the list
    result = [__qsympify_sequence_helper(item) for item in seq]

    return Tuple(*result)
Exemple #26
0
def line_integrate(field, curve, vars):
    """line_integrate(field, Curve, variables)

       Compute the line integral.

       Examples
       --------
       >>> from sympy import Curve, line_integrate, E, ln
       >>> from sympy.abc import x, y, t
       >>> C = Curve([E**t + 1, E**t - 1], (t, 0, ln(2)))
       >>> line_integrate(x + y, C, [x, y])
       3*2**(1/2)

    """
    F = sympify(field)
    if not F:
        raise ValueError(
            "Expecting function specifying field as first argument.")
    if not isinstance(curve, Curve):
        raise ValueError("Expecting Curve entity as second argument.")
    if not ordered_iter(vars):
        raise ValueError("Expecting ordered iterable for variables.")
    if len(curve.functions) != len(vars):
        raise ValueError("Field variable size does not match curve dimension.")

    if curve.parameter in vars:
        raise ValueError("Curve parameter clashes with field parameters.")

    # Calculate derivatives for line parameter functions
    # F(r) -> F(r(t)) and finally F(r(t)*r'(t))
    Ft = F
    dldt = 0
    for i, var in enumerate(vars):
        _f = curve.functions[i]
        _dn = diff(_f, curve.parameter)
        # ...arc length
        dldt = dldt + (_dn * _dn)
        Ft = Ft.subs(var, _f)
    Ft = Ft * dldt**(S(1) / 2)

    integral = Integral(Ft, curve.limits).doit(deep=False)
    return integral
Exemple #27
0
def _process_limits(*symbols):
    """Convert the symbols-related limits into propert limits,
    storing them as Tuple(symbol, lower, upper). The sign of
    the function is also returned when the upper limit is missing
    so (x, 1, None) becomes (x, None, 1) and the sign is changed.
    """
    limits = []
    sign = 1
    for V in symbols:
        if isinstance(V, Symbol):
            limits.append(Tuple(V))
            continue
        elif ordered_iter(V, Tuple):
            V = sympify(flatten(V))
            if V[0].is_Symbol:
                newsymbol = V[0]
                if len(V) == 2 and isinstance(V[1], Interval):
                    V[1:] = [V[1].start, V[1].end]

                if len(V) == 3:
                    if V[1] is None and V[2] is not None:
                        nlim = [V[2]]
                    elif V[1] is not None and V[2] is None:
                        sign *= -1
                        nlim = [V[1]]
                    elif V[1] is None and V[2] is None:
                        nlim = []
                    else:
                        nlim = V[1:]
                    limits.append(Tuple(newsymbol, *nlim))
                    continue
                elif len(V) == 1 or (len(V) == 2 and V[1] is None):
                    limits.append(Tuple(newsymbol))
                    continue
                elif len(V) == 2:
                    limits.append(Tuple(newsymbol, V[1]))
                    continue

        raise ValueError('Invalid limits given: %s' % str(symbols))

    return limits, sign
Exemple #28
0
def _process_limits(*symbols):
    """Convert the symbols-related limits into propert limits,
    storing them as Tuple(symbol, lower, upper). The sign of
    the function is also returned when the upper limit is missing
    so (x, 1, None) becomes (x, None, 1) and the sign is changed.
    """
    limits = []
    sign = 1
    for V in symbols:
        if isinstance(V, Symbol):
            limits.append(Tuple(V))
            continue
        elif ordered_iter(V, Tuple):
            V = sympify(flatten(V))
            if V[0].is_Symbol:
                newsymbol = V[0]
                if len(V) == 2 and isinstance(V[1], Interval):
                    V[1:] = [V[1].start, V[1].end]

                if len(V) == 3:
                    if V[1] is None and V[2] is not None:
                        nlim = [V[2]]
                    elif V[1] is not None and V[2] is None:
                        sign *= -1
                        nlim = [V[1]]
                    elif V[1] is None and V[2] is None:
                        nlim = []
                    else:
                        nlim = V[1:]
                    limits.append(Tuple(newsymbol, *nlim ))
                    continue
                elif len(V) == 1 or (len(V) == 2 and V[1] is None):
                    limits.append(Tuple(newsymbol))
                    continue
                elif len(V) == 2:
                    limits.append(Tuple(newsymbol, V[1]))
                    continue

        raise ValueError('Invalid limits given: %s' % str(symbols))

    return limits, sign
Exemple #29
0
def line_integrate(field, curve, vars):
    """line_integrate(field, Curve, variables)

       Compute the line integral.

       Examples
       --------
       >>> from sympy import Curve, line_integrate, E, ln
       >>> from sympy.abc import x, y, t
       >>> C = Curve([E**t + 1, E**t - 1], (t, 0, ln(2)))
       >>> line_integrate(x + y, C, [x, y])
       3*2**(1/2)

    """
    F = sympify(field)
    if not F:
        raise ValueError("Expecting function specifying field as first argument.")
    if not isinstance(curve, Curve):
        raise ValueError("Expecting Curve entity as second argument.")
    if not ordered_iter(vars):
        raise ValueError("Expecting ordered iterable for variables.")
    if len(curve.functions) != len(vars):
        raise ValueError("Field variable size does not match curve dimension.")

    if curve.parameter in vars:
        raise ValueError("Curve parameter clashes with field parameters.")

    # Calculate derivatives for line parameter functions
    # F(r) -> F(r(t)) and finally F(r(t)*r'(t))
    Ft = F
    dldt = 0
    for i, var in enumerate(vars):
        _f = curve.functions[i]
        _dn = diff(_f, curve.parameter)
        # ...arc length
        dldt = dldt + (_dn * _dn)
        Ft = Ft.subs(var, _f)
    Ft = Ft * dldt**(S(1)/2)

    integral = Integral(Ft, curve.limits).doit(deep = False)
    return integral
Exemple #30
0
def mplot2d(f, var, show=True):
    """
    Plot a 2d function using matplotlib/Tk.
    """

    import warnings
    warnings.filterwarnings("ignore", "Could not match \S")

    p = import_module('pylab')
    if not p:
        sys.exit("Matplotlib is required to use mplot2d.")

    if not ordered_iter(f):
        f = [f,]

    for f_i in f:
        x, y = sample(f_i, var)
        p.plot(x, y)

    p.draw()
    if show:
        p.show()
Exemple #31
0
    def __new__(cls, term, *symbols, **assumptions):
        term = sympify(term)

        if term.is_Number:
            if term is S.NaN:
                return S.NaN
            elif term is S.Infinity:
                return S.NaN
            elif term is S.NegativeInfinity:
                return S.NaN
            elif term is S.Zero:
                return S.Zero
            elif term is S.One:
                return S.One

        if len(symbols) == 1:
            symbol = symbols[0]

            if isinstance(symbol, C.Equality):
                k = symbol.lhs
                a = symbol.rhs.start
                n = symbol.rhs.end
            elif ordered_iter(symbol):
                k, a, n = symbol
            else:
                raise ValueError("Invalid arguments")

            k, a, n = map(sympify, (k, a, n))

            if isinstance(a, C.Number) and isinstance(n, C.Number):
                return Mul(*[term.subs(k, i) for i in xrange(int(a), int(n)+1)])
        else:
            raise NotImplementedError

        obj = Expr.__new__(cls, **assumptions)
        obj._args = (term, k, a, n)

        return obj
Exemple #32
0
def mplot2d(f, var, show=True):
    """
    Plot a 2d function using matplotlib/Tk.
    """

    import warnings
    warnings.filterwarnings("ignore", "Could not match \S")

    try:
        import pylab as p
    except ImportError:
        raise ImportError("Matplotlib is required to use mplot2d.")

    if not ordered_iter(f):
        f = [f,]

    for f_i in f:
        x, y = sample(f_i, var)
        p.plot(x, y)

    p.draw()
    if show:
        p.show()
Exemple #33
0
    def __init__(self, name, expr, argument_sequence=None):
        """Initialize a Routine instance.

        ``name``
            A string with the name of this routine in the generated code
        ``expr``
            The sympy expression that the Routine instance will represent.  If
            given a list or tuple of expressions, the routine will be
            considered to have multiple return values.
        ``argument_sequence``
            Optional list/tuple containing arguments for the routine in a
            preferred order.  If omitted, arguments will be ordered
            alphabetically, but with all input aguments first, and then output
            or in-out arguments.

        A decision about whether to use output arguments or return values,
        is made depending on the mathematical expressions.  For an expression
        of type Equality, the left hand side is made into an OutputArgument
        (or an InOutArgument if appropriate).  Else, the calculated
        expression is the return values of the routine.

        A tuple of exressions can be used to create a routine with both
        return value(s) and output argument(s).

        """
        arg_list = []

        if ordered_iter(expr):
            if not expr:
                raise ValueError("No expression given")
            expressions = Tuple(*expr)
        else:
            expressions = Tuple(expr)

        # local variables
        local_vars = set([i.label for i in expressions.atoms(Idx)])

        # symbols that should be arguments
        symbols = expressions.atoms(Symbol) - local_vars

        # Decide whether to use output argument or return value
        return_val = []
        output_args = []
        for expr in expressions:
            if isinstance(expr, Equality):
                out_arg = expr.lhs
                expr = expr.rhs
                if isinstance(out_arg, Indexed):
                    dims = tuple([ (S.Zero, dim-1) for dim in out_arg.shape])
                    symbol = out_arg.base.label
                elif isinstance(out_arg, Symbol):
                    dims = []
                    symbol = out_arg
                else:
                    raise CodeGenError("Only Indexed or Symbol can define output arguments")

                if expr.has(symbol):
                    output_args.append(InOutArgument(symbol, out_arg, expr, dimensions=dims))
                else:
                    output_args.append(OutputArgument(symbol, out_arg, expr, dimensions=dims))

                # avoid duplicate arguments
                symbols.remove(symbol)
            else:
                return_val.append(Result(expr))

        # setup input argument list
        array_symbols = {}
        for array in expressions.atoms(Indexed):
            array_symbols[array.base.label] = array

        for symbol in sorted(symbols, key=str):
            if symbol in array_symbols:
                dims = []
                array = array_symbols[symbol]
                for dim in array.shape:
                    dims.append((S.Zero, dim - 1))
                metadata = {'dimensions': dims}
            else:
                metadata = {}

            arg_list.append(InputArgument(symbol, **metadata))

        output_args.sort(key=lambda x:str(x.name))
        arg_list.extend(output_args)

        if argument_sequence is not None:
            # if the user has supplied IndexedBase instances, we'll accept that
            new_sequence = []
            for arg in argument_sequence:
                if isinstance(arg, IndexedBase):
                    new_sequence.append(arg.label)
                else:
                    new_sequence.append(arg)
            argument_sequence = new_sequence

            missing = filter(lambda x: x.name not in argument_sequence, arg_list)
            if missing:
                raise CodeGenArgumentListError("Argument list didn't specify: %s" %
                        ", ".join([str(m.name) for m in missing]), missing)

            # create redundant arguments to produce the requested sequence
            name_arg_dict = dict([(x.name, x) for x in arg_list])
            new_args = []
            for symbol in argument_sequence:
                try:
                    new_args.append(name_arg_dict[symbol])
                except KeyError:
                    new_args.append(InputArgument(symbol))
            arg_list = new_args

        self.name = name
        self.arguments = arg_list
        self.results = return_val
        self.local_vars = local_vars
Exemple #34
0
def solve(f, *symbols, **flags):
    """
    Algebraically solves equations and systems of equations.

        Currently supported are:
            - univariate polynomial,
            - transcendental
            - piecewise combinations of the above
            - systems of linear and polynomial equations
            - sytems containing relational expressions.

        Input is formed as:
            f
                - a single Expr or Poly that must be zero,
                - an Equality
                - a Relational expression or boolean
                - iterable of one or more of the above

            symbols (Symbol, Function or Derivative) specified as
                - none given (all free symbols will be used)
                - single symbol
                - denested list of symbols
                  e.g. solve(f, x, y)
                - ordered iterable of symbols
                  e.g. solve(f, [x, y])

            flags
                - ``simplified``, when False, will not simplify solutions
                                 (default=True except for polynomials of
                                  order 3 or greater)

        The output varies according to the input and can be seen by example:

            >>> from sympy import solve, Poly, Eq, Function, exp
            >>> from sympy.abc import x, y, z, a, b

            o boolean or univariate Relational

                >>> solve(x < 3)
                And(im(x) == 0, re(x) < 3)

            o single expression and single symbol that is in the expression

                >>> solve(x - y, x)
                [y]
                >>> solve(x - 3, x)
                [3]
                >>> solve(Eq(x, 3), x)
                [3]
                >>> solve(Poly(x - 3), x)
                [3]
                >>> solve(x**2 - y**2, x)
                [y, -y]
                >>> solve(x**4 - 1, x)
                [1, -1, -I, I]

            o single expression with no symbol that is in the expression

                >>> solve(3, x)
                []
                >>> solve(x - 3, y)
                []

            o when no symbol is given then all free symbols will be used
              and sorted with default_sort_key and the result will be the
              same as above as if those symbols had been supplied

                >>> solve(x - 3)
                [3]
                >>> solve(x**2 - y**2)
                [y, -y]

            o when a Function or Derivative is given as a symbol, it is isolated
              algebraically and an implicit solution may be obtained

                >>> f = Function('f')
                >>> solve(f(x) - x, f(x))
                [x]
                >>> solve(f(x).diff(x) - f(x) - x, f(x).diff(x))
                [x + f(x)]

            o single expression and more than 1 symbol

                when there is a linear solution
                    >>> solve(x - y**2, x, y)
                    {x: y**2}
                    >>> solve(x**2 - y, x, y)
                    {y: x**2}

                when undetermined coefficients are identified
                    that are linear
                        >>> solve((a + b)*x - b + 2, a, b)
                        {a: -2, b: 2}

                    that are nonlinear
                        >>> solve((a + b)*x - b**2 + 2, a, b)
                        [(-2**(1/2), 2**(1/2)), (2**(1/2), -2**(1/2))]

                if there is no linear solution then the first successful
                attempt for a nonlinear solution will be returned
                    >>> solve(x**2 - y**2, x, y)
                    [y, -y]
                    >>> solve(x**2 - y**2/exp(x), x, y)
                    [x*exp(x/2), -x*exp(x/2)]

            o iterable of one or more of the above

                involving relationals or bools
                    >>> solve([x < 3, x - 2])
                    And(im(x) == 0, re(x) == 2)
                    >>> solve([x > 3, x - 2])
                    False

                when the system is linear
                    with a solution
                        >>> solve([x - 3], x)
                        {x: 3}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y)
                        {x: -3, y: 1}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y, z)
                        {x: -3, y: 1}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - z), z, x, y)
                        {x: -5*y + 2, z: 21*y - 6}

                    without a solution
                        >>> solve([x + 3, x - 3])

                when the system is not linear
                    >>> solve([x**2 + y -2, y**2 - 4], x, y)
                    [(-2, -2), (0, 2), (0, 2), (2, -2)]

                Warning: there is a possibility of obtaining ambiguous results
                if no symbols are given for a nonlinear system of equations or
                are given as a set since the symbols are not presently reported
                with the solution. A warning will be issued in this situation.
                    >>> solve([x - 2, x**2 + y])
                    <BLANKLINE>
                        For nonlinear systems of equations, symbols should be
                        given as a list so as to avoid ambiguity in the results.
                        solve sorted the symbols as [x, y]
                    [(2, -4)]

                    >>> solve([x - 2, x**2 + f(x)], set([f(x), x]))
                    <BLANKLINE>
                        For nonlinear systems of equations, symbols should be
                        given as a list so as to avoid ambiguity in the results.
                        solve sorted the symbols as [x, f(x)]
                    [(2, -4)]

       See also:
          rsolve() for solving recurrence relationships
          dsolve() for solving differential equations

    """
    # make f and symbols into lists of sympified quantities
    # keeping track of how f was passed since if it is a list
    # a dictionary of results will be returned.
    ###########################################################################
    def sympified_list(w):
        return map(sympify, iff(iterable(w), w, [w]))
    bare_f = not iterable(f)
    ordered_symbols = (symbols and
                       symbols[0] and
                       (isinstance(symbols[0], Symbol) or
                        ordered_iter(symbols[0], include=GeneratorType)
                       )
                      )
    f, symbols = (sympified_list(w) for w in [f, symbols])

    # preprocess equation(s)
    ###########################################################################
    for i, fi in enumerate(f):
        if isinstance(fi, Equality):
            f[i] = fi.lhs - fi.rhs
        elif isinstance(fi, Poly):
            f[i] = fi.as_expr()
        elif isinstance(fi, bool) or fi.is_Relational:
            return reduce_inequalities(f, assume=flags.get('assume'))
        # Any embedded piecewise functions need to be brought out to the
        # top level so that the appropriate strategy gets selected.
        f[i] = piecewise_fold(f[i])

    # preprocess symbol(s)
    ###########################################################################
    if not symbols:
        # get symbols from equations or supply dummy symbols so solve(3) behaves
        # like solve(3, x).
        symbols = set([])
        for fi in f:
            symbols |= fi.free_symbols or set([Dummy()])
        ordered_symbols = False
    elif len(symbols) == 1 and iterable(symbols[0]):
        symbols = symbols[0]
    if not ordered_symbols:
        # we do this to make the results returned canonical in case f
        # contains a system of nonlinear equations; all other cases should
        # be unambiguous
        symbols = sorted(symbols, key=lambda i: i.sort_key())

    # we can solve for Function and Derivative instances by replacing them
    # with Dummy symbols
    symbols_new = []
    symbol_swapped = False
    symbols_passed = list(symbols)

    for i, s in enumerate(symbols):
        if s.is_Symbol:
            s_new = s
        elif s.is_Function:
            symbol_swapped = True
            s_new = Dummy('F%d' % i)
        elif s.is_Derivative:
            symbol_swapped = True
            s_new = Dummy('D%d' % i)
        else:
            msg = 'expected Symbol, Function or Derivative but got %s'
            raise TypeError(msg % type(s))
        symbols_new.append(s_new)

    if symbol_swapped:
        swap_back_dict = dict(zip(symbols_new, symbols))
        swap_dict = zip(symbols, symbols_new)
        f = [fi.subs(swap_dict) for fi in f]
        symbols = symbols_new

    #
    # try to get a solution
    ###########################################################################
    if bare_f:
        # pass f the way it was passed to solve; if it wasn't a list then
        # a list of solutions will be returned, otherwise a dictionary is
        # going to be returned
        f = f[0]
    solution = _solve(f, *symbols, **flags)

    #
    # postprocessing
    ###########################################################################
    # Restore original Functions and Derivatives if a dictionary is returned.
    # This is not necessary for
    #   - the single equation, single unknown case
    #     since the symbol will have been removed from the solution;
    #   - the nonlinear poly_system since that only support zero-dimensional
    #     systems and those results come back as a list
    if symbol_swapped and type(solution) is dict:
            solution = dict([(swap_back_dict[k], v.subs(swap_back_dict))
                              for k, v in solution.iteritems()])
    # warn if ambiguous results are being obtained
    # XXX agree on how to make this unambiguous
    # see issue 2405 for logic in how Polys chooses ordering and
    # for discussion of what to return see http://groups.google.com/group/sympy
    #                           Apr 18, 2011 posting 'using results from solve'
    elif (not ordered_symbols and len(symbols) > 1 and solution and
          ordered_iter(solution) and ordered_iter(solution[0]) and
          any(len(set(s)) > 1 for s in solution)):
        msg = ('\n\tFor nonlinear systems of equations, symbols should be' +
               '\n\tgiven as a list so as to avoid ambiguity in the results.' +
               '\n\tsolve sorted the symbols as %s')
        print msg % str(bool(symbol_swapped) and list(zip(*swap_dict)[0]) or symbols)
    #
    # done
    ###########################################################################
    return solution
Exemple #35
0
def solve(f, *symbols, **flags):
    """
    Algebraically solves equations and systems of equations.

        Currently supported are:
            - univariate polynomial,
            - transcendental
            - piecewise combinations of the above
            - systems of linear and polynomial equations
            - sytems containing relational expressions.

        Input is formed as:
            f
                - a single Expr or Poly that must be zero,
                - an Equality
                - a Relational expression or boolean
                - iterable of one or more of the above

            symbols (Symbol, Function or Derivative) specified as
                - none given (all free symbols will be used)
                - single symbol
                - denested list of symbols
                  e.g. solve(f, x, y)
                - ordered iterable of symbols
                  e.g. solve(f, [x, y])

            flags
                - ``simplified``, when False, will not simplify solutions
                                 (default=True except for polynomials of
                                  order 3 or greater)

        The output varies according to the input and can be seen by example:

            >>> from sympy import solve, Poly, Eq, Function, exp
            >>> from sympy.abc import x, y, z, a, b

            o boolean or univariate Relational

                >>> solve(x < 3)
                And(im(x) == 0, re(x) < 3)

            o single expression and single symbol that is in the expression

                >>> solve(x - y, x)
                [y]
                >>> solve(x - 3, x)
                [3]
                >>> solve(Eq(x, 3), x)
                [3]
                >>> solve(Poly(x - 3), x)
                [3]
                >>> solve(x**2 - y**2, x)
                [y, -y]
                >>> solve(x**4 - 1, x)
                [1, -1, -I, I]

            o single expression with no symbol that is in the expression

                >>> solve(3, x)
                []
                >>> solve(x - 3, y)
                []

            o when no symbol is given then all free symbols will be used
              and sorted with default_sort_key and the result will be the
              same as above as if those symbols had been supplied

                >>> solve(x - 3)
                [3]
                >>> solve(x**2 - y**2)
                [y, -y]

            o when a Function or Derivative is given as a symbol, it is isolated
              algebraically and an implicit solution may be obtained

                >>> f = Function('f')
                >>> solve(f(x) - x, f(x))
                [x]
                >>> solve(f(x).diff(x) - f(x) - x, f(x).diff(x))
                [x + f(x)]

            o single expression and more than 1 symbol

                when there is a linear solution
                    >>> solve(x - y**2, x, y)
                    {x: y**2}
                    >>> solve(x**2 - y, x, y)
                    {y: x**2}

                when undetermined coefficients are identified
                    that are linear
                        >>> solve((a + b)*x - b + 2, a, b)
                        {a: -2, b: 2}

                    that are nonlinear
                        >>> solve((a + b)*x - b**2 + 2, a, b)
                        [(-2**(1/2), 2**(1/2)), (2**(1/2), -2**(1/2))]

                if there is no linear solution then the first successful
                attempt for a nonlinear solution will be returned
                    >>> solve(x**2 - y**2, x, y)
                    [y, -y]
                    >>> solve(x**2 - y**2/exp(x), x, y)
                    [x*exp(x/2), -x*exp(x/2)]

            o iterable of one or more of the above

                involving relationals or bools
                    >>> solve([x < 3, x - 2])
                    And(im(x) == 0, re(x) == 2)
                    >>> solve([x > 3, x - 2])
                    False

                when the system is linear
                    with a solution
                        >>> solve([x - 3], x)
                        {x: 3}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y)
                        {x: -3, y: 1}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y, z)
                        {x: -3, y: 1}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - z), z, x, y)
                        {x: -5*y + 2, z: 21*y - 6}

                    without a solution
                        >>> solve([x + 3, x - 3])

                when the system is not linear
                    >>> solve([x**2 + y -2, y**2 - 4], x, y)
                    [(-2, -2), (0, 2), (0, 2), (2, -2)]

                Warning: there is a possibility of obtaining ambiguous results
                if no symbols are given for a nonlinear system of equations or
                are given as a set since the symbols are not presently reported
                with the solution. A warning will be issued in this situation.
                    >>> solve([x - 2, x**2 + y])
                    <BLANKLINE>
                        For nonlinear systems of equations, symbols should be
                        given as a list so as to avoid ambiguity in the results.
                        solve sorted the symbols as [x, y]
                    [(2, -4)]

                    >>> solve([x - 2, x**2 + f(x)], set([f(x), x]))
                    <BLANKLINE>
                        For nonlinear systems of equations, symbols should be
                        given as a list so as to avoid ambiguity in the results.
                        solve sorted the symbols as [x, f(x)]
                    [(2, -4)]

       See also:
          rsolve() for solving recurrence relationships
          dsolve() for solving differential equations

    """

    # make f and symbols into lists of sympified quantities
    # keeping track of how f was passed since if it is a list
    # a dictionary of results will be returned.
    ###########################################################################
    def sympified_list(w):
        return map(sympify, iff(iterable(w), w, [w]))

    bare_f = not iterable(f)
    ordered_symbols = (symbols and symbols[0] and
                       (isinstance(symbols[0], Symbol)
                        or ordered_iter(symbols[0], include=GeneratorType)))
    f, symbols = (sympified_list(w) for w in [f, symbols])

    # preprocess equation(s)
    ###########################################################################
    for i, fi in enumerate(f):
        if isinstance(fi, Equality):
            f[i] = fi.lhs - fi.rhs
        elif isinstance(fi, Poly):
            f[i] = fi.as_expr()
        elif isinstance(fi, bool) or fi.is_Relational:
            return reduce_inequalities(f, assume=flags.get('assume'))
        # Any embedded piecewise functions need to be brought out to the
        # top level so that the appropriate strategy gets selected.
        f[i] = piecewise_fold(f[i])

    # preprocess symbol(s)
    ###########################################################################
    if not symbols:
        # get symbols from equations or supply dummy symbols so solve(3) behaves
        # like solve(3, x).
        symbols = set([])
        for fi in f:
            symbols |= fi.free_symbols or set([Dummy()])
        ordered_symbols = False
    elif len(symbols) == 1 and iterable(symbols[0]):
        symbols = symbols[0]
    if not ordered_symbols:
        # we do this to make the results returned canonical in case f
        # contains a system of nonlinear equations; all other cases should
        # be unambiguous
        symbols = sorted(symbols, key=lambda i: i.sort_key())

    # we can solve for Function and Derivative instances by replacing them
    # with Dummy symbols
    symbols_new = []
    symbol_swapped = False
    symbols_passed = list(symbols)

    for i, s in enumerate(symbols):
        if s.is_Symbol:
            s_new = s
        elif s.is_Function:
            symbol_swapped = True
            s_new = Dummy('F%d' % i)
        elif s.is_Derivative:
            symbol_swapped = True
            s_new = Dummy('D%d' % i)
        else:
            msg = 'expected Symbol, Function or Derivative but got %s'
            raise TypeError(msg % type(s))
        symbols_new.append(s_new)

    if symbol_swapped:
        swap_back_dict = dict(zip(symbols_new, symbols))
        swap_dict = zip(symbols, symbols_new)
        f = [fi.subs(swap_dict) for fi in f]
        symbols = symbols_new

    #
    # try to get a solution
    ###########################################################################
    if bare_f:
        # pass f the way it was passed to solve; if it wasn't a list then
        # a list of solutions will be returned, otherwise a dictionary is
        # going to be returned
        f = f[0]
    solution = _solve(f, *symbols, **flags)

    #
    # postprocessing
    ###########################################################################
    # Restore original Functions and Derivatives if a dictionary is returned.
    # This is not necessary for
    #   - the single equation, single unknown case
    #     since the symbol will have been removed from the solution;
    #   - the nonlinear poly_system since that only support zero-dimensional
    #     systems and those results come back as a list
    if symbol_swapped and type(solution) is dict:
        solution = dict([(swap_back_dict[k], v.subs(swap_back_dict))
                         for k, v in solution.iteritems()])
    # warn if ambiguous results are being obtained
    # XXX agree on how to make this unambiguous
    # see issue 2405 for logic in how Polys chooses ordering and
    # for discussion of what to return see http://groups.google.com/group/sympy
    #                           Apr 18, 2011 posting 'using results from solve'
    elif (not ordered_symbols and len(symbols) > 1 and solution
          and ordered_iter(solution) and ordered_iter(solution[0])
          and any(len(set(s)) > 1 for s in solution)):
        msg = ('\n\tFor nonlinear systems of equations, symbols should be' +
               '\n\tgiven as a list so as to avoid ambiguity in the results.' +
               '\n\tsolve sorted the symbols as %s')
        print msg % str(
            bool(symbol_swapped) and list(zip(*swap_dict)[0]) or symbols)
    #
    # done
    ###########################################################################
    return solution
Exemple #36
0
def _imp_namespace(expr, namespace=None):
    """ Return namespace dict with function implementations

    We need to search for functions in anything that can be thrown at
    us - that is - anything that could be passed as `expr`.  Examples
    include sympy expressions, as well as tuples, lists and dicts that may
    contain sympy expressions.

    Parameters
    ----------
    expr : object
       Something passed to lambdify, that will generate valid code from
       ``str(expr)``.
    namespace : None or mapping
       Namespace to fill.  None results in new empty dict

    Returns
    -------
    namespace : dict
       dict with keys of implemented function names within `expr` and
       corresponding values being the numerical implementation of
       function

    Examples
    --------
    >>> from sympy.abc import x, y, z
    >>> from sympy.utilities.lambdify import implemented_function, _imp_namespace
    >>> from sympy import Function
    >>> f = implemented_function(Function('f'), lambda x : x+1)
    >>> g = implemented_function(Function('g'), lambda x : x*10)
    >>> namespace = _imp_namespace(f(g(x)))
    >>> sorted(namespace.keys())
    ['f', 'g']
    """
    # Delayed import to avoid circular imports
    from sympy.core.function import FunctionClass
    if namespace is None:
        namespace = {}
    # tuples, lists, dicts are valid expressions
    if ordered_iter(expr):
        for arg in expr:
            _imp_namespace(arg, namespace)
        return namespace
    elif isinstance(expr, dict):
        for key, val in expr.items():
            # functions can be in dictionary keys
            _imp_namespace(key, namespace)
            _imp_namespace(val, namespace)
        return namespace
    # sympy expressions may be Functions themselves
    func = getattr(expr, 'func', None)
    if isinstance(func, FunctionClass):
        imp = getattr(func, '_imp_', None)
        if not imp is None:
            name = expr.func.__name__
            if name in namespace and namespace[name] != imp:
                raise ValueError('We found more than one '
                                 'implementation with name '
                                 '"%s"' % name)
            namespace[name] = imp
    # and / or they may take Functions as arguments
    if hasattr(expr, 'args'):
        for arg in expr.args:
            _imp_namespace(arg, namespace)
    return namespace
Exemple #37
0
    def __init__(self, name, expr, argument_sequence=None):
        """Initialize a Routine instance.

        ``name``
            A string with the name of this routine in the generated code
        ``expr``
            The sympy expression that the Routine instance will represent.  If
            given a list or tuple of expressions, the routine will be
            considered to have multiple return values.
        ``argument_sequence``
            Optional list/tuple containing arguments for the routine in a
            preferred order.  If omitted, arguments will be ordered
            alphabetically, but with all input aguments first, and then output
            or in-out arguments.

        A decision about whether to use output arguments or return values,
        is made depending on the mathematical expressions.  For an expression
        of type Equality, the left hand side is made into an OutputArgument
        (or an InOutArgument if appropriate).  Else, the calculated
        expression is the return values of the routine.

        A tuple of exressions can be used to create a routine with both
        return value(s) and output argument(s).

        """
        arg_list = []

        if ordered_iter(expr):
            if not expr:
                raise ValueError("No expression given")
            expressions = Tuple(*expr)
        else:
            expressions = Tuple(expr)

        # local variables
        local_vars = set([i.label for i in expressions.atoms(Idx)])

        # symbols that should be arguments
        symbols = expressions.atoms(Symbol) - local_vars

        # Decide whether to use output argument or return value
        return_val = []
        output_args = []
        for expr in expressions:
            if isinstance(expr, Equality):
                out_arg = expr.lhs
                expr = expr.rhs
                if isinstance(out_arg, Indexed):
                    dims = tuple([(S.Zero, dim - 1) for dim in out_arg.shape])
                    symbol = out_arg.base.label
                elif isinstance(out_arg, Symbol):
                    dims = []
                    symbol = out_arg
                else:
                    raise CodeGenError(
                        "Only Indexed or Symbol can define output arguments")

                if expr.has(symbol):
                    output_args.append(
                        InOutArgument(symbol, out_arg, expr, dimensions=dims))
                else:
                    output_args.append(
                        OutputArgument(symbol, out_arg, expr, dimensions=dims))

                # avoid duplicate arguments
                symbols.remove(symbol)
            else:
                return_val.append(Result(expr))

        # setup input argument list
        array_symbols = {}
        for array in expressions.atoms(Indexed):
            array_symbols[array.base.label] = array

        for symbol in sorted(symbols, key=str):
            if symbol in array_symbols:
                dims = []
                array = array_symbols[symbol]
                for dim in array.shape:
                    dims.append((S.Zero, dim - 1))
                metadata = {'dimensions': dims}
            else:
                metadata = {}

            arg_list.append(InputArgument(symbol, **metadata))

        output_args.sort(key=lambda x: str(x.name))
        arg_list.extend(output_args)

        if argument_sequence is not None:
            # if the user has supplied IndexedBase instances, we'll accept that
            new_sequence = []
            for arg in argument_sequence:
                if isinstance(arg, IndexedBase):
                    new_sequence.append(arg.label)
                else:
                    new_sequence.append(arg)
            argument_sequence = new_sequence

            missing = filter(lambda x: x.name not in argument_sequence,
                             arg_list)
            if missing:
                raise CodeGenArgumentListError(
                    "Argument list didn't specify: %s" %
                    ", ".join([str(m.name) for m in missing]), missing)

            # create redundant arguments to produce the requested sequence
            name_arg_dict = dict([(x.name, x) for x in arg_list])
            new_args = []
            for symbol in argument_sequence:
                try:
                    new_args.append(name_arg_dict[symbol])
                except KeyError:
                    new_args.append(InputArgument(symbol))
            arg_list = new_args

        self.name = name
        self.arguments = arg_list
        self.results = return_val
        self.local_vars = local_vars
Exemple #38
0
def _imp_namespace(expr, namespace=None):
    """ Return namespace dict with function implementations

    We need to search for functions in anything that can be thrown at
    us - that is - anything that could be passed as `expr`.  Examples
    include sympy expressions, as well as tuples, lists and dicts that may
    contain sympy expressions.

    Parameters
    ----------
    expr : object
       Something passed to lambdify, that will generate valid code from
       ``str(expr)``.
    namespace : None or mapping
       Namespace to fill.  None results in new empty dict

    Returns
    -------
    namespace : dict
       dict with keys of implemented function names within `expr` and
       corresponding values being the numerical implementation of
       function

    Examples
    --------
    >>> from sympy.abc import x, y, z
    >>> from sympy.utilities.lambdify import implemented_function, _imp_namespace
    >>> from sympy import Function
    >>> f = implemented_function(Function('f'), lambda x : x+1)
    >>> g = implemented_function(Function('g'), lambda x : x*10)
    >>> namespace = _imp_namespace(f(g(x)))
    >>> sorted(namespace.keys())
    ['f', 'g']
    """
    # Delayed import to avoid circular imports
    from sympy.core.function import FunctionClass

    if namespace is None:
        namespace = {}
    # tuples, lists, dicts are valid expressions
    if ordered_iter(expr):
        for arg in expr:
            _imp_namespace(arg, namespace)
        return namespace
    elif isinstance(expr, dict):
        for key, val in expr.items():
            # functions can be in dictionary keys
            _imp_namespace(key, namespace)
            _imp_namespace(val, namespace)
        return namespace
    # sympy expressions may be Functions themselves
    func = getattr(expr, "func", None)
    if isinstance(func, FunctionClass):
        imp = getattr(func, "_imp_", None)
        if not imp is None:
            name = expr.func.__name__
            if name in namespace and namespace[name] != imp:
                raise ValueError("We found more than one " "implementation with name " '"%s"' % name)
            namespace[name] = imp
    # and / or they may take Functions as arguments
    if hasattr(expr, "args"):
        for arg in expr.args:
            _imp_namespace(arg, namespace)
    return namespace