K iNzdZddlmZddlmZmZmZmZmZddl m Z m Z ddl m Z ddlmZddlmZddlmZmZdd lmZmZmZmZmZdd lmZmZmZmZm Z m!Z!dd l"m#Z#dd l$m%Z%dd l&m'Z'm(Z(m)Z)m*Z*ddl+m,Z,e,jZe,j\fe dfgZ/dZ0dZ1dZ2dZ3dZ4GddZ5GddZ6dZ7ddZ8d dZ9 d!dZ:dZ;y)"z3 Tools for doing common subexpression elimination. ) defaultdict)BasicMulAddPowsympify)Tuple OrderedSet) factor_terms)S)ordered)symbolsSymbol) MatrixBaseMatrixImmutableMatrix SparseMatrixImmutableSparseMatrix) MatrixExpr MatrixSymbolMatMulMatAddMatPowInverse) MatrixElement)RootOf)numbered_symbolssifttopological_sortiterable)cse_optsNc"t|}g}t|D]@\}\}}t|D]*\}\}}||jvs|j||f,Bt t t ||fDcgc]}|| c}Scc}w)a(Sort replacements ``r`` so (k1, v1) appears before (k2, v2) if k2 is in v1's free symbols. This orders items in the way that cse returns its results (hence, in order to use the replacements in a substitution option it would make sense to reverse the order). Examples ======== >>> from sympy.simplify.cse_main import reps_toposort >>> from sympy.abc import x, y >>> from sympy import Eq >>> for l, r in reps_toposort([(x, y + 1), (y, 2)]): ... print(Eq(l, r)) ... Eq(y, 2) Eq(x, y + 1) )r enumerate free_symbolsappendrrangelen) rEc1k1v1c2k2v2is ]/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/sympy/simplify/cse_main.py reps_toposortr3+s(  A A!! # HR%aL #LBRR__$"b" ##+E#a&M1+=> ?QAaD ?? ?s= B ct|d}||dDcgc]}|jc}z}|d}t||gScc}w)aMove expressions that are in the form (symbol, expr) out of the expressions and sort them into the replacements using the reps_toposort. Examples ======== >>> from sympy.simplify.cse_main import cse_separate >>> from sympy.abc import x, y, z >>> from sympy import cos, exp, cse, Eq, symbols >>> x0, x1 = symbols('x:2') >>> eq = (x + 1 + exp((x + 1)/(y + 1)) + cos(y + 1)) >>> cse([eq, Eq(x, z + 1), z - 2], postprocess=cse_separate) in [ ... [[(x0, y + 1), (x, z + 1), (x1, x + 1)], ... [x1 + exp(x1/x0) + cos(x0), z - 2]], ... [[(x1, y + 1), (x, z + 1), (x0, x + 1)], ... [x0 + exp(x0/x1) + cos(x1), z - 2]]] ... True cJ|jxr|jjSN) is_Equalitylhs is_Symbol)ws r2zcse_separate..\s!--;AEEOOTF)rargsr3)r)edr:s r2 cse_separater@HsL( Q;>> from sympy import cse >>> from sympy.simplify.cse_main import cse_release_variables >>> from sympy.abc import x, y >>> eqs = [(x + y - 1)**2, x, x + y, (x + y)/(2*x + 1) + (x + y - 1)**2, (2*x + 1)**(x + y)] >>> defs, rvs = cse_release_variables(*cse(eqs)) >>> for i in defs: ... print(i) ... (x0, x + y) (x1, (x0 - 1)**2) (x2, 2*x + 1) (_3, x0/x2 + x1) (_4, x2**x0) (x2, None) (_0, x1) (x1, None) (_2, x0) (x0, None) (_1, x) >>> print(rvs) (_0, _1, _2, _3, _4) z_:%dcPtfd|djzD S)Nc3bK|]&}j|j(ywr6)index count_ops).0r1pss r2 z:cse_release_variables....s.- QWWQZ=224-s,/r)sumr%)xin_userGrHs r2r;z'cse_release_variables..s-s-1""V+---r<keyr!rN) ziprr(listsetr'sortedpopr%extendstrr&reverse) r)r>esymssymsr1rv_pcrHrLrGs `@@r2cse_release_variablesr\bssD !t 7DAq FSVO $E ;D QA VF QA"'A-0Q!A$Q0A06! -./GAt :DFA B A A q& UUW R__ $ II&*<=Q4y= > A; IItxxz2& ' IIqtRj !!  Q q&JJL u9) 1>s .E< Fc0|D]\}}| ||}|S)a} Preprocess an expression to optimize for common subexpression elimination. Parameters ========== expr : SymPy expression The target expression to optimize. optimizations : list of (callable, callable) pairs The (preprocessor, postprocessor) pairs. Returns ======= expr : SymPy expression The transformed expression. expr optimizationspreposts r2preprocess_for_cserds,$# T ?t9D Kr<cBt|D]\}}| ||}|S)a)Postprocess an expression after common subexpression elimination to return the expression to canonical SymPy form. Parameters ========== expr : SymPy expression The target expression to transform. optimizations : list of (callable, callable) pairs, optional The (preprocessor, postprocessor) pairs. The postprocessors will be applied in reversed order to undo the effects of the preprocessors correctly. Returns ======= expr : SymPy expression The transformed expression. )reversedr_s r2postprocess_for_csergs2(m, T  :D Kr<c>eZdZdZdZdZdZdZd dZd dZ d Z y) FuncArgTrackerz} A class which manages a mapping from functions to arguments and an inverse mapping from arguments to functions. cNi|_g|_g|_g|_t |D]{\}}t }|j D]B}|j|}|j||j|j|D|jj|}yr6) value_numbersvalue_number_to_valuearg_to_funcsetfunc_to_argsetr$r r=get_or_add_value_numberaddr&)selffuncsfunc_ifunc func_argsetfunc_arg arg_numbers r2__init__zFuncArgTracker.__init__s %'"! %e, 4LFD$,K II <!99(C  +##J/33F; <    & &{ 3 4r<cXt|Dcgc]}|j|c}Scc}w)zh Return the list of arguments in sorted order according to their value numbers. )rRrl)rqargsetargns r2get_args_in_value_orderz&FuncArgTracker.get_args_in_value_orders( >DF^LT**40LLLs'ct|j}|jj||}||k(r>|jj ||j j t |S)zA Return the value number for the given argument. )r(rk setdefaultrlr&rmr )rqvaluenvalues value_numbers r2roz&FuncArgTracker.get_or_add_value_numbersdd(()))44UGD 7 "  & & - -e 4    & &z| 4r<ch|j|D] }|j|j|"y)zS Remove the function func_i from the argument to function mapping. N)rnrmremove)rqrsargs r2stop_arg_trackingz FuncArgTracker.stop_arg_trackings7&&v. 4C    $ + +F 3 4r<ctd}|s|S|Dcgc]}|j|}}t|t}|D]!}||ur|D]}||k\s ||xxdz cc<#t ||gt\} } | D]}||dkr || vs||xxdz cc<|j D cic]\} } | dk\s | | c} } Scc}wcc} } w)aReturn a dict whose keys are function numbers. The entries of the dict are the number of arguments said function has in common with ``argset``. Entries have at least 2 items in common. All keys have value at least ``min_func_i``. cy)Nrr^r^r<r2r;z:FuncArgTracker.get_common_arg_candidates..sr<rMr!)rrmmaxr(rRitems) rqrz min_func_i count_maprfuncsetslargest_funcsetfuncsetrssmaller_funcs_containerlarger_funcs_containerkvs r2get_common_arg_candidatesz(FuncArgTracker.get_common_arg_candidatess  *  8>?D'',??hC0 +G')! +Z'f%*% + +$*!9-$ ! . 'F 1$//&!Q&! '"+!2=Aa1f1==9@8>sC/ C =C Nct|}td|jt|D}|||z}|D]}||j|z}|S)z Return a set of functions each of which whose argument list contains ``argset``, optionally filtered only to contain functions in ``restrict_to_funcset``. c3 K|]}|ywr6r^)rFfis r2rIz7FuncArgTracker.get_subset_candidates..>s:B:s )iterr rmnext)rqrzrestrict_to_funcsetiargindicesrs r2get_subset_candidatesz$FuncArgTracker.get_subset_candidates6sq F|:,,T$Z8::  * * *G 0C t**3/ /G 0r<cNt|}|j|}||z D] }|j|j|"||z D] }|j|j |"|j|j |j|j |y)z@ Update a function with a new set of arguments. N)r rnrmrrpclearupdate)rqrs new_argsetnew_argsold_args deleted_arg added_args r2update_func_argsetz!FuncArgTracker.update_func_argsetIsj)&&v.#h. P& 5r<ric2eZdZdZdZdZedZeZy) Unevaluatedc ||_||_yr6rtr=)rqrtr=s r2rxzUnevaluated.__init__[s  r<czdj|jdjd|jDS)NzUneval<{}>({})z, c32K|]}t|ywr6)rU)rFas r2rIz&Unevaluated.__str__..as$?SV$?s)formatrtjoinr=rqs r2__str__zUnevaluated.__str___s3&& 499$?TYY$??A Ar<c:|j|jddiS)NevaluateFrrs r2as_unevaluated_basicz Unevaluated.as_unevaluated_basiccstyy$))4e44r<c~tj|jDcgc]}|jc}Scc}wr6)rQunionr=r%)rqrs r2r%zUnevaluated.free_symbolsfs+su{{TYY?Q^^?@@?s:N) rrrrxrrpropertyr%__repr__r^r<r2rrYs/A5AAHr<rc t|d}t|}t}tt |D]'}|j |j ||dzttjfd}|r|jd}|j |j|j |}t |dkrO|j |j|} | r]t||j|} |j| } |j|| t| gz|j|n|j||} |j |j|} |j|| t| gz|j||j!||D]P} |j | j|}|j| |t| gz|j| R|r||vr.t||j|j ||||<|j#|*y) aw Recognize and extract common subexpressions of function arguments within a set of function calls. For instance, for the following function calls:: x + z + y sin(x + y) this will extract a common subexpression of `x + y`:: w = x + y w + z sin(w) The function we work with is assumed to be associative and commutative. Parameters ========== func_class: class The function class (e.g. Add, Mul) funcs: list of functions A list of function calls. opt_subs: dict A dictionary of substitutions which this function may update. c,t|jSr6)r(r=)fs r2r;z#match_common_args..sAFF r<rMr!)rc||fSr6r^)rcommon_arg_candidates_countss r2r;z#match_common_args..s;A>Br<F)lastN)rRrir r'r(rrnkeysrS intersection differencerr|rorrprr) func_classrropt_subs arg_trackerchangedr1common_arg_candidatesjcom_argsdiff_icom_funccom_func_numberdiff_jrdiff_krs @r2match_common_argsrms_: 53 4E 'KlG 3u: 9)'2'L'L**1-!a%(M(A$ !+6,113B,D!E$%))u)5A"11!4AA..q13H8}! !//2==hGF&"K$G$G$QS"-"E"Eh"O..q&:FW;X2XY A#."E"EeAh"O //2==hGF  * *1fz?BS7T.T U KKN 6635 $33A6AA(K..q&:FW;X2XY A  K$V >> from sympy.simplify.cse_main import opt_cse >>> from sympy.abc import x >>> opt_subs = opt_cse([x**-2]) >>> k, v = list(opt_subs.keys())[0], list(opt_subs.values())[0] >>> print((k, v.as_unevaluated_basic())) (x**(-2), 1/(x**2)) c\t|ttfsy|js |jryt |rt t|y| vr|S j|t t|jt|ts|jrot|trtd|jD}n| }|js6tttj|f|< j||}t|tt fr._find_opts..s 7! 7s r!) isinstancerris_Atomis_Orderr rPmaprpr=rcould_extract_minus_signrrr NegativeOnerr(rrrrbaseexp) r`neg_exprrr _find_optsaddscollapsible_subexpmulsr seen_subexps r2rzopt_cse.._find_optss$ 45  <<4==  D> Z& '  ; K STYY '($ +0M0M0O$$ 7TYY 78 5##!,S1==(2K!L) dS&M *499~""&&t, sFm ,499~""&&t, g &  sFm , 488#D++-!,S3tcT?B2G!H.-r<rF)csetr!r)r)r rQrrrr=rfrgetargs_cncrtrr(rprrr)exprsorderr>rHedgescommutative_mulsmr[ncc_mulnew_objrrrrrrs @@@@@@r2opt_csers:H ._find_repeatedds$ 45  dF #  dE "  4, !>?~~ $$TYY/  D>D{"!Cd///!$$T* OOD !x~99D S &'r<c3@K|]}|jvs|ywr6)r)rF_rs r2rIztree_cse..sDQQVV3C%CqDsct|ttfs|S|js|St |r.|jDcgc] } | }}|j |S| vr |S|}| vr |} dk7rt|t tfr4|j\}}|dgk(r|}nftt||z}nNt|ttfrtt|j}n|j}n |j}tt |}t|ts||k7r|j |}n|}|vra t}t|t"r+t%|j&|j(|j*}| |< j-||f|S|Scc}w#t$r t!dwxYw)Nnoner!z$Symbols iterator ran out of symbols.)rrrr=r rtrrrrPr rrrr StopIteration ValueErrorrrrrowscolsr&)r`rr orig_exprr[rr=new_exprsym_rebuildrr replacementssubsrrs r2rztree_cse.._rebuilds$ 45KyyK D>15;# ;H;499h' ' 4<:  8 D>D F?$f . 28D +b0DD3-0GDII./yy99DHd+, dK (H,< tyy(+HH  $ I7m)Z0"388Y^^NN$"DO   h 0JO_ reduced_exprs reduced_errrrrrrs ```` @@@@@@@r2tree_cser Gs&5L%Ku"("(H a  1 E'DGL D77rM ( a   IIY' (  &&r<c 2|st||||||St|ttfr t |}t|t t fr|g}|}g}|D]} t| ttfr&|jt| j?t| ttfr4|jt| jj|j| |}~|g}n |dk(rt }|D cgc]} t#| |} } |t%t&}n t)|}t+| |} t-| || ||\} } |}| D cgc]\} }| t/||f} } }| D cgc]} t/| |} } t1|D]\}} t| ttfrOt| j2| j4| || |<t| tsT| |j7| |<kt| ttfst| j2| j4i}| |D] \}}|||< t| tr|j7}|| |<|| | fS|| | Scc} wcc}} wcc} w)as 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 The (preprocessor, postprocessor) pairs of external optimization functions. Optionally 'basic' can be passed for a set of predefined basic optimizations. Such 'basic' optimizations were used by default in old implementation, however they can be really slow on larger expressions. Now, no pre or post optimizations are made by default. 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 order : string, 'none' or 'canonical' The order by which Mul and Add arguments are processed. If set to 'canonical', arguments will be canonically ordered. If set to 'none', ordering will be faster but dependent on expressions hashes, thus machine dependent and variable. 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. list : bool, (default True) Returns expression in list or else with same type as input (when False). 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. Examples ======== >>> from sympy import cse, SparseMatrix >>> from sympy.abc import x, y, z, w >>> cse(((w + x + y + z)*(w + y + z))/(w + x)**3) ([(x0, y + z), (x1, w + x)], [(w + x0)*(x0 + x1)/x1**3]) List of expressions with recursive substitutions: >>> m = SparseMatrix([x + y, x + y + z]) >>> cse([(x+y)**2, x + y + z, y + z, x + z + y, m]) ([(x0, x + y), (x1, x0 + z)], [x0**2, x1, y + z, x1, Matrix([ [x0], [x1]])]) Note: the type and mutability of input matrices is retained. >>> isinstance(_[1][-1], SparseMatrix) True The user may disallow substitutions containing certain symbols: >>> cse([y**2*(x + 1), 3*y**2*(x + 1)], ignore=(y,)) ([(x0, x + 1)], [x0*y**2, 3*x0*y**2]) The default return value for the reduced expression(s) is a list, even if there is only one expression. The `list` flag preserves the type of the input in the output: >>> cse(x) ([], [x]) >>> cse(x, list=False) ([], x) )rra postprocessrrbasic)cls)_cse_homogeneousrintfloatrrrrrr&r flatrrtodokrbasic_optimizationsrdrrrrr rgr$rr as_immutable)rrrar rrrPcopytempr>rrrrsubtreer1rrrs r2csers` =#5A A%#u&%%,- D D  a&/2 3 KKqvvx( ) L*?@ A KKqwwy01 2 KKN  E  ' !+ DIIa'=9IMI"v.w-}e,H#+='8+0&#:L- E(46$W-g}EF6L6,-)M:-M-% !1 a&/2 3%affaffmA6FGM! !_-#0#3#@#@#B a L*?@ AQVVQVVR0A%a( 1! !23NN$ M!  !]** |] 33QJ$6-sJ J>Jc t|tr%tt|fi|\}}|t |fSt|t t tfr"t|fi|\}}|t||fSt|trRt |j}t|Dcgc]}|| c}fi|\}}tt||}||fS t|fi|\}\}||fScc}w#t$rg|fcYSwxYw)aM Same as ``cse`` but the ``reduced_exprs`` are returned with the same type as ``exprs`` or a sympified version of the same. Parameters ========== exprs : an Expr, iterable of Expr or dictionary with Expr values the expressions in which repeated subexpressions will be identified kwargs : additional arguments for the ``cse`` function 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. Examples ======== >>> from sympy.simplify.cse_main import cse >>> from sympy import cos, Tuple, Matrix >>> from sympy.abc import x >>> output = lambda x: type(cse(x, list=False)[1]) >>> output(1) >>> output('cos(x)') >>> output(cos(x)) cos >>> output(Tuple(1, x)) >>> output(Matrix([[1,0], [0,1]])) >>> output([1, x]) >>> output((1, x)) >>> output({1, x}) )rrUrrreprrPtuplerQrtypedictrrO TypeError)rkwargsrrrrvaluess r2rrqs\%&6 EN'&$'&# mT-000%$s+,&)%&:6&:# m%[777%EJJL!"d#;E!H#;FvF fSv./ ]**+),U)=f)=& &}]**$< 5ys% C+C00 D?D) canonical)Nr!r^)NNNr!r^T)r1s#443-"&-AAAA<*##!(((*;*;<$d+-@:!4@L04|5|5~([)|yxN'b>B+/V4r@+r<