本文整理汇总了Python中sympy.utilities.iterables.ordered函数的典型用法代码示例。如果您正苦于以下问题:Python ordered函数的具体用法?Python ordered怎么用?Python ordered使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了ordered函数的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Python代码示例。
示例1: _rebuild
def _rebuild(expr):
if not isinstance(expr, Basic):
return expr
if not expr.args:
return expr
if iterable(expr):
new_args = [_rebuild(arg) for arg in expr]
return expr.func(*new_args)
if expr in subs:
return subs[expr]
orig_expr = expr
if expr in opt_subs:
expr = opt_subs[expr]
# If enabled, parse Muls and Adds arguments by order to ensure
# replacement order independent from hashes
if order != 'none':
if isinstance(expr, (Mul, MatMul)):
c, nc = expr.args_cnc()
if c == [1]:
args = nc
else:
args = list(ordered(c)) + nc
elif isinstance(expr, (Add, MatAdd)):
args = list(ordered(expr.args))
else:
args = expr.args
else:
args = expr.args
new_args = list(map(_rebuild, args))
if new_args != args:
new_expr = expr.func(*new_args)
else:
new_expr = expr
if orig_expr in to_eliminate:
try:
sym = next(symbols)
except StopIteration:
raise ValueError("Symbols iterator ran out of symbols.")
if isinstance(orig_expr, MatrixExpr):
sym = MatrixSymbol(sym.name, orig_expr.rows,
orig_expr.cols)
subs[orig_expr] = sym
replacements.append((sym, new_expr))
return sym
else:
return new_expr
示例2: _match_common_args
def _match_common_args(Func, funcs):
if order != 'none':
funcs = list(ordered(funcs))
else:
funcs = sorted(funcs, key=lambda x: len(x.args))
func_args = [set(e.args) for e in funcs]
for i in xrange(len(func_args)):
for j in xrange(i + 1, len(func_args)):
com_args = func_args[i].intersection(func_args[j])
if len(com_args) > 1:
com_func = Func(*com_args)
# for all sets, replace the common symbols by the function
# over them, to allow recursive matches
diff_i = func_args[i].difference(com_args)
func_args[i] = diff_i | set([com_func])
if diff_i:
opt_subs[funcs[i]] = Func(Func(*diff_i), com_func,
evaluate=False)
diff_j = func_args[j].difference(com_args)
func_args[j] = diff_j | set([com_func])
opt_subs[funcs[j]] = Func(Func(*diff_j), com_func,
evaluate=False)
for k in xrange(j + 1, len(func_args)):
if not com_args.difference(func_args[k]):
diff_k = func_args[k].difference(com_args)
func_args[k] = diff_k | set([com_func])
opt_subs[funcs[k]] = Func(Func(*diff_k), com_func,
evaluate=False)
示例3: _eval_simplify
def _eval_simplify(self, ratio, measure, rational, inverse):
args = [a._eval_simplify(ratio, measure, rational, inverse)
for a in self.args]
for i, (expr, cond) in enumerate(args):
# try to simplify conditions and the expression for
# equalities that are part of the condition, e.g.
# Piecewise((n, And(Eq(n,0), Eq(n + m, 0))), (1, True))
# -> Piecewise((0, And(Eq(n, 0), Eq(m, 0))), (1, True))
if isinstance(cond, And):
eqs, other = sift(cond.args,
lambda i: isinstance(i, Equality), binary=True)
elif isinstance(cond, Equality):
eqs, other = [cond], []
else:
eqs = other = []
if eqs:
eqs = list(ordered(eqs))
for j, e in enumerate(eqs):
# these blessed lhs objects behave like Symbols
# and the rhs are simple replacements for the "symbols"
if isinstance(e.lhs, (Symbol, UndefinedFunction)) and \
isinstance(e.rhs,
(Rational, NumberSymbol,
Symbol, UndefinedFunction)):
expr = expr.subs(*e.args)
eqs[j + 1:] = [ei.subs(*e.args) for ei in eqs[j + 1:]]
other = [ei.subs(*e.args) for ei in other]
cond = And(*(eqs + other))
args[i] = args[i].func(expr, cond)
return self.func(*args)
示例4: _rebuild
def _rebuild(expr):
if expr.is_Atom:
return expr
if iterable(expr):
new_args = [_rebuild(arg) for arg in expr]
return expr.func(*new_args)
if expr in subs:
return subs[expr]
orig_expr = expr
if expr in opt_subs:
expr = opt_subs[expr]
# If enabled, parse Muls and Adds arguments by order to ensure
# replacement order independent from hashes
if order != 'none':
if expr.is_Mul:
c, nc = expr.args_cnc()
args = list(ordered(c)) + nc
elif expr.is_Add:
args = list(ordered(expr.args))
else:
args = expr.args
else:
args = expr.args
new_args = list(map(_rebuild, args))
if new_args != args:
new_expr = expr.func(*new_args)
else:
new_expr = expr
if orig_expr in to_eliminate:
try:
sym = next(symbols)
except StopIteration:
raise ValueError("Symbols iterator ran out of symbols.")
subs[orig_expr] = sym
replacements.append((sym, new_expr))
return sym
else:
return new_expr
示例5: test_ordered
def test_ordered():
assert list(ordered((x, y), hash, default=False)) in [[x, y], [y, x]]
assert list(ordered((x, y), hash, default=False)) == list(ordered((y, x), hash, default=False))
assert list(ordered((x, y))) == [x, y]
seq, keys = [[[1, 2, 1], [0, 3, 1], [1, 1, 3], [2], [1]], (lambda x: len(x), lambda x: sum(x))]
assert list(ordered(seq, keys, default=False, warn=False)) == [[1], [2], [1, 2, 1], [0, 3, 1], [1, 1, 3]]
raises(ValueError, lambda: list(ordered(seq, keys, default=False, warn=True)))
示例6: __repr__
def __repr__(self): # Factors
return "Factors({%s})" % ', '.join(
['%s: %s' % (k, v) for k, v in ordered(self.factors.items())])
示例7: __hash__
def __hash__(self): # Factors
keys = tuple(ordered(self.factors.keys()))
values = [self.factors[k] for k in keys]
return hash((keys, values))
示例8: _handle_irel
def _handle_irel(self, x, handler):
"""Return either None (if the conditions of self depend only on x) else
a Piecewise expression whose expressions (handled by the handler that
was passed) are paired with the governing x-independent relationals,
e.g. Piecewise((A, a(x) & b(y)), (B, c(x) | c(y)) ->
Piecewise(
(handler(Piecewise((A, a(x) & True), (B, c(x) | True)), b(y) & c(y)),
(handler(Piecewise((A, a(x) & True), (B, c(x) | False)), b(y)),
(handler(Piecewise((A, a(x) & False), (B, c(x) | True)), c(y)),
(handler(Piecewise((A, a(x) & False), (B, c(x) | False)), True))
"""
# identify governing relationals
rel = self.atoms(Relational)
irel = list(ordered([r for r in rel if x not in r.free_symbols
and r not in (S.true, S.false)]))
if irel:
args = {}
exprinorder = []
for truth in product((1, 0), repeat=len(irel)):
reps = dict(zip(irel, truth))
# only store the true conditions since the false are implied
# when they appear lower in the Piecewise args
if 1 not in truth:
cond = None # flag this one so it doesn't get combined
else:
andargs = Tuple(*[i for i in reps if reps[i]])
free = list(andargs.free_symbols)
if len(free) == 1:
from sympy.solvers.inequalities import (
reduce_inequalities, _solve_inequality)
try:
t = reduce_inequalities(andargs, free[0])
# ValueError when there are potentially
# nonvanishing imaginary parts
except (ValueError, NotImplementedError):
# at least isolate free symbol on left
t = And(*[_solve_inequality(
a, free[0], linear=True)
for a in andargs])
else:
t = And(*andargs)
if t is S.false:
continue # an impossible combination
cond = t
expr = handler(self.xreplace(reps))
if isinstance(expr, self.func) and len(expr.args) == 1:
expr, econd = expr.args[0]
cond = And(econd, True if cond is None else cond)
# the ec pairs are being collected since all possibilities
# are being enumerated, but don't put the last one in since
# its expr might match a previous expression and it
# must appear last in the args
if cond is not None:
args.setdefault(expr, []).append(cond)
# but since we only store the true conditions we must maintain
# the order so that the expression with the most true values
# comes first
exprinorder.append(expr)
# convert collected conditions as args of Or
for k in args:
args[k] = Or(*args[k])
# take them in the order obtained
args = [(e, args[e]) for e in uniq(exprinorder)]
# add in the last arg
args.append((expr, True))
# if any condition reduced to True, it needs to go last
# and there should only be one of them or else the exprs
# should agree
trues = [i for i in range(len(args)) if args[i][1] is S.true]
if not trues:
# make the last one True since all cases were enumerated
e, c = args[-1]
args[-1] = (e, S.true)
else:
assert len(set([e for e, c in [args[i] for i in trues]])) == 1
args.append(args.pop(trues.pop()))
while trues:
args.pop(trues.pop())
return Piecewise(*args)
示例9: __repr__
def __repr__(self): # Factors
return "Factors({%s})" % ", ".join(["%s: %s" % (k, v) for k, v in ordered(self.factors.items())])
示例10: _match_common_args
def _match_common_args(Func, funcs):
if order != 'none':
funcs = list(ordered(funcs))
else:
funcs = sorted(funcs, key=lambda x: len(x.args))
if Func is Mul:
F = Pow
meth = 'as_powers_dict'
from sympy.core.add import _addsort as inplace_sorter
elif Func is Add:
F = Mul
meth = 'as_coefficients_dict'
from sympy.core.mul import _mulsort as inplace_sorter
else:
assert None # expected Mul or Add
# ----------------- helpers ---------------------------
def ufunc(*args):
# return a well formed unevaluated function from the args
# SHARES Func, inplace_sorter
args = list(args)
inplace_sorter(args)
return Func(*args, evaluate=False)
def as_dict(e):
# creates a dictionary of the expression using either
# as_coefficients_dict or as_powers_dict, depending on Func
# SHARES meth
d = getattr(e, meth, lambda: {a: S.One for a in e.args})()
for k in list(d.keys()):
try:
as_int(d[k])
except ValueError:
d[F(k, d.pop(k))] = S.One
return d
def from_dict(d):
# build expression from dict from
# as_coefficients_dict or as_powers_dict
# SHARES F
return ufunc(*[F(k, v) for k, v in d.items()])
def update(k):
# updates all of the info associated with k using
# the com_dict: func_dicts, func_args, opt_subs
# returns True if all values were updated, else None
# SHARES com_dict, com_func, func_dicts, func_args,
# opt_subs, funcs, verbose
for di in com_dict:
# don't allow a sign to change
if com_dict[di] > func_dicts[k][di]:
return
# remove it
if Func is Add:
take = min(func_dicts[k][i] for i in com_dict)
com_func_take = Mul(take, from_dict(com_dict), evaluate=False)
else:
take = igcd(*[func_dicts[k][i] for i in com_dict])
com_func_take = Pow(from_dict(com_dict), take, evaluate=False)
for di in com_dict:
func_dicts[k][di] -= take*com_dict[di]
# compute the remaining expression
rem = from_dict(func_dicts[k])
# reject hollow change, e.g extracting x + 1 from x + 3
if Func is Add and rem and rem.is_Integer and 1 in com_dict:
return
if verbose:
print('\nfunc %s (%s) \ncontains %s \nas %s \nleaving %s' %
(funcs[k], func_dicts[k], com_func, com_func_take, rem))
# recompute the dict since some keys may now
# have corresponding values of 0; one could
# keep track of which ones went to zero but
# this seems cleaner
func_dicts[k] = as_dict(rem)
# update associated info
func_dicts[k][com_func] = take
func_args[k] = set(func_dicts[k])
# keep the constant separate from the remaining
# part of the expression, e.g. 2*(a*b) rather than 2*a*b
opt_subs[funcs[k]] = ufunc(rem, com_func_take)
# everything was updated
return True
def get_copy(i):
return [func_dicts[i].copy(), func_args[i].copy(), funcs[i], i]
def restore(dafi):
i = dafi.pop()
func_dicts[i], func_args[i], funcs[i] = dafi
# ----------------- end helpers -----------------------
func_dicts = [as_dict(f) for f in funcs]
func_args = [set(d) for d in func_dicts]
while True:
hit = pairwise_most_common(func_args)
if not hit or len(hit[0][0]) <= 1:
break
changed = False
#.........这里部分代码省略.........
示例11: cse
def cse(exprs, symbols=None, optimizations=None, postprocess=None):
""" Perform common subexpression elimination on an expression.
Parameters
==========
exprs : list of sympy expressions, or a single sympy expression
The expressions to reduce.
symbols : infinite iterator yielding unique Symbols
The symbols used to label the common subexpressions which are pulled
out. The ``numbered_symbols`` generator is useful. The default is a
stream of symbols of the form "x0", "x1", etc. This must be an infinite
iterator.
optimizations : list of (callable, callable) pairs, optional
The (preprocessor, postprocessor) pairs. If not provided,
``sympy.simplify.cse.cse_optimizations`` is used.
postprocess : a function which accepts the two return values of cse and
returns the desired form of output from cse, e.g. if you want the
replacements reversed the function might be the following lambda:
lambda r, e: return reversed(r), e
Returns
=======
replacements : list of (Symbol, expression) pairs
All of the common subexpressions that were replaced. Subexpressions
earlier in this list might show up in subexpressions later in this list.
reduced_exprs : list of sympy expressions
The reduced expressions with all of the replacements above.
"""
from sympy.matrices import Matrix
if symbols is None:
symbols = numbered_symbols()
else:
# In case we get passed an iterable with an __iter__ method instead of
# an actual iterator.
symbols = iter(symbols)
tmp_symbols = numbered_symbols('_csetmp')
subexp_iv = dict()
muls = set()
adds = set()
if optimizations is None:
# Pull out the default here just in case there are some weird
# manipulations of the module-level list in some other thread.
optimizations = list(cse_optimizations)
# Handle the case if just one expression was passed.
if isinstance(exprs, Basic):
exprs = [exprs]
# Preprocess the expressions to give us better optimization opportunities.
prep_exprs = [preprocess_for_cse(e, optimizations) for e in exprs]
# Find all subexpressions.
def _parse(expr):
if expr.is_Atom:
# Exclude atoms, since there is no point in renaming them.
return expr
if iterable(expr):
return expr
subexpr = type(expr)(*map(_parse, expr.args))
if subexpr in subexp_iv:
return subexp_iv[subexpr]
if subexpr.is_Mul:
muls.add(subexpr)
elif subexpr.is_Add:
adds.add(subexpr)
ivar = next(tmp_symbols)
subexp_iv[subexpr] = ivar
return ivar
tmp_exprs = list()
for expr in prep_exprs:
if isinstance(expr, Basic):
tmp_exprs.append(_parse(expr))
else:
tmp_exprs.append(expr)
# process adds - any adds that weren't repeated might contain
# subpatterns that are repeated, e.g. x+y+z and x+y have x+y in common
adds = list(ordered(adds))
addargs = [set(a.args) for a in adds]
for i in xrange(len(addargs)):
for j in xrange(i + 1, len(addargs)):
com = addargs[i].intersection(addargs[j])
if len(com) > 1:
add_subexp = Add(*com)
diff_add_i = addargs[i].difference(com)
diff_add_j = addargs[j].difference(com)
#.........这里部分代码省略.........
示例12: _collapse_arguments
def _collapse_arguments(cls, args, **assumptions):
"""Remove redundant args.
Examples
========
>>> from sympy import Min, Max
>>> from sympy.abc import a, b, c, d, e
Any arg in parent that appears in any
parent-like function in any of the flat args
of parent can be removed from that sub-arg:
>>> Min(a, Max(b, Min(a, c, d)))
Min(a, Max(b, Min(c, d)))
If the arg of parent appears in an opposite-than parent
function in any of the flat args of parent that function
can be replaced with the arg:
>>> Min(a, Max(b, Min(c, d, Max(a, e))))
Min(a, Max(b, Min(a, c, d)))
"""
from sympy.utilities.iterables import ordered
from sympy.simplify.simplify import walk
if not args:
return args
args = list(ordered(args))
if cls == Min:
other = Max
else:
other = Min
# find global comparable max of Max and min of Min if a new
# value is being introduced in these args at position 0 of
# the ordered args
if args[0].is_number:
sifted = mins, maxs = [], []
for i in args:
for v in walk(i, Min, Max):
if v.args[0].is_comparable:
sifted[isinstance(v, Max)].append(v)
small = Min.identity
for i in mins:
v = i.args[0]
if v.is_number and (v < small) == True:
small = v
big = Max.identity
for i in maxs:
v = i.args[0]
if v.is_number and (v > big) == True:
big = v
# at the point when this function is called from __new__,
# there may be more than one numeric arg present since
# local zeros have not been handled yet, so look through
# more than the first arg
if cls == Min:
for i in range(len(args)):
if not args[i].is_number:
break
if (args[i] < small) == True:
small = args[i]
elif cls == Max:
for i in range(len(args)):
if not args[i].is_number:
break
if (args[i] > big) == True:
big = args[i]
T = None
if cls == Min:
if small != Min.identity:
other = Max
T = small
elif big != Max.identity:
other = Min
T = big
if T is not None:
# remove numerical redundancy
for i in range(len(args)):
a = args[i]
if isinstance(a, other):
a0 = a.args[0]
if ((a0 > T) if other == Max else (a0 < T)) == True:
args[i] = cls.identity
# remove redundant symbolic args
def do(ai, a):
if not isinstance(ai, (Min, Max)):
return ai
cond = a in ai.args
if not cond:
return ai.func(*[do(i, a) for i in ai.args],
evaluate=False)
if isinstance(ai, cls):
return ai.func(*[do(i, a) for i in ai.args if i != a],
evaluate=False)
return a
for i, a in enumerate(args):
#.........这里部分代码省略.........
示例13: tree_cse
def tree_cse(exprs, symbols, opt_subs=None, order='canonical', ignore=()):
"""Perform raw CSE on expression tree, taking opt_subs into account.
Parameters
==========
exprs : list of sympy expressions
The expressions to reduce.
symbols : infinite iterator yielding unique Symbols
The symbols used to label the common subexpressions which are pulled
out.
opt_subs : dictionary of expression substitutions
The expressions to be substituted before any CSE action is performed.
order : string, 'none' or 'canonical'
The order by which Mul and Add arguments are processed. For large
expressions where speed is a concern, use the setting order='none'.
ignore : iterable of Symbols
Substitutions containing any Symbol from ``ignore`` will be ignored.
"""
from sympy.matrices.expressions import MatrixExpr, MatrixSymbol, MatMul, MatAdd
if opt_subs is None:
opt_subs = dict()
## Find repeated sub-expressions
to_eliminate = set()
seen_subexp = set()
def _find_repeated(expr):
if not isinstance(expr, Basic):
return
if expr.is_Atom or expr.is_Order:
return
if iterable(expr):
args = expr
else:
if expr in seen_subexp:
for ign in ignore:
if ign in expr.free_symbols:
break
else:
to_eliminate.add(expr)
return
seen_subexp.add(expr)
if expr in opt_subs:
expr = opt_subs[expr]
args = expr.args
list(map(_find_repeated, args))
for e in exprs:
if isinstance(e, Basic):
_find_repeated(e)
## Rebuild tree
replacements = []
subs = dict()
def _rebuild(expr):
if not isinstance(expr, Basic):
return expr
if not expr.args:
return expr
if iterable(expr):
new_args = [_rebuild(arg) for arg in expr]
return expr.func(*new_args)
if expr in subs:
return subs[expr]
orig_expr = expr
if expr in opt_subs:
expr = opt_subs[expr]
# If enabled, parse Muls and Adds arguments by order to ensure
# replacement order independent from hashes
if order != 'none':
if isinstance(expr, (Mul, MatMul)):
c, nc = expr.args_cnc()
if c == [1]:
args = nc
else:
args = list(ordered(c)) + nc
elif isinstance(expr, (Add, MatAdd)):
args = list(ordered(expr.args))
else:
args = expr.args
else:
#.........这里部分代码省略.........
示例14: _eval_simplify
def _eval_simplify(self, ratio, measure, rational, inverse):
args = [a._eval_simplify(ratio, measure, rational, inverse)
for a in self.args]
for i, (expr, cond) in enumerate(args):
# try to simplify conditions and the expression for
# equalities that are part of the condition, e.g.
# Piecewise((n, And(Eq(n,0), Eq(n + m, 0))), (1, True))
# -> Piecewise((0, And(Eq(n, 0), Eq(m, 0))), (1, True))
if isinstance(cond, And):
eqs, other = sift(cond.args,
lambda i: isinstance(i, Equality), binary=True)
elif isinstance(cond, Equality):
eqs, other = [cond], []
else:
eqs = other = []
if eqs:
eqs = list(ordered(eqs))
for j, e in enumerate(eqs):
# these blessed lhs objects behave like Symbols
# and the rhs are simple replacements for the "symbols"
if isinstance(e.lhs, (Symbol, UndefinedFunction)) and \
isinstance(e.rhs,
(Rational, NumberSymbol,
Symbol, UndefinedFunction)):
expr = expr.subs(*e.args)
eqs[j + 1:] = [ei.subs(*e.args) for ei in eqs[j + 1:]]
other = [ei.subs(*e.args) for ei in other]
cond = And(*(eqs + other))
args[i] = args[i].func(expr, cond)
# See if expressions valid for a single point happens to evaluate
# to the same function as in the next piecewise segment, see:
# https://github.com/sympy/sympy/issues/8458
prevexpr = None
for i, (expr, cond) in reversed(list(enumerate(args))):
if prevexpr is not None:
_prevexpr = prevexpr
_expr = expr
if isinstance(cond, And):
eqs, other = sift(cond.args,
lambda i: isinstance(i, Equality), binary=True)
elif isinstance(cond, Equality):
eqs, other = [cond], []
else:
eqs = other = []
if eqs:
eqs = list(ordered(eqs))
for j, e in enumerate(eqs):
# these blessed lhs objects behave like Symbols
# and the rhs are simple replacements for the "symbols"
if isinstance(e.lhs, (Symbol, UndefinedFunction)) and \
isinstance(e.rhs,
(Rational, NumberSymbol,
Symbol, UndefinedFunction)):
_prevexpr = _prevexpr.subs(*e.args)
_expr = _expr.subs(*e.args)
if _prevexpr == _expr:
args[i] = args[i].func(args[i+1][0], cond)
else:
prevexpr = expr
else:
prevexpr = expr
return self.func(*args)
示例15: piecewise_fold
def piecewise_fold(expr):
"""
Takes an expression containing a piecewise function and returns the
expression in piecewise form. In addition, any ITE conditions are
rewritten in negation normal form and simplified.
Examples
========
>>> from sympy import Piecewise, piecewise_fold, sympify as S
>>> from sympy.abc import x
>>> p = Piecewise((x, x < 1), (1, S(1) <= x))
>>> piecewise_fold(x*p)
Piecewise((x**2, x < 1), (x, True))
See Also
========
Piecewise
"""
if not isinstance(expr, Basic) or not expr.has(Piecewise):
return expr
new_args = []
if isinstance(expr, (ExprCondPair, Piecewise)):
for e, c in expr.args:
if not isinstance(e, Piecewise):
e = piecewise_fold(e)
# we don't keep Piecewise in condition because
# it has to be checked to see that it's complete
# and we convert it to ITE at that time
assert not c.has(Piecewise) # pragma: no cover
if isinstance(c, ITE):
c = c.to_nnf()
c = simplify_logic(c, form='cnf')
if isinstance(e, Piecewise):
new_args.extend([(piecewise_fold(ei), And(ci, c))
for ei, ci in e.args])
else:
new_args.append((e, c))
else:
from sympy.utilities.iterables import cartes, sift, common_prefix
# Given
# P1 = Piecewise((e11, c1), (e12, c2), A)
# P2 = Piecewise((e21, c1), (e22, c2), B)
# ...
# the folding of f(P1, P2) is trivially
# Piecewise(
# (f(e11, e21), c1),
# (f(e12, e22), c2),
# (f(Piecewise(A), Piecewise(B)), True))
# Certain objects end up rewriting themselves as thus, so
# we do that grouping before the more generic folding.
# The following applies this idea when f = Add or f = Mul
# (and the expression is commutative).
if expr.is_Add or expr.is_Mul and expr.is_commutative:
p, args = sift(expr.args, lambda x: x.is_Piecewise, binary=True)
pc = sift(p, lambda x: tuple([c for e,c in x.args]))
for c in list(ordered(pc)):
if len(pc[c]) > 1:
pargs = [list(i.args) for i in pc[c]]
# the first one is the same; there may be more
com = common_prefix(*[
[i.cond for i in j] for j in pargs])
n = len(com)
collected = []
for i in range(n):
collected.append((
expr.func(*[ai[i].expr for ai in pargs]),
com[i]))
remains = []
for a in pargs:
if n == len(a): # no more args
continue
if a[n].cond == True: # no longer Piecewise
remains.append(a[n].expr)
else: # restore the remaining Piecewise
remains.append(
Piecewise(*a[n:], evaluate=False))
if remains:
collected.append((expr.func(*remains), True))
args.append(Piecewise(*collected, evaluate=False))
continue
args.extend(pc[c])
else:
args = expr.args
# fold
folded = list(map(piecewise_fold, args))
for ec in cartes(*[
(i.args if isinstance(i, Piecewise) else
[(i, true)]) for i in folded]):
e, c = zip(*ec)
new_args.append((expr.func(*e), And(*c)))
return Piecewise(*new_args)