4242 SymbolFalse ,
4343 SymbolUndefined ,
4444 SymbolSequence ,
45+ SymbolList ,
4546 from_mpmath ,
4647 from_python ,
4748)
4849from mathics .core .numbers import min_prec , dps , SpecialValueError
4950
5051from mathics .builtin .lists import _IterationFunction
51- from mathics .core .convert import from_sympy , SympyExpression
52+ from mathics .core .convert import from_sympy , SympyExpression , sympy_symbol_prefix
53+ from mathics .builtin .scoping import dynamic_scoping
54+ from mathics .builtin .inference import get_assumptions_list , evaluate_predicate
5255
5356
5457@lru_cache (maxsize = 1024 )
@@ -741,7 +744,7 @@ def apply(self, items, evaluation):
741744 elif number .sameQ (Integer (- 1 )) and leaves and leaves [0 ].has_form ("Plus" , None ):
742745 leaves [0 ] = Expression (
743746 leaves [0 ].get_head (),
744- * [Expression ("Times" , Integer (- 1 ), leaf ) for leaf in leaves [0 ].leaves ]
747+ * [Expression ("Times" , Integer (- 1 ), leaf ) for leaf in leaves [0 ].leaves ],
745748 )
746749 number = None
747750
@@ -2222,7 +2225,7 @@ class Piecewise(SympyFunction):
22222225 ## Piecewise({{0, Or[x < 0, x > 0]}}, Indeterminate).
22232226
22242227 >> Integrate[Piecewise[{{1, x <= 0}, {-1, x > 0}}], x]
2225- = Piecewise[{{x, x <= 0}, {-x, True}} ]
2228+ = Piecewise[{{x, x <= 0}}, -x ]
22262229
22272230 >> Integrate[Piecewise[{{1, x <= 0}, {-1, x > 0}}], {x, -1, 2}]
22282231 = -1
@@ -2244,15 +2247,18 @@ class Piecewise(SympyFunction):
22442247
22452248 def apply (self , items , evaluation ):
22462249 "%(name)s[items__]"
2247- result = self .to_sympy (Expression ("Piecewise" , * items .get_sequence ()))
2250+ result = self .to_sympy (Expression ("Piecewise" , * items .get_sequence ()),
2251+ evaluation = evaluation
2252+ )
22482253 if result is None :
22492254 return
22502255 if not isinstance (result , sympy .Piecewise ):
2251- return from_sympy (result )
2256+ result = from_sympy (result )
2257+ return result
22522258
22532259 def to_sympy (self , expr , ** kwargs ):
22542260 leaves = expr .leaves
2255-
2261+ evaluation = kwargs . get ( "evaluation" , None )
22562262 if len (leaves ) not in (1 , 2 ):
22572263 return
22582264
@@ -2263,6 +2269,8 @@ def to_sympy(self, expr, **kwargs):
22632269 if len (case .leaves ) != 2 :
22642270 return
22652271 then , cond = case .leaves
2272+ if evaluation :
2273+ cond = evaluate_predicate (cond , evaluation )
22662274
22672275 sympy_cond = None
22682276 if isinstance (cond , Symbol ):
@@ -2320,11 +2328,11 @@ def apply(self, expr, evaluation):
23202328
23212329class Assumptions (Predefined ):
23222330 """
2323- <dl>
2324- <dt>'$Assumptions'
2325- <dd>is the default setting for the Assumptions option used in such
2326- functions as Simplify, Refine, and Integrate.
2327- </dl>
2331+ <dl>
2332+ <dt>'$Assumptions'
2333+ <dd>is the default setting for the Assumptions option used in such
2334+ functions as Simplify, Refine, and Integrate.
2335+ </dl>
23282336 """
23292337
23302338 name = "$Assumptions"
@@ -2338,84 +2346,113 @@ class Assuming(Builtin):
23382346 """
23392347 <dl>
23402348 <dt>'Assuming[$cond$, $expr$]'
2341- <dd>Evaluates $expr$ assuming the conditions $cond$
2349+ <dd>Evaluates $expr$ assuming the conditions $cond$.
23422350 </dl>
23432351 >> $Assumptions = { x > 0 }
23442352 = {x > 0}
2345- >> Assuming[y>0, $Assumptions]
2346- = {x > 0, y > 0}
2353+ >> Assuming[y>0, ConditionalExpression[y x^2, y>0]//Simplify]
2354+ = x ^ 2 y
2355+ >> Assuming[Not[y>0], ConditionalExpression[y x^2, y>0]//Simplify]
2356+ = Undefined
2357+ >> ConditionalExpression[y x ^ 2, y > 0]//Simplify
2358+ = ConditionalExpression[x ^ 2 y, y > 0]
23472359 """
23482360
23492361 attributes = ("HoldRest" ,)
23502362
2351- def apply_assuming (self , cond , expr , evaluation ):
2352- "Assuming[cond_ , expr_]"
2353- cond = cond .evaluate (evaluation )
2354- if cond .is_true ():
2363+ def apply_assuming (self , assumptions , expr , evaluation ):
2364+ "Assuming[assumptions_ , expr_]"
2365+ assumptions = assumptions .evaluate (evaluation )
2366+ if assumptions .is_true ():
23552367 cond = []
2356- elif cond .is_symbol () or not cond .has_form ("List" , None ):
2357- cond = [cond ]
2368+ elif assumptions .is_symbol () or not assumptions .has_form ("List" , None ):
2369+ cond = [assumptions ]
23582370 else :
2359- cond = cond .leaves
2360- assumptions = evaluation .definitions .get_definition (
2361- "System`$Assumptions" , only_if_exists = True
2371+ cond = assumptions ._leaves
2372+ cond = tuple (cond ) + get_assumptions_list (evaluation )
2373+ list_cond = Expression ("List" , * cond )
2374+ # TODO: reduce the list of predicates
2375+ return dynamic_scoping (
2376+ lambda ev : expr .evaluate (ev ), {"System`$Assumptions" : list_cond }, evaluation
23622377 )
23632378
2364- if assumptions :
2365- assumptions = assumptions .ownvalues
2366- if len (assumptions ) > 0 :
2367- assumptions = assumptions [0 ].replace
2368- else :
2369- assumptions = None
2370- if assumptions :
2371- if assumptions .is_symbol () or not assumptions .has_form ("List" , None ):
2372- assumptions = [assumptions ]
2373- else :
2374- assumptions = assumptions .leaves
2375- cond = assumptions + tuple (cond )
2376- Expression (
2377- "Set" , Symbol ("System`$Assumptions" ), Expression ("List" , * cond )
2378- ).evaluate (evaluation )
2379- ret = expr .evaluate (evaluation )
2380- if assumptions :
2381- Expression (
2382- "Set" , Symbol ("System`$Assumptions" ), Expression ("List" , * assumptions )
2383- ).evaluate (evaluation )
2384- else :
2385- Expression (
2386- "Set" , Symbol ("System`$Assumptions" ), Expression ("List" , SymbolTrue )
2387- ).evaluate (evaluation )
2388- return ret
2389-
23902379
23912380class ConditionalExpression (Builtin ):
23922381 """
23932382 <dl>
2394- <dt>'ConditionalExpression[$expr$, $cond$]'
2395- <dd>returns $expr$ if $cond$ evaluates to $True$, $Undefined$ if
2396- $cond$ evaluates to $False$.
2383+ <dt>'ConditionalExpression[$expr$, $cond$]'
2384+ <dd>returns $expr$ if $cond$ evaluates to $True$, $Undefined$ if $cond$ evaluates to $False$.
23972385 </dl>
23982386
2387+ >> ConditionalExpression[x^2, True]
2388+ = x ^ 2
2389+
2390+ >> ConditionalExpression[x^2, False]
2391+ = Undefined
2392+
23992393 >> f = ConditionalExpression[x^2, x>0]
24002394 = ConditionalExpression[x ^ 2, x > 0]
24012395 >> f /. x -> 2
24022396 = 4
24032397 >> f /. x -> -2
24042398 = Undefined
2399+ 'ConditionalExpression' uses assumptions to evaluate the condition:
2400+ >> $Assumptions = x > 0;
2401+ >> ConditionalExpression[x ^ 2, x>0]//Simplify
2402+ = x ^ 2
2403+ >> $Assumptions = True;
2404+ # >> ConditionalExpression[ConditionalExpression[s,x>a], x<b]
2405+ # = ConditionalExpression[s, And[x>a, x<b]]
24052406 """
24062407
2408+ sympy_name = "Piecewise"
2409+
24072410 rules = {
24082411 "ConditionalExpression[expr_, True]" : "expr" ,
24092412 "ConditionalExpression[expr_, False]" : "Undefined" ,
2413+ "ConditionalExpression[ConditionalExpression[expr_, cond1_], cond2_]" : "ConditionalExpression[expr, And@@Flatten[{cond1, cond2}]]" ,
2414+ "ConditionalExpression[expr1_, cond_] + expr2_" : "ConditionalExpression[expr1+expr2, cond]" ,
2415+ "ConditionalExpression[expr1_, cond_] expr2_" : "ConditionalExpression[expr1 expr2, cond]" ,
2416+ "ConditionalExpression[expr1_, cond_]^expr2_" : "ConditionalExpression[expr1^expr2, cond]" ,
2417+ "expr1_ ^ ConditionalExpression[expr2_, cond_]" : "ConditionalExpression[expr1^expr2, cond]" ,
24102418 }
24112419
24122420 def apply_generic (self , expr , cond , evaluation ):
24132421 "ConditionalExpression[expr_, cond_]"
2414- cond = cond .evaluate (evaluation )
2422+ # What we need here is a way to evaluate
2423+ # cond as a predicate, using assumptions.
2424+ # Let's delegate this to the And (and Or) symbols...
2425+ if not cond .is_atom () and cond ._head == SymbolList :
2426+ cond = Expression ("System`And" , * (cond ._leaves ))
2427+ else :
2428+ cond = Expression ("System`And" , cond )
24152429 if cond is None :
24162430 return
24172431 if cond .is_true ():
24182432 return expr
24192433 if cond == SymbolFalse :
24202434 return SymbolUndefined
24212435 return
2436+
2437+ def to_sympy (self , expr , ** kwargs ):
2438+ leaves = expr .leaves
2439+ if len (leaves ) != 2 :
2440+ return
2441+ expr , cond = leaves
2442+
2443+ sympy_cond = None
2444+ if isinstance (cond , Symbol ):
2445+ if cond == SymbolTrue :
2446+ sympy_cond = True
2447+ elif cond == SymbolFalse :
2448+ sympy_cond = False
2449+ if sympy_cond is None :
2450+ sympy_cond = cond .to_sympy (** kwargs )
2451+ if not (sympy_cond .is_Relational or sympy_cond .is_Boolean ):
2452+ return
2453+
2454+ sympy_cases = (
2455+ (expr .to_sympy (** kwargs ), sympy_cond ),
2456+ (sympy .Symbol (sympy_symbol_prefix + "System`Undefined" ), True ),
2457+ )
2458+ return sympy .Piecewise (* sympy_cases )
0 commit comments