def uniquely_named_symbol(xname, exprs=(), compare=str, modify=None, **assumptions): """Return a symbol which, when printed, will have a name unique from any other already in the expressions given. The name is made unique by appending numbers (default) but this can be customized with the keyword 'modify'. Parameters ========== xname : a string or a Symbol compare : a single arg function that takes a symbol and returns a string to be compared with xname (the default is the str function which indicates how the name will look when it is printed, e.g. this includes underscores that appear on Dummy symbols). When ``xname`` is a Symbol, ``compare`` will be used to supply the value for ``xname``. modify : a single arg function that changes its string argument in some way (the default is to append numbers) Examples ======== >>> from sympy.core.symbol import uniquely_named_symbol >>> from sympy.abc import x >>> uniquely_named_symbol('x', x) x0 """ def numbered_string_incr(s, start=0): if not s: return str(start) i = len(s) - 1 while i != -1: if not s[i].isdigit(): break i -= 1 n = str(int(s[i + 1:] or start - 1) + 1) return s[:i + 1] + n default = None if is_sequence(xname): xname, default = xname x = compare(xname) if not exprs: return _symbol(x, default, **assumptions) if not is_sequence(exprs): exprs = [exprs] names = set().union( [i.name for e in exprs for i in e.atoms(Symbol)] + [i.func.name for e in exprs for i in e.atoms(AppliedUndef)]) if modify is None: modify = numbered_string_incr while any(x == compare(s) for s in names): x = modify(x) return _symbol(x, default, **assumptions)
def test_iterable_is_sequence(): ordered = [list(), tuple(), Tuple(), Matrix([[]])] unordered = [set()] not_sympy_iterable = [{}, '', ''] assert all(is_sequence(i) for i in ordered) assert all(not is_sequence(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)
def _eval_subs(self, old, new): from sympy.geometry.point import Point, Point3D if is_sequence(old) or is_sequence(new): if isinstance(self, Point3D): old = Point3D(old) new = Point3D(new) else: old = Point(old) new = Point(new) return self._subs(old, new)
def __new__(cls, function, limits): fun = sympify(function) if not is_sequence(fun) or len(fun) != 2: raise ValueError("Function argument should be (x(t), y(t)) " "but got %s" % str(function)) if not is_sequence(limits) or len(limits) != 3: raise ValueError("Limit argument should be (t, tmin, tmax) " "but got %s" % str(limits)) return GeometryEntity.__new__(cls, Tuple(*fun), Tuple(*limits))
def sequence(seq, limits=None): """ Returns appropriate sequence object. Explanation =========== If ``seq`` is a SymPy sequence, returns :class:`SeqPer` object otherwise returns :class:`SeqFormula` object. Examples ======== >>> from sympy import sequence >>> from sympy.abc import n >>> sequence(n**2, (n, 0, 5)) SeqFormula(n**2, (n, 0, 5)) >>> sequence((1, 2, 3), (n, 0, 5)) SeqPer((1, 2, 3), (n, 0, 5)) See Also ======== sympy.series.sequences.SeqPer sympy.series.sequences.SeqFormula """ seq = sympify(seq) if is_sequence(seq, Tuple): return SeqPer(seq, limits) else: return SeqFormula(seq, limits)
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 is_sequence(a, include=str): raise ValueError(interpret_error % (str(a))) try: f = sympify(a) functions.append(f) except TypeError: raise ValueError(interpret_error % str(a)) return functions, intervals
def __new__(cls, label, shape=None, *, offset=S.Zero, strides=None, **kw_args): from sympy.matrices.matrices import MatrixBase from sympy.tensor.array.ndim_array import NDimArray assumptions, kw_args = _filter_assumptions(kw_args) if isinstance(label, str): label = Symbol(label, **assumptions) elif isinstance(label, Symbol): assumptions = label._merge(assumptions) elif isinstance(label, (MatrixBase, NDimArray)): return label elif isinstance(label, Iterable): return _sympify(label) else: label = _sympify(label) if is_sequence(shape): shape = Tuple(*shape) elif shape is not None: shape = Tuple(shape) if shape is not None: obj = Expr.__new__(cls, label, shape) else: obj = Expr.__new__(cls, label) obj._shape = shape obj._offset = offset obj._strides = strides obj._name = str(label) IndexedBase._set_assumptions(obj, assumptions) return obj
def __setitem__(self, i, args): """ Parses and adds a PlotMode to the function list. """ if not (isinstance(i, (SYMPY_INTS, Integer)) and i >= 0): raise ValueError("Function index must " "be an integer >= 0.") if isinstance(args, PlotObject): f = args else: if (not is_sequence(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))
def _(func): for t in types: if not is_sequence(t): t = ( t, ) # for convenience, allow passing `type` to mean `(type,)` cls.register(*t, **kwargs)(func)
def evalf(self, n=15, subs=None, maxn=100, chop=False, strict=False, quad=None, verbose=False): if subs and is_sequence(subs): raise TypeError('subs must be given as a dictionary') x, y = self.args return f_t(x, y)
def wrapper(*args): out = func(*args) # out can be array(1.0) or [array(1.0), array(2.0)] if is_sequence(out): return [o[()] if is_0d[i] else o for i, o in enumerate(out)] else: return out[()]
def _eval_args(cls, args): # _eval_args has the right logic for the controls argument. controls = args[0] gate = args[1] if not is_sequence(controls): controls = (controls,) controls = UnitaryOperator._eval_args(controls) _validate_targets_controls(chain(controls, gate.targets)) return (Tuple(*controls), gate)
def __getitem__(self, indices, **kw_args): if is_sequence(indices): # 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)
def __new__(cls, *args, **kwargs): from sympy.matrices.immutable import ImmutableDenseMatrix from sympy.matrices import zeros from sympy.matrices.matrices import MatrixBase from sympy.utilities.iterables import is_sequence isMat = lambda i: getattr(i, 'is_Matrix', False) if len(args) != 1 or \ not is_sequence(args[0]) or \ len(set([isMat(r) for r in args[0]])) != 1: raise ValueError( filldedent(''' expecting a sequence of 1 or more rows containing Matrices.''')) rows = args[0] if args else [] if not isMat(rows): if rows and isMat(rows[0]): rows = [rows] # rows is not list of lists or [] # regularity check # same number of matrices in each row blocky = ok = len(set([len(r) for r in rows])) == 1 if ok: # same number of rows for each matrix in a row for r in rows: ok = len(set([i.rows for i in r])) == 1 if not ok: break blocky = ok # same number of cols for each matrix in each col for c in range(len(rows[0])): ok = len(set([rows[i][c].cols for i in range(len(rows))])) == 1 if not ok: break if not ok: # same total cols in each row ok = len(set([sum([i.cols for i in r]) for r in rows])) == 1 if blocky and ok: raise ValueError( filldedent(''' Although this matrix is comprised of blocks, the blocks do not fill the matrix in a size-symmetric fashion. To create a full matrix from these arguments, pass them directly to Matrix.''')) raise ValueError( filldedent(''' When there are not the same number of rows in each row's matrices or there are not the same number of total columns in each row, the matrix is not a block matrix. If this matrix is known to consist of blocks fully filling a 2-D space then see Matrix.irregular.''')) mat = ImmutableDenseMatrix(rows, evaluate=False) obj = Basic.__new__(cls, mat) return obj
def _process_limits(func, limits): """ Limits should be of the form (x, start, stop). x should be a symbol. Both start and stop should be bounded. Explanation =========== * If x is not given, x is determined from func. * If limits is None. Limit of the form (x, -pi, pi) is returned. Examples ======== >>> from sympy.series.fourier import _process_limits as pari >>> from sympy.abc import x >>> pari(x**2, (x, -2, 2)) (x, -2, 2) >>> pari(x**2, (-2, 2)) (x, -2, 2) >>> pari(x**2, None) (x, -pi, pi) """ def _find_x(func): free = func.free_symbols if len(free) == 1: return free.pop() elif not free: return Dummy('k') else: raise ValueError( " specify dummy variables for %s. If the function contains" " more than one free symbol, a dummy variable should be" " supplied explicitly e.g. FourierSeries(m*n**2, (n, -pi, pi))" % func) x, start, stop = None, None, None if limits is None: x, start, stop = _find_x(func), -pi, pi if is_sequence(limits, Tuple): if len(limits) == 3: x, start, stop = limits elif len(limits) == 2: x = _find_x(func) start, stop = limits if not isinstance(x, Symbol) or start is None or stop is None: raise ValueError('Invalid limits given: %s' % str(limits)) unbounded = [S.NegativeInfinity, S.Infinity] if start in unbounded or stop in unbounded: raise ValueError("Both the start and end value should be bounded") return sympify((x, start, stop))
def __new__(cls, *args, **kwargs): from sympy.matrices.immutable import ImmutableDenseMatrix from sympy.matrices import zeros from sympy.matrices.matrices import MatrixBase from sympy.utilities.iterables import is_sequence isMat = lambda i: getattr(i, 'is_Matrix', False) if len(args) != 1 or \ not is_sequence(args[0]) or \ len(set([isMat(r) for r in args[0]])) != 1: raise ValueError(filldedent(''' expecting a sequence of 1 or more rows containing Matrices.''')) rows = args[0] if args else [] if not isMat(rows): if rows and isMat(rows[0]): rows = [rows] # rows is not list of lists or [] # regularity check # same number of matrices in each row blocky = ok = len(set([len(r) for r in rows])) == 1 if ok: # same number of rows for each matrix in a row for r in rows: ok = len(set([i.rows for i in r])) == 1 if not ok: break blocky = ok # same number of cols for each matrix in each col for c in range(len(rows[0])): ok = len(set([rows[i][c].cols for i in range(len(rows))])) == 1 if not ok: break if not ok: # same total cols in each row ok = len(set([ sum([i.cols for i in r]) for r in rows])) == 1 if blocky and ok: raise ValueError(filldedent(''' Although this matrix is comprised of blocks, the blocks do not fill the matrix in a size-symmetric fashion. To create a full matrix from these arguments, pass them directly to Matrix.''')) raise ValueError(filldedent(''' When there are not the same number of rows in each row's matrices or there are not the same number of total columns in each row, the matrix is not a block matrix. If this matrix is known to consist of blocks fully filling a 2-D space then see Matrix.irregular.''')) mat = ImmutableDenseMatrix(rows, evaluate=False) obj = Basic.__new__(cls, mat) return obj
def __new__(cls, periodical, limits=None): periodical = sympify(periodical) def _find_x(periodical): free = periodical.free_symbols if len(periodical.free_symbols) == 1: return free.pop() else: return Dummy('k') x, start, stop = None, None, None if limits is None: x, start, stop = _find_x(periodical), 0, S.Infinity if is_sequence(limits, Tuple): if len(limits) == 3: x, start, stop = limits elif len(limits) == 2: x = _find_x(periodical) start, stop = limits if not isinstance(x, (Symbol, Idx)) or start is None or stop is None: raise ValueError('Invalid limits given: %s' % str(limits)) if start is S.NegativeInfinity and stop is S.Infinity: raise ValueError("Both the start and end value" "cannot be unbounded") limits = sympify((x, start, stop)) if is_sequence(periodical, Tuple): periodical = sympify(tuple(flatten(periodical))) else: raise ValueError("invalid period %s should be something " "like e.g (1, 2) " % periodical) if Interval(limits[1], limits[2]) is S.EmptySet: return S.EmptySequence return Basic.__new__(cls, periodical, limits)
def _set_color(self, v): try: if v is not None: if is_sequence(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 as e: raise RuntimeError("Color change failed. " "Reason: %s" % (str(e)))
def sfield(exprs, *symbols, **options): """Construct a field deriving generators and domain from options and input expressions. Parameters ========== exprs : py:class:`~.Expr` or sequence of :py:class:`~.Expr` (sympifiable) symbols : sequence of :py:class:`~.Symbol`/:py:class:`~.Expr` options : keyword arguments understood by :py:class:`~.Options` Examples ======== >>> from sympy import exp, log, symbols, sfield >>> x = symbols("x") >>> K, f = sfield((x*log(x) + 4*x**2)*exp(1/x + log(x)/3)/x**2) >>> K Rational function field in x, exp(1/x), log(x), x**(1/3) over ZZ with lex order >>> f (4*x**2*(exp(1/x)) + x*(exp(1/x))*(log(x)))/((x**(1/3))**5) """ single = False if not is_sequence(exprs): exprs, single = [exprs], True exprs = list(map(sympify, exprs)) opt = build_options(symbols, options) numdens = [] for expr in exprs: numdens.extend(expr.as_numer_denom()) reps, opt = _parallel_dict_from_expr(numdens, opt) if opt.domain is None: # NOTE: this is inefficient because construct_domain() automatically # performs conversion to the target domain. It shouldn't do this. coeffs = sum([list(rep.values()) for rep in reps], []) opt.domain, _ = construct_domain(coeffs, opt=opt) _field = FracField(opt.gens, opt.domain, opt.order) fracs = [] for i in range(0, len(reps), 2): fracs.append(_field(tuple(reps[i:i + 2]))) if single: return (_field, fracs[0]) else: return (_field, fracs)
def __contains__(self, point): if is_sequence(point): if len(point) == 2: z1 = 1 else: z1 = point[2] x1, y1 = point[:2] elif isinstance(point, EllipticCurvePoint): x1, y1, z1 = point.x, point.y, point.z else: raise ValueError('Invalid point.') if self.characteristic == 0 and z1 == 0: return True return self._eq.subs({self.x: x1, self.y: y1, self.z: z1})
def preprocess(cls, gens): if isinstance(gens, Basic): gens = (gens, ) elif len(gens) == 1 and is_sequence(gens[0]): gens = gens[0] if gens == (None, ): gens = () elif has_dups(gens): raise GeneratorsError("duplicated generators: %s" % str(gens)) elif any(gen.is_commutative is False for gen in gens): raise GeneratorsError("non-commutative generators: %s" % str(gens)) return tuple(gens)
def _parse_symbols(symbols): if not symbols: return tuple() if isinstance(symbols, str): return _symbols(symbols, seq=True) elif isinstance(symbols, Expr or FreeGroupElement): return (symbols, ) elif is_sequence(symbols): if all(isinstance(s, str) for s in symbols): return _symbols(symbols) elif all(isinstance(s, Expr) for s in symbols): return symbols raise ValueError("The type of `symbols` must be one of the following: " "a str, Symbol/Expr or a sequence of " "one of these types")
def _randrange(seed=None): """Return a randrange generator. ``seed`` can be o None - return randomly seeded generator o int - return a generator seeded with the int o list - the values to be returned will be taken from the list in the order given; the provided list is not modified. Examples ======== >>> from sympy.core.random import _randrange >>> rr = _randrange() >>> rr(1000) # doctest: +SKIP 999 >>> rr = _randrange(3) >>> rr(1000) # doctest: +SKIP 238 >>> rr = _randrange([0, 5, 1, 3, 4]) >>> rr(3), rr(3) (0, 1) """ if seed is None: return randrange elif isinstance(seed, int): rng.seed(seed) return randrange elif is_sequence(seed): seed = list(seed) # make a copy seed.reverse() def give(a, b=None, seq=seed): if b is None: a, b = 0, a a, b = as_int(a), as_int(b) w = b - a if w < 1: raise ValueError('_randrange got empty range') try: x = seq.pop() except IndexError: raise ValueError('_randrange sequence was too short') if a <= x < b: return x else: return give(a, b, seq) return give else: raise ValueError('_randrange got an unexpected seed')
def _eval_args(cls, args): targets = args[0] if not is_sequence(targets): targets = (targets, ) targets = Gate._eval_args(targets) _validate_targets_controls(targets) mat = args[1] if not isinstance(mat, MatrixBase): raise TypeError('Matrix expected, got: %r' % mat) #make sure this matrix is of a Basic type mat = _sympify(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)
def __new__(cls, label, range=None, **kw_args): if isinstance(label, str): label = Symbol(label, integer=True) label, range = list(map(sympify, (label, range))) if label.is_Number: if not label.is_integer: raise TypeError("Index is not an integer number.") return label if not label.is_integer: raise TypeError("Idx object requires an integer label.") elif is_sequence(range): if len(range) != 2: raise ValueError( filldedent(""" Idx range tuple must have length 2, but got %s""" % len(range))) for bound in range: if (bound.is_integer is False and bound is not S.Infinity and bound is not S.NegativeInfinity): raise TypeError("Idx object requires integer bounds.") args = label, Tuple(*range) elif isinstance(range, Expr): if range is not S.Infinity and fuzzy_not(range.is_integer): raise TypeError("Idx object requires an integer dimension.") args = label, Tuple(0, range - 1) elif range: raise TypeError( filldedent(""" The range must be an ordered iterable or integer SymPy expression.""")) else: args = label, obj = Expr.__new__(cls, *args, **kw_args) obj._assumptions["finite"] = True obj._assumptions["real"] = True return obj
def __new__(cls, p1, a=None, b=None, **kwargs): p1 = Point3D(p1, dim=3) if a and b: p2 = Point(a, dim=3) p3 = Point(b, dim=3) if Point3D.are_collinear(p1, p2, p3): raise ValueError('Enter three non-collinear points') a = p1.direction_ratio(p2) b = p1.direction_ratio(p3) normal_vector = tuple(Matrix(a).cross(Matrix(b))) else: a = kwargs.pop('normal_vector', a) evaluate = kwargs.get('evaluate', True) if is_sequence(a) and len(a) == 3: normal_vector = Point3D(a).args if evaluate else a else: raise ValueError(filldedent(''' Either provide 3 3D points or a point with a normal vector expressed as a sequence of length 3''')) if all(coord.is_zero for coord in normal_vector): raise ValueError('Normal vector cannot be zero vector') return GeometryEntity.__new__(cls, p1, normal_vector, **kwargs)
def __new__(cls, formula, limits=None): formula = sympify(formula) def _find_x(formula): free = formula.free_symbols if len(free) == 1: return free.pop() elif not free: return Dummy('k') else: raise ValueError( " specify dummy variables for %s. If the formula contains" " more than one free symbol, a dummy variable should be" " supplied explicitly e.g., SeqFormula(m*n**2, (n, 0, 5))" % formula) x, start, stop = None, None, None if limits is None: x, start, stop = _find_x(formula), 0, S.Infinity if is_sequence(limits, Tuple): if len(limits) == 3: x, start, stop = limits elif len(limits) == 2: x = _find_x(formula) start, stop = limits if not isinstance(x, (Symbol, Idx)) or start is None or stop is None: raise ValueError('Invalid limits given: %s' % str(limits)) if start is S.NegativeInfinity and stop is S.Infinity: raise ValueError("Both the start and end value " "cannot be unbounded") limits = sympify((x, start, stop)) if Interval(limits[1], limits[2]) is S.EmptySet: return S.EmptySequence return Basic.__new__(cls, formula, limits)
def copyin_list(self, key, value): """Copy in elements from a list. Parameters ========== key : slice The section of this matrix to replace. value : iterable The iterable to copy values from. Examples ======== >>> from sympy import eye >>> I = eye(3) >>> I[:2, 0] = [1, 2] # col >>> I Matrix([ [1, 0, 0], [2, 1, 0], [0, 0, 1]]) >>> I[1, :2] = [[3, 4]] >>> I Matrix([ [1, 0, 0], [3, 4, 0], [0, 0, 1]]) See Also ======== copyin_matrix """ if not is_sequence(value): raise TypeError("`value` must be an ordered iterable, not %s." % type(value)) return self.copyin_matrix(key, type(self)(value))
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 is_sequence(seq): if isinstance(seq, Matrix): return seq elif isinstance(seq, str): return Symbol(seq) else: return sympify(seq) # base condition, when seq is QExpr and also # is iterable. if isinstance(seq, QExpr): return seq #if list, recurse on each item in the list result = [__qsympify_sequence_helper(item) for item in seq] return Tuple(*result)
def mplot2d(f, var, *, show=True): """ Plot a 2d function using matplotlib/Tk. """ import warnings warnings.filterwarnings("ignore", r"Could not match \S") p = import_module('pylab') if not p: sys.exit("Matplotlib is required to use mplot2d.") if not is_sequence(f): f = [ f, ] for f_i in f: x, y = sample(f_i, var) p.plot(x, y) p.draw() if show: p.show()
def extend(self, arg): """Adds all series from another plot. Examples ======== Consider two ``Plot`` objects, ``p1`` and ``p2``. To add the second plot to the first, use the ``extend`` method, like so: .. plot:: :format: doctest :include-source: True >>> from sympy import symbols >>> from sympy.plotting import plot >>> x = symbols('x') >>> p1 = plot(x**2, show=False) >>> p2 = plot(x, -x, show=False) >>> p1.extend(p2) >>> p1 Plot object containing: [0]: cartesian line: x**2 for x over (-10.0, 10.0) [1]: cartesian line: x for x over (-10.0, 10.0) [2]: cartesian line: -x for x over (-10.0, 10.0) >>> p1.show() """ if isinstance(arg, Plot): self._series.extend(arg._series) elif is_sequence(arg) and all([isinstance(a, BaseSeries) for a in arg]): self._series.extend(arg) else: raise TypeError("Expecting Plot or sequence of BaseSeries") # auto legend if len(self._series) > 1: self.legend = True
def extract_leading_order(self, symbols, point=None): """ Returns the leading term and its order. Examples ======== >>> from sympy.abc import x >>> (x + 1 + 1/x**5).extract_leading_order(x) ((x**(-5), O(x**(-5))),) >>> (1 + x).extract_leading_order(x) ((1, O(1)),) >>> (x + x**2).extract_leading_order(x) ((x, O(x)),) """ from sympy.series.order import Order lst = [] symbols = list(symbols if is_sequence(symbols) else [symbols]) if not point: point = [0]*len(symbols) seq = [(f, Order(f, *zip(symbols, point))) for f in self.args] for ef, of in seq: for e, o in lst: if o.contains(of) and o != of: of = None break if of is None: continue new_lst = [(ef, of)] for e, o in lst: if of.contains(o) and o != of: continue new_lst.append((e, o)) lst = new_lst return tuple(lst)
def _contains(self, other): from sympy.matrices import Matrix from sympy.solvers.solveset import solveset, linsolve from sympy.utilities.iterables import is_sequence, iterable, cartes L = self.lamda if is_sequence(other): if not is_sequence(L.expr): return S.false if len(L.expr) != len(other): raise ValueError(filldedent(''' Dimensions of other and output of Lambda are different.''')) elif iterable(other): raise ValueError(filldedent(''' `other` should be an ordered object like a Tuple.''')) solns = None if self._is_multivariate(): if not is_sequence(L.expr): # exprs -> (numer, denom) and check again # XXX this is a bad idea -- make the user # remap self to desired form return other.as_numer_denom() in self.func( Lambda(L.variables, L.expr.as_numer_denom()), self.base_set) eqs = [expr - val for val, expr in zip(other, L.expr)] variables = L.variables free = set(variables) if all(i.is_number for i in list(Matrix(eqs).jacobian(variables))): solns = list(linsolve([e - val for e, val in zip(L.expr, other)], variables)) else: syms = [e.free_symbols & free for e in eqs] solns = {} for i, (e, s, v) in enumerate(zip(eqs, syms, other)): if not s: if e != v: return S.false solns[vars[i]] = [v] continue elif len(s) == 1: sy = s.pop() sol = solveset(e, sy) if sol is S.EmptySet: return S.false elif isinstance(sol, FiniteSet): solns[sy] = list(sol) else: raise NotImplementedError else: raise NotImplementedError solns = cartes(*[solns[s] for s in variables]) else: x = L.variables[0] if isinstance(L.expr, Expr): # scalar -> scalar mapping solnsSet = solveset(L.expr - other, x) if solnsSet.is_FiniteSet: solns = list(solnsSet) else: msgset = solnsSet else: # scalar -> vector for e, o in zip(L.expr, other): solns = solveset(e - o, x) if solns is S.EmptySet: return S.false for soln in solns: try: if soln in self.base_set: break # check next pair except TypeError: if self.base_set.contains(soln.evalf()): break else: return S.false # never broke so there was no True return S.true if solns is None: raise NotImplementedError(filldedent(''' Determining whether %s contains %s has not been implemented.''' % (msgset, other))) for soln in solns: try: if soln in self.base_set: return S.true except TypeError: return self.base_set.contains(soln.evalf()) return S.false
def banded(*args, **kwargs): """Returns a SparseMatrix from the given dictionary describing the diagonals of the matrix. The keys are positive for upper diagonals and negative for those below the main diagonal. The values may be: * expressions or single-argument functions, * lists or tuples of values, * matrices Unless dimensions are given, the size of the returned matrix will be large enough to contain the largest non-zero value provided. kwargs ====== rows : rows of the resulting matrix; computed if not given. cols : columns of the resulting matrix; computed if not given. Examples ======== >>> from sympy import banded, ones, Matrix >>> from sympy.abc import x If explicit values are given in tuples, the matrix will autosize to contain all values, otherwise a single value is filled onto the entire diagonal: >>> banded({1: (1, 2, 3), -1: (4, 5, 6), 0: x}) Matrix([ [x, 1, 0, 0], [4, x, 2, 0], [0, 5, x, 3], [0, 0, 6, x]]) A function accepting a single argument can be used to fill the diagonal as a function of diagonal index (which starts at 0). The size (or shape) of the matrix must be given to obtain more than a 1x1 matrix: >>> s = lambda d: (1 + d)**2 >>> banded(5, {0: s, 2: s, -2: 2}) Matrix([ [1, 0, 1, 0, 0], [0, 4, 0, 4, 0], [2, 0, 9, 0, 9], [0, 2, 0, 16, 0], [0, 0, 2, 0, 25]]) The diagonal of matrices placed on a diagonal will coincide with the indicated diagonal: >>> vert = Matrix([1, 2, 3]) >>> banded({0: vert}, cols=3) Matrix([ [1, 0, 0], [2, 1, 0], [3, 2, 1], [0, 3, 2], [0, 0, 3]]) >>> banded(4, {0: ones(2)}) Matrix([ [1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 1, 1], [0, 0, 1, 1]]) Errors are raised if the designated size will not hold all values an integral number of times. Here, the rows are designated as odd (but an even number is required to hold the off-diagonal 2x2 ones): >>> banded({0: 2, 1: ones(2)}, rows=5) Traceback (most recent call last): ... ValueError: sequence does not fit an integral number of times in the matrix And here, an even number of rows is given...but the square matrix has an even number of columns, too. As we saw in the previous example, an odd number is required: >>> banded(4, {0: 2, 1: ones(2)}) # trying to make 4x4 and cols must be odd Traceback (most recent call last): ... ValueError: sequence does not fit an integral number of times in the matrix A way around having to count rows is to enclosing matrix elements in a tuple and indicate the desired number of them to the right: >>> banded({0: 2, 2: (ones(2),)*3}) Matrix([ [2, 0, 1, 1, 0, 0, 0, 0], [0, 2, 1, 1, 0, 0, 0, 0], [0, 0, 2, 0, 1, 1, 0, 0], [0, 0, 0, 2, 1, 1, 0, 0], [0, 0, 0, 0, 2, 0, 1, 1], [0, 0, 0, 0, 0, 2, 1, 1]]) An error will be raised if more than one value is written to a given entry. Here, the ones overlap with the main diagonal if they are placed on the first diagonal: >>> banded({0: (2,)*5, 1: (ones(2),)*3}) Traceback (most recent call last): ... ValueError: collision at (1, 1) By placing a 0 at the bottom left of the 2x2 matrix of ones, the collision is avoided: >>> u2 = Matrix([ ... [1, 1], ... [0, 1]]) >>> banded({0: [2]*5, 1: [u2]*3}) Matrix([ [2, 1, 1, 0, 0, 0, 0], [0, 2, 1, 0, 0, 0, 0], [0, 0, 2, 1, 1, 0, 0], [0, 0, 0, 2, 1, 0, 0], [0, 0, 0, 0, 2, 1, 1], [0, 0, 0, 0, 0, 0, 1]]) """ from sympy import Dict, Dummy, SparseMatrix try: if len(args) not in (1, 2, 3): raise TypeError if not isinstance(args[-1], (dict, Dict)): raise TypeError if len(args) == 1: rows = kwargs.get('rows', None) cols = kwargs.get('cols', None) if rows is not None: rows = as_int(rows) if cols is not None: cols = as_int(cols) elif len(args) == 2: rows = cols = as_int(args[0]) else: rows, cols = map(as_int, args[:2]) # fails with ValueError if any keys are not ints _ = all(as_int(k) for k in args[-1]) except (ValueError, TypeError): raise TypeError(filldedent( '''unrecognized input to banded: expecting [[row,] col,] {int: value}''')) def rc(d): # return row,col coord of diagonal start r = -d if d < 0 else 0 c = 0 if r else d return r, c smat = {} undone = [] tba = Dummy() # first handle objects with size for d, v in args[-1].items(): r, c = rc(d) # note: only list and tuple are recognized since this # will allow other Basic objects like Tuple # into the matrix if so desired if isinstance(v, (list, tuple)): extra = 0 for i, vi in enumerate(v): i += extra if is_sequence(vi): vi = SparseMatrix(vi) smat[r + i, c + i] = vi extra += min(vi.shape) - 1 else: smat[r + i, c + i] = vi elif is_sequence(v): v = SparseMatrix(v) rv, cv = v.shape if rows and cols: nr, xr = divmod(rows - r, rv) nc, xc = divmod(cols - c, cv) x = xr or xc do = min(nr, nc) elif rows: do, x = divmod(rows - r, rv) elif cols: do, x = divmod(cols - c, cv) else: do = 1 x = 0 if x: raise ValueError(filldedent(''' sequence does not fit an integral number of times in the matrix''')) j = min(v.shape) for i in range(do): smat[r, c] = v r += j c += j elif v: smat[r, c] = tba undone.append((d, v)) s = SparseMatrix(None, smat) # to expand matrices smat = s._smat # check for dim errors here if rows is not None and rows < s.rows: raise ValueError('Designated rows %s < needed %s' % (rows, s.rows)) if cols is not None and cols < s.cols: raise ValueError('Designated cols %s < needed %s' % (cols, s.cols)) if rows is cols is None: rows = s.rows cols = s.cols elif rows is not None and cols is None: cols = max(rows, s.cols) elif cols is not None and rows is None: rows = max(cols, s.rows) def update(i, j, v): # update smat and make sure there are # no collisions if v: if (i, j) in smat and smat[i, j] not in (tba, v): raise ValueError('collision at %s' % ((i, j),)) smat[i, j] = v if undone: for d, vi in undone: r, c = rc(d) v = vi if callable(vi) else lambda _: vi i = 0 while r + i < rows and c + i < cols: update(r + i, c + i, v(i)) i += 1 return SparseMatrix(rows, cols, smat)
def evalf(self, n=15, subs=None, maxn=100, chop=False, strict=False, quad=None, verbose=False): """ Evaluate the given formula to an accuracy of n digits. Optional keyword arguments: subs=<dict> Substitute numerical values for symbols, e.g. subs={x:3, y:1+pi}. The substitutions must be given as a dictionary. maxn=<integer> Allow a maximum temporary working precision of maxn digits (default=100) chop=<bool> Replace tiny real or imaginary parts in subresults by exact zeros (default=False) strict=<bool> Raise PrecisionExhausted if any subresult fails to evaluate to full accuracy, given the available maxprec (default=False) quad=<str> Choose algorithm for numerical quadrature. By default, tanh-sinh quadrature is used. For oscillatory integrals on an infinite interval, try quad='osc'. verbose=<bool> Print debug information (default=False) """ from sympy import Float, Number n = n if n is not None else 15 if subs and is_sequence(subs): raise TypeError('subs must be given as a dictionary') # for sake of sage that doesn't like evalf(1) if n == 1 and isinstance(self, Number): from sympy.core.expr import _mag rv = self.evalf(2, subs, maxn, chop, strict, quad, verbose) m = _mag(rv) rv = rv.round(1 - m) return rv if not evalf_table: _create_evalf_table() prec = dps_to_prec(n) options = {'maxprec': max(prec, int(maxn*LG10)), 'chop': chop, 'strict': strict, 'verbose': verbose} if subs is not None: options['subs'] = subs if quad is not None: options['quad'] = quad try: result = evalf(self, prec + 4, options) except NotImplementedError: # Fall back to the ordinary evalf v = self._eval_evalf(prec) if v is None: return self try: # If the result is numerical, normalize it result = evalf(v, prec, options) except NotImplementedError: # Probably contains symbols or unknown functions return v re, im, re_acc, im_acc = result if re: p = max(min(prec, re_acc), 1) re = Float._new(re, p) else: re = S.Zero if im: p = max(min(prec, im_acc), 1) im = Float._new(im, p) return re + im*S.ImaginaryUnit else: return re