diff --git a/mathics/builtin/__init__.py b/mathics/builtin/__init__.py
index 155e8ee11d..f57406299e 100755
--- a/mathics/builtin/__init__.py
+++ b/mathics/builtin/__init__.py
@@ -130,7 +130,7 @@ def is_builtin(var):
_builtins = []
builtins_by_module = {}
-for subdir in ("specialfns",):
+for subdir in ("drawing", "numbers", "specialfns",):
import_name = f"{__name__}.{subdir}"
builtin_module = importlib.import_module(import_name)
submodule_names = [
diff --git a/mathics/builtin/assignment.py b/mathics/builtin/assignment.py
index c50be16328..8a0ebda339 100644
--- a/mathics/builtin/assignment.py
+++ b/mathics/builtin/assignment.py
@@ -1922,11 +1922,11 @@ class LoadModule(Builtin):
def apply(self, module, evaluation):
"LoadModule[module_String]"
try:
- module_loaded = evaluation.definitions.load_pymathics_module(module.value)
- except PyMathicsLoadException as e:
+ evaluation.definitions.load_pymathics_module(module.value)
+ except PyMathicsLoadException:
evaluation.message(self.name, "notmathicslib", module)
return SymbolFailed
- except ImportError as e:
+ except ImportError:
evaluation.message(self.get_name(), "notfound", module)
return SymbolFailed
else:
diff --git a/mathics/builtin/comparison.py b/mathics/builtin/comparison.py
index 04a3aa9933..e083bf48fb 100644
--- a/mathics/builtin/comparison.py
+++ b/mathics/builtin/comparison.py
@@ -13,7 +13,7 @@
SympyFunction,
)
-from mathics.builtin.constants import mp_convert_constant
+from mathics.builtin.numbers.constants import mp_convert_constant
from mathics.core.expression import (
COMPARE_PREC,
diff --git a/mathics/builtin/drawing/__init__.py b/mathics/builtin/drawing/__init__.py
new file mode 100644
index 0000000000..bbbc3fd78b
--- /dev/null
+++ b/mathics/builtin/drawing/__init__.py
@@ -0,0 +1,3 @@
+"""
+Graphics, Drawing, and Images
+"""
diff --git a/mathics/builtin/colors.py b/mathics/builtin/drawing/colors.py
similarity index 100%
rename from mathics/builtin/colors.py
rename to mathics/builtin/drawing/colors.py
diff --git a/mathics/builtin/graphics3d.py b/mathics/builtin/drawing/graphics3d.py
similarity index 99%
rename from mathics/builtin/graphics3d.py
rename to mathics/builtin/drawing/graphics3d.py
index 59527a76d8..f7e9df4477 100644
--- a/mathics/builtin/graphics3d.py
+++ b/mathics/builtin/drawing/graphics3d.py
@@ -14,7 +14,7 @@
SymbolList,
)
from mathics.builtin.base import BoxConstructError, Builtin, InstanceableBuiltin
-from .graphics import (
+from mathics.builtin.graphics import (
Graphics,
GraphicsBox,
PolygonBox,
diff --git a/mathics/builtin/image.py b/mathics/builtin/drawing/image.py
similarity index 99%
rename from mathics/builtin/image.py
rename to mathics/builtin/drawing/image.py
index db5f3a3e27..861156c409 100644
--- a/mathics/builtin/image.py
+++ b/mathics/builtin/drawing/image.py
@@ -21,7 +21,7 @@
SymbolRule,
from_python,
)
-from mathics.builtin.colors import (
+from mathics.builtin.drawing.colors import (
convert as convert_color,
colorspaces as known_colorspaces,
)
@@ -1599,7 +1599,7 @@ def apply(self, values, evaluation, options):
):
color_function = String("LakeColors")
- from mathics.builtin.plot import gradient_palette
+ from mathics.builtin.drawing.plot import gradient_palette
cmap = gradient_palette(color_function, n, evaluation)
if not cmap:
diff --git a/mathics/builtin/plot.py b/mathics/builtin/drawing/plot.py
similarity index 99%
rename from mathics/builtin/plot.py
rename to mathics/builtin/drawing/plot.py
index 7167cbdcfe..65be21f606 100644
--- a/mathics/builtin/plot.py
+++ b/mathics/builtin/drawing/plot.py
@@ -24,12 +24,13 @@
SymbolN,
SymbolRule,
)
+
from mathics.builtin.base import Builtin
-from mathics.builtin.scoping import dynamic_scoping
-from mathics.builtin.options import options_to_rules
-from mathics.builtin.numeric import chop
from mathics.builtin.graphics import Graphics
-from mathics.builtin.graphics3d import Graphics3D
+from mathics.builtin.drawing.graphics3d import Graphics3D
+from mathics.builtin.numeric import chop
+from mathics.builtin.options import options_to_rules
+from mathics.builtin.scoping import dynamic_scoping
try:
@@ -39,7 +40,6 @@
except ImportError:
has_compile = False
-
def gradient_palette(color_function, n, evaluation): # always returns RGB values
if isinstance(color_function, String):
color_data = Expression("ColorData", color_function).evaluate(evaluation)
@@ -340,7 +340,6 @@ def get_plot_range(values, all_values, option):
class _Plot(Builtin):
- from .graphics import Graphics
attributes = ("HoldAll",)
@@ -705,8 +704,6 @@ def find_excl(excl):
class _Chart(Builtin):
attributes = ("HoldAll",)
- from .graphics import Graphics
-
options = Graphics.options.copy()
options.update(
{
@@ -1135,8 +1132,6 @@ class Histogram(Builtin):
= -Graphics-
"""
- from .graphics import Graphics
-
attributes = ("HoldAll",)
options = Graphics.options.copy()
@@ -2224,8 +2219,6 @@ class ListPlot(_ListPlot):
= -Graphics-
"""
- from .graphics import Graphics
-
attributes = ("HoldAll",)
options = Graphics.options.copy()
@@ -2264,8 +2257,6 @@ class ListLinePlot(_ListPlot):
= -Graphics-
"""
- from .graphics import Graphics
-
attributes = ("HoldAll",)
options = Graphics.options.copy()
@@ -2344,8 +2335,6 @@ class Plot3D(_Plot3D):
#> Plot3D[x + 2y, {x, -2, 2}, {y, -2, 2}] // TeXForm
"""
- from .graphics import Graphics
-
attributes = ("HoldAll",)
options = Graphics.options.copy()
@@ -2428,8 +2417,6 @@ class DensityPlot(_Plot3D):
= -Graphics-
"""
- from .graphics import Graphics
-
attributes = ("HoldAll",)
options = Graphics.options.copy()
diff --git a/mathics/builtin/rgbcolor.py b/mathics/builtin/drawing/rgbcolor.py
similarity index 100%
rename from mathics/builtin/rgbcolor.py
rename to mathics/builtin/drawing/rgbcolor.py
diff --git a/mathics/builtin/files.py b/mathics/builtin/files.py
index fd873865e6..7f6919e854 100644
--- a/mathics/builtin/files.py
+++ b/mathics/builtin/files.py
@@ -35,7 +35,6 @@
String,
Symbol,
SymbolFailed,
- SymbolFalse,
SymbolNull,
SymbolTrue,
from_mpmath,
@@ -46,10 +45,8 @@
Stream,
path_search,
stream_manager,
- urlsave_tmp,
)
from mathics.builtin.base import Builtin, Predefined, BinaryOperator, PrefixOperator
-from mathics.builtin.numeric import Hash
from mathics.builtin.strings import to_python_encoding
from mathics.builtin.base import MessageException
diff --git a/mathics/builtin/filesystem.py b/mathics/builtin/filesystem.py
index 8a90b95397..b01472e478 100644
--- a/mathics/builtin/filesystem.py
+++ b/mathics/builtin/filesystem.py
@@ -15,7 +15,6 @@
from mathics.version import __version__ # noqa used in loading to check consistency.
from mathics.core.expression import (
- BaseExpression,
Expression,
String,
Symbol,
@@ -38,7 +37,11 @@
)
from mathics.builtin.base import Builtin, Predefined
-from mathics.builtin.files import DIRECTORY_STACK, INITIAL_DIR, mathics_open
+from mathics.builtin.files import (
+ DIRECTORY_STACK,
+ INITIAL_DIR, # noqa is used via global
+ mathics_open
+ )
from mathics.builtin.numeric import Hash
from mathics.builtin.strings import to_regex
from mathics.builtin.base import MessageException
diff --git a/mathics/builtin/graphics.py b/mathics/builtin/graphics.py
index 6f146ad437..6e26b51ee5 100644
--- a/mathics/builtin/graphics.py
+++ b/mathics/builtin/graphics.py
@@ -29,12 +29,11 @@
SymbolList,
SymbolN,
SymbolMakeBoxes,
- strip_context,
system_symbols,
system_symbols_dict,
from_python,
)
-from mathics.builtin.colors import convert as convert_color
+from mathics.builtin.drawing.colors import convert as convert_color
from mathics.core.numbers import machine_epsilon
GRAPHICS_OPTIONS = {
@@ -60,7 +59,7 @@ class ColorError(BoxConstructError):
def get_class(name):
- from mathics.builtin.graphics3d import GLOBALS3D
+ from mathics.builtin.drawing.graphics3d import GLOBALS3D
c = GLOBALS.get(name)
if c is None:
@@ -119,7 +118,9 @@ def cut(value):
return value
-def create_css(edge_color=None, face_color=None, stroke_width=None, font_color=None, opacity=1.0):
+def create_css(
+ edge_color=None, face_color=None, stroke_width=None, font_color=None, opacity=1.0
+):
css = []
if edge_color is not None:
color, stroke_opacity = edge_color.to_css()
@@ -524,7 +525,7 @@ def convert(content):
options[option] = Expression(SymbolN, options[option]).evaluate(
evaluation
)
- from mathics.builtin.graphics3d import Graphics3DBox, Graphics3D
+ from mathics.builtin.drawing.graphics3d import Graphics3DBox, Graphics3D
if type(self) is Graphics:
return GraphicsBox(
@@ -1004,7 +1005,7 @@ def distance(a, b):
else:
return Expression(
"List",
- *[distance(a, b) for a, b in zip(c1.leaves, c2.leaves)]
+ *[distance(a, b) for a, b in zip(c1.leaves, c2.leaves)],
)
else:
return Expression(SymbolList, *[distance(c, c2) for c in c1.leaves])
@@ -1805,7 +1806,7 @@ def parse_component(segments):
k = spline_degree.get_int_value()
elif head == "System`BSplineCurve":
raise NotImplementedError # FIXME convert bspline to bezier here
- parts = segment.leaves
+ # parts = segment.leaves
else:
raise BoxConstructError
@@ -2569,7 +2570,16 @@ def default_arrow(px, py, vx, vy, t1, s):
class InsetBox(_GraphicsElement):
- def init(self, graphics, style, item=None, content=None, pos=None, opos=(0, 0), opacity=1.0):
+ def init(
+ self,
+ graphics,
+ style,
+ item=None,
+ content=None,
+ pos=None,
+ opos=(0, 0),
+ opacity=1.0,
+ ):
super(InsetBox, self).init(graphics, item, style)
self.color = self.style.get_option("System`FontColor")
@@ -2618,15 +2628,16 @@ def to_svg(self, offset=None):
svg = "\n" + content + "\n"
else:
css_style = create_css(
- font_color=self.color, edge_color=self.color, face_color=self.color, opacity=self.opacity
+ font_color=self.color,
+ edge_color=self.color,
+ face_color=self.color,
+ opacity=self.opacity,
)
text_pos_opts = f'x="{x}" y="{y}" ox="{self.opos[0]}" oy="{self.opos[1]}"'
# FIXME: don't hard code text_style_opts, but allow these to be adjustable.
text_style_opts = "text-anchor:middle; dominant-baseline:middle;"
content = self.content.boxes_to_text(evaluation=self.graphics.evaluation)
- svg = (
- f'{content}'
- )
+ svg = f'{content}'
# content = self.content.boxes_to_mathml(evaluation=self.graphics.evaluation)
# style = create_css(font_color=self.color)
diff --git a/mathics/builtin/inference.py b/mathics/builtin/inference.py
index 5dda95db1c..94c296203d 100644
--- a/mathics/builtin/inference.py
+++ b/mathics/builtin/inference.py
@@ -1,7 +1,9 @@
+# -*- coding: utf-8 -*-
+
from mathics.version import __version__ # noqa used in loading to check consistency.
+
from mathics.core.expression import (
Expression,
- Symbol,
SymbolTrue,
SymbolFalse,
)
@@ -14,8 +16,103 @@
# TODO: Extend these rules?
+def debug_logical_expr(pref, expr, evaluation):
+ pass
+ # return
+ # print(pref , expr) #expr.format(evaluation,"OutputForm").boxes_to_text(evaluation=evaluation))
+
+
+logical_algebraic_rules_spec = {
+ # Inequality rules
+ "Unequal[a_, b_]": "Not[Equal[a, b]]",
+ "Greater[a_, b_]": "Less[b, a]",
+ "GreaterEqual[a_, b_]": "Not[Less[a, b]]",
+ "LessEqual[a_, b_]": "Not[Less[b, a]]",
+ "PositiveQ[a_]": "Less[0, a]",
+ "NegativeQ[a_]": "Less[a, 0]",
+ # Logical basic reductions
+ "Or[q_, Not[q_]]": "True",
+ "Or[q_,]": "q",
+ "Or[q_, q_]": "q",
+ "Or[pred1___, q_, pred2___, q_, pred3___]": "Or[pred1, q, pred2, pred3]",
+ # TODO: Logical operations should sort the leaves...
+ "Or[Not[q_], q_]": "True",
+ "Or[pred1___, q_, pred2___, Not[q_], pred3___]": "Or[pred1, pred2, pred3]",
+ "Or[pred1___, Not[q_], pred2___, q_, pred3___]": "Or[pred1, pred2, pred3]",
+ "And[q_,q_]": "q",
+ "And[q_, Not[q_]]": "False",
+ "And[Not[q_],q_]": "False",
+ "And[pred1___, q_, pred2___, Not[q_], pred3___]": "False",
+ "And[pred1___, Not[q_], pred2___, q_, pred3___]": "False",
+ # Logical reductions involving equalities
+ "Or[pred1___, a_==b_, pred2___ , b_==a_, pred3___]": "Or[pred1, a==b, pred2, pred3]",
+ "And[pred1___, a_==b_, pred2___ , b_==a_, pred3___]": "And[pred1, a==b, pred2, pred3]",
+ "Or[pred1___, a_==b_, pred2___ , Not[b_==a_], pred3___]": "Or[pred1, pred2, pred3]",
+ "And[pred1___, a_==b_, pred2___ , Not[b_==a_], pred3___]": "False",
+ "Xor[q_, Not[q_]]": "True",
+ "Xor[a_==b_, Not[b_==a_]]": "True",
+ # Logical reductions involving inequalities
+ "Or[a_b)",
+ "Or[b_==a_, a_b)",
+ "And[a_=b",
+ "Not[a_==b_]": "a!=b",
+}
+
-def get_assumptions_list(evaluation):
+logical_algebraic_rules = None
+remove_not_rules = None
+
+
+def ensure_logical_algebraic_rules():
+ global logical_algebraic_rules
+ global remove_not_rules
+ if logical_algebraic_rules is None:
+ logical_algebraic_rules = []
+ for pattern, replace in logical_algebraic_rules_spec.items():
+ pattern = parse_builtin_rule(pattern, SystemDefinitions())
+ logical_algebraic_rules.append(
+ Rule(pattern, parse_builtin_rule(replace), system=True)
+ )
+ remove_not_rules = []
+ for pattern, replace in remove_not_rules_spec.items():
+ pattern = parse_builtin_rule(pattern, SystemDefinitions())
+ remove_not_rules.append(
+ Rule(pattern, parse_builtin_rule(replace), system=True)
+ )
+ return
+
+
+def remove_nots_when_unnecesary(pred, evaluation):
+ global remove_not_rules
+ cc = True
+ while cc:
+ pred, cc = pred.apply_rules(remove_not_rules, evaluation)
+ debug_logical_expr("-> ", pred, evaluation)
+ if pred.is_true() or pred == SymbolFalse:
+ return pred
+ return pred
+
+
+def get_assumptions_list(evaluation):
assumptions = None
assumptions_def = evaluation.definitions.get_definition(
"System`$Assumptions", only_if_exists=True
@@ -35,23 +132,251 @@ def get_assumptions_list(evaluation):
return assumptions
+def remove_duplicated_assumptions(assumptions_list, evaluation):
+ if len(assumptions_list) == 0:
+ return assumptions_list
+ assumptions_list = sorted(assumptions_list)
+ unique_assumptions = [assumptions_list[0]]
+ for i, assumption in enumerate(assumptions_list):
+ if not (assumption == unique_assumptions[-1]):
+ unique_assumptions.append(assumption)
+ return unique_assumptions
-def evaluate_predicate(pred, evaluation):
- if pred.has_form(("List", "Sequence"), None):
- return Expression(pred._head, *[evaluate_predicate(subp, evaluation) for subp in pred._leaves] )
- assumptions = get_assumptions_list(evaluation)
+def logical_expand_assumptions(assumptions_list, evaluation):
+ new_assumptions_list = []
+ changed = False
+ for assumption in assumptions_list:
+ if assumption.is_symbol():
+ if assumption.is_true():
+ changed = True
+ continue
+ if assumption == SymbolFalse:
+ evaluation.message("Assumption", "faas")
+ changed = True
+ continue
+ if assumption.is_numeric():
+ evaluation.message("Assumption", "baas")
+ changed = True
+ continue
+ new_assumptions_list.append(assumption)
+ continue
+ if assumption.has_form("And", None):
+ changed = True
+ for leaf in assumption.leaves:
+ new_assumptions_list.append(leaf)
+ continue
+ if assumption.has_form("Not", 1):
+ sentence = assumption._leaves[0]
+ if sentence.has_form("Or", None):
+ changed = True
+ for leaf in sentence._leaves:
+ new_assumptions_list.append(Expression("Not", leaf))
+ continue
+ if sentence.has_form("And", None):
+ leaves = (Expression("Not", leaf) for leaf in sentence._leaves)
+ new_assumptions_list.append(Expression("Or", *leaves))
+ continue
+ if sentence.has_form("Implies", 2):
+ changed = True
+ new_assumptions_list.append(sentence._leaves[0])
+ new_assumptions_list.append(Expression("Not", sentence._leaves[1]))
+ if assumption.has_form("Nor", None):
+ changed = True
+ for leaf in assumption.leaves:
+ new_assumptions_list.append(Expression("Not", leaf))
+ continue
+ else:
+ new_assumptions_list.append(assumption)
+
+ if changed:
+ new_assumptions_list = remove_duplicated_assumptions(
+ new_assumptions_list, evaluation
+ )
+
+ return new_assumptions_list, changed
+
+
+def algebraic_expand_assumptions(assumptions_list, evaluation):
+ global logical_algebraic_rules
+ ensure_logical_algebraic_rules()
+ new_assumptions_list = []
+ changed = False
+ # First apply standard rules of reduction.
+ # These rules are generated the first time that are used.
+ for assumption in assumptions_list:
+ assumption, applied = assumption.apply_rules(
+ logical_algebraic_rules, evaluation
+ )
+ changed = changed or applied
+ new_assumptions_list.append(assumption)
+ if changed:
+ return new_assumptions_list, changed
+ # If not changed, let's try with the next set of rules
+ for assumption in assumptions_list:
+ if assumption.has_form("Not", 1):
+ nas, local_change = algebraic_expand_assumptions(
+ [assumption._leaves[0]], evaluation
+ )
+ if local_change:
+ changed = local_change
+ for na in nas:
+ if na.has_form("Not", 1):
+ new_assumptions_list.append(na._leaves[0])
+ else:
+ new_assumptions_list.append(Expression("Not", na))
+ else:
+ new_assumptions_list.append(assumption)
+ elif assumption.has_form(("Equal", "Unequal", "Equivalent"), (3, None)):
+ leaves = assumption.leaves()
+ head = assumption.get_head()
+ changed = True
+ for i in range(len(leaves)):
+ for j in range(i):
+ new_assumptions_list.append(Expression(head, leaves[i], leaves[j]))
+ new_assumptions_list.append(Expression(head, leaves[j], leaves[i]))
+ elif assumption.has_form(
+ ("Less", "Greater", "LessEqual", "GreaterEqual"), (3, None)
+ ):
+ leaves = assumption.leaves()
+ head = assumption.get_head()
+ changed = True
+ for i in range(len(leaves)):
+ for j in range(i):
+ new_assumptions_list.append(Expression(head, leaves[i], leaves[j]))
+ else:
+ new_assumptions_list.append(assumption)
+
+ if changed:
+ assumptions_list = remove_duplicated_assumptions(
+ new_assumptions_list, evaluation
+ )
+ new_assumptions_list = []
+ for assumption in assumptions_list:
+ assumption, applied = assumption.apply_rules(
+ logical_algebraic_rules, evaluation
+ )
+ new_assumptions_list.append(assumption)
+ return new_assumptions_list, changed
+
+
+def get_assumption_rules_dispatch(evaluation):
+ # TODO: cache the generated rules...
+ assumptions_list = get_assumptions_list(evaluation)
+ if assumptions_list is None:
+ return None
+
+ # check for consistency:
+ consistent_assumptions = Expression("And", *assumptions_list)
+ val_consistent_assumptions = consistent_assumptions.evaluate(evaluation)
+ if val_consistent_assumptions == SymbolFalse:
+ evaluation.message("Inconsistent assumptions")
+
+ # Expands Logically
+ assumptions_list, cont = logical_expand_assumptions(assumptions_list, evaluation)
+ while cont:
+ assumptions_list, cont = logical_expand_assumptions(
+ assumptions_list, evaluation
+ )
+
+ # Expands algebraically
+ assumptions_list, cont = algebraic_expand_assumptions(assumptions_list, evaluation)
+ while cont:
+ assumptions_list, cont = algebraic_expand_assumptions(
+ assumptions_list, evaluation
+ )
assumption_rules = []
- for assumption in assumptions:
- true_state = True
- while assumption.has_form("Not",1):
- true_state = False
- assumption = assumption._leaves[0]
- if true_state:
- assumption_rules.append(Rule(assumption, SymbolTrue))
+ for pat in assumptions_list:
+ value = True
+ while pat.has_form("Not", 1):
+ value = not value
+ pat = pat._leaves[0]
+
+ if value:
+ symbol_value = SymbolTrue
+ symbol_negate_value = SymbolFalse
+ else:
+ symbol_value = SymbolFalse
+ symbol_negate_value = SymbolTrue
+
+ if pat.has_form("Equal", 2):
+ if value:
+ lhs, rhs = pat._leaves
+ if lhs.is_numeric():
+ assumption_rules.append(Rule(rhs, lhs))
+ else:
+ assumption_rules.append(Rule(lhs, rhs))
+ else:
+ assumption_rules.append(Rule(pat, SymbolFalse))
+ symm_pat = Expression(pat._head, pat._leaves[1], pat._leaves[0])
+ assumption_rules.append(Rule(symm_pat, SymbolFalse))
+ elif pat.has_form("Equivalent", 2):
+ assumption_rules.append(Rule(pat, symbol_value))
+ symm_pat = Expression(pat._head, pat._leaves[1], pat._leaves[0])
+ assumption_rules.append(Rule(symm_pat, symbol_value))
+ elif pat.has_form("Less", 2):
+ if value:
+ assumption_rules.append(Rule(pat, SymbolTrue))
+ assumption_rules.append(
+ Rule(
+ Expression(pat._head, pat._leaves[1], pat._leaves[0]),
+ SymbolFalse,
+ )
+ )
+ for head in ("Equal", "Equivalent"):
+ assumption_rules.append(
+ Rule(
+ Expression(head, pat._leaves[0], pat._leaves[1]),
+ SymbolFalse,
+ )
+ )
+ assumption_rules.append(
+ Rule(
+ Expression(head, pat._leaves[1], pat._leaves[0]),
+ SymbolFalse,
+ )
+ )
+ else:
+ assumption_rules.append(Rule(pat, SymbolFalse))
else:
- assumption_rules.append(Rule(assumption, SymbolFalse))
-
- pred, changed = pred.apply_rules(assumption_rules, evaluation)
+ assumption_rules.append(Rule(pat, symbol_value))
+ # TODO: expand the pred and assumptions into an standard,
+ # atomized form, and then apply the rules...
+ if len(assumption_rules) == 0:
+ return None
+ return assumption_rules
+
+
+def evaluate_predicate(pred, evaluation):
+ global logical_algebraic_rules
+ global remove_not_rules
+
+ if pred.has_form(("List", "Sequence"), None):
+ return Expression(
+ pred._head, *[evaluate_predicate(subp, evaluation) for subp in pred._leaves]
+ )
+
+ debug_logical_expr("reducing ", pred, evaluation)
+ ensure_logical_algebraic_rules()
pred = pred.evaluate(evaluation)
+ debug_logical_expr("-> ", pred, evaluation)
+ cc = True
+ while cc:
+ pred, cc = pred.apply_rules(logical_algebraic_rules, evaluation)
+ debug_logical_expr("-> ", pred, evaluation)
+ if pred.is_true() or pred == SymbolFalse:
+ return pred
+
+ assumption_rules = get_assumption_rules_dispatch(evaluation)
+ if assumption_rules is None:
+ return remove_nots_when_unnecesary(pred, evaluation).evaluate(evaluation)
+
+ if assumption_rules is not None:
+ debug_logical_expr(" Now, using the assumptions over ", pred, evaluation)
+ changed = True
+ while changed:
+ pred, changed = pred.apply_rules(assumption_rules, evaluation)
+ debug_logical_expr(" -> ", pred, evaluation)
+
+ pred = remove_nots_when_unnecesary(pred, evaluation).evaluate(evaluation)
return pred
diff --git a/mathics/builtin/lists.py b/mathics/builtin/lists.py
index 054dced5a9..dde8f65b9c 100644
--- a/mathics/builtin/lists.py
+++ b/mathics/builtin/lists.py
@@ -52,7 +52,7 @@
from mathics.core.evaluation import BreakInterrupt, ContinueInterrupt, ReturnInterrupt
from mathics.core.rules import Pattern
from mathics.core.convert import from_sympy
-from mathics.builtin.algebra import cancel
+from mathics.builtin.numbers.algebra import cancel
from mathics.algorithm.introselect import introselect
from mathics.algorithm.clusters import (
optimize,
diff --git a/mathics/builtin/numbers/__init__.py b/mathics/builtin/numbers/__init__.py
new file mode 100644
index 0000000000..2555e6b8dd
--- /dev/null
+++ b/mathics/builtin/numbers/__init__.py
@@ -0,0 +1,3 @@
+"""
+Integer and Number-Theoretical Functions
+"""
diff --git a/mathics/builtin/algebra.py b/mathics/builtin/numbers/algebra.py
similarity index 100%
rename from mathics/builtin/algebra.py
rename to mathics/builtin/numbers/algebra.py
diff --git a/mathics/builtin/calculus.py b/mathics/builtin/numbers/calculus.py
similarity index 100%
rename from mathics/builtin/calculus.py
rename to mathics/builtin/numbers/calculus.py
diff --git a/mathics/builtin/constants.py b/mathics/builtin/numbers/constants.py
similarity index 100%
rename from mathics/builtin/constants.py
rename to mathics/builtin/numbers/constants.py
diff --git a/mathics/builtin/diffeqns.py b/mathics/builtin/numbers/diffeqns.py
similarity index 100%
rename from mathics/builtin/diffeqns.py
rename to mathics/builtin/numbers/diffeqns.py
diff --git a/mathics/builtin/exptrig.py b/mathics/builtin/numbers/exptrig.py
similarity index 100%
rename from mathics/builtin/exptrig.py
rename to mathics/builtin/numbers/exptrig.py
diff --git a/mathics/builtin/integer.py b/mathics/builtin/numbers/integer.py
similarity index 100%
rename from mathics/builtin/integer.py
rename to mathics/builtin/numbers/integer.py
diff --git a/mathics/builtin/linalg.py b/mathics/builtin/numbers/linalg.py
similarity index 100%
rename from mathics/builtin/linalg.py
rename to mathics/builtin/numbers/linalg.py
diff --git a/mathics/builtin/numbertheory.py b/mathics/builtin/numbers/numbertheory.py
similarity index 100%
rename from mathics/builtin/numbertheory.py
rename to mathics/builtin/numbers/numbertheory.py
diff --git a/mathics/builtin/randomnumbers.py b/mathics/builtin/numbers/randomnumbers.py
similarity index 100%
rename from mathics/builtin/randomnumbers.py
rename to mathics/builtin/numbers/randomnumbers.py
diff --git a/mathics/builtin/options.py b/mathics/builtin/options.py
index a857db24e3..9cddae70c7 100644
--- a/mathics/builtin/options.py
+++ b/mathics/builtin/options.py
@@ -5,6 +5,7 @@
"""
from mathics.version import __version__ # noqa used in loading to check consistency.
+
from mathics.builtin.base import Builtin, Test, get_option
from mathics.core.expression import (
Symbol,
@@ -14,8 +15,7 @@
ensure_context,
strip_context,
)
-from mathics.builtin.image import Image
-from mathics.core.expression import strip_context
+from mathics.builtin.drawing.image import Image
class Options(Builtin):
diff --git a/mathics/builtin/specialfns/expintegral.py b/mathics/builtin/specialfns/expintegral.py
index 89cc79d076..53401c80a8 100644
--- a/mathics/builtin/specialfns/expintegral.py
+++ b/mathics/builtin/specialfns/expintegral.py
@@ -7,6 +7,7 @@
from mathics.version import __version__ # noqa used in loading to check consistency.
from mathics.builtin.arithmetic import _MPMathFunction
+from mathics.core.expression import from_mpmath
class ExpIntegralE(_MPMathFunction):
"""
diff --git a/setup.py b/setup.py
index da2af5109d..ce1c389de7 100644
--- a/setup.py
+++ b/setup.py
@@ -64,17 +64,27 @@ def read(*rnames):
EXTENSIONS = []
CMDCLASS = {}
else:
- EXTENSIONS = {
- "core": ["expression", "numbers", "rules", "pattern"],
+ EXTENSIONS_DICT = {
+ "core": ("expression", "numbers", "rules", "pattern"),
"builtin": ["arithmetic", "numeric", "patterns", "graphics"],
}
EXTENSIONS = [
Extension(
"mathics.%s.%s" % (parent, module), ["mathics/%s/%s.py" % (parent, module)]
)
- for parent, modules in EXTENSIONS.items()
+ for parent, modules in EXTENSIONS_DICT.items()
for module in modules
]
+ # EXTENSIONS_SUBDIR_DICT = {
+ # "builtin": [("numbers", "arithmetic"), ("numbers", "numeric"), ("drawing", "graphics")],
+ # }
+ # EXTENSIONS.append(
+ # Extension(
+ # "mathics.%s.%s.%s" % (parent, module[0], module[1]), ["mathics/%s/%s/%s.py" % (parent, module[0], module[1])]
+ # )
+ # for parent, modules in EXTENSIONS_SUBDIR_DICT.items()
+ # for module in modules
+ # )
CMDCLASS = {"build_ext": build_ext}
INSTALL_REQUIRES += ["cython>=0.15.1"]
@@ -113,6 +123,8 @@ def subdirs(root, file="*.*", depth=10):
"mathics.core.parser",
"mathics.builtin",
"mathics.builtin.compile",
+ "mathics.builtin.drawing",
+ "mathics.builtin.numbers",
"mathics.builtin.numpy_utils",
"mathics.builtin.pymimesniffer",
"mathics.builtin.pympler",
diff --git a/test/test_assumptions.py b/test/test_assumptions.py
new file mode 100644
index 0000000000..78cb2e20fc
--- /dev/null
+++ b/test/test_assumptions.py
@@ -0,0 +1,58 @@
+# -*- coding: utf-8 -*-
+from .helper import check_evaluation
+import pytest
+
+from mathics_scanner.errors import IncompleteSyntaxError
+
+list_test_assumptions_integrate = [
+ (
+ "Integrate[x^n, {x, 0, 1}]",
+ "Piecewise[{{1 / (1 + n), 1 + Re[n] > 0 && n > -Infinity && n < Infinity && n != -1}}, Infinity]",
+ "This is so complicated due the sympy result is wrong...",
+ ),
+ (
+ "Assuming[0 < n < 1, Integrate[x^n, {x, 0, 1}]]",
+ "Piecewise[{{1 / (1 + n), 1 + Re[n] > 0 && n > -Infinity && n < Infinity && n != -1}}, Infinity]",
+ "",
+ ),
+ (
+ "Assuming[0 < Re[n] + 1, Integrate[x^n, {x, 0, 1}]]",
+ "Piecewise[{{1 / (1 + n), n > -Infinity && n < Infinity && n != -1}}, Infinity]",
+ "",
+ ),
+ ("Assuming[n == 1, Integrate[x^n, {x, 0, 1}]]", "1 / 2", ""),
+ ("Assuming[n == 2, Integrate[x^n, {x, 0, 1}]]", "1 / 3", ""),
+ ("Assuming[n == -1, Integrate[x^n, {x, 0, 1}]]", "Infinity", ""),
+ # ("Assuming[12, n>=3], Integrate[x^n, {x, 0, 1}]]", "x^(n+1)/(n+1)", ""),
+]
+
+list_test_assumptions_simplify = [
+ ("Simplify[a==b || a!=b]", "True", "",),
+ ("Simplify[a==b && a!=b]", "False", "",),
+ ("Simplify[a<=b && a>b]", "False", "",),
+ ("Simplify[a==b, ! a!=b]", "True", "",),
+ ("Simplify[a==b, a!=b]", "False", "",),
+ ("Simplify[a > b, {a==4}]", "b < 4", "",),
+ ("Simplify[And[a>b, bb", "",),
+ ("Simplify[Or[a>b, ab, bb", "",),
+ ("Simplify[a>b, {b<=a}]", "a>b", "",),
+]
+
+
+@pytest.mark.parametrize(
+ ("str_expr", "str_expected", "message"), list_test_assumptions_integrate,
+)
+@pytest.mark.xfail
+def test_assumptions_integrate(str_expr, str_expected, message):
+ check_evaluation(str_expr, str_expected)
+
+
+@pytest.mark.parametrize(
+ ("str_expr", "str_expected", "message"), list_test_assumptions_simplify,
+)
+@pytest.mark.xfail
+def test_assumptions_simplify(str_expr, str_expected, message):
+ check_evaluation(str_expr, str_expected)
diff --git a/test/test_color.py b/test/test_color.py
index 946dff3aec..116f67af5f 100755
--- a/test/test_color.py
+++ b/test/test_color.py
@@ -6,7 +6,7 @@
from random import random
-import mathics.builtin.colors as colors
+import mathics.builtin.drawing.colors as colors
from mathics.builtin.numpy_utils import array, stacked, vectorize
from mathics.core.definitions import Definitions
from mathics.core.evaluation import Evaluation
diff --git a/test/test_files.py b/test/test_files.py
index e51773600a..014a6c2220 100644
--- a/test/test_files.py
+++ b/test/test_files.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
+import sys
from .helper import check_evaluation, evaluate
-
def test_compress():
for text in ("", "abc", " "):
str_expr = f'Uncompress[Compress["{text}"]]'
@@ -19,12 +19,13 @@ def test_unprotected():
check_evaluation(str_expr, str_expected, message)
-def test_get_and_put():
- temp_filename = evaluate('$TemporaryDirectory<>"/testfile"').to_python()
- temp_filename_strip = temp_filename[1:-1]
- check_evaluation(f"40! >> {temp_filename_strip}", "Null")
- check_evaluation(f"<< {temp_filename_strip}", "40!")
- check_evaluation(f"DeleteFile[{temp_filename}]", "Null")
+if sys.platform not in ("win32",):
+ def test_get_and_put():
+ temp_filename = evaluate('$TemporaryDirectory<>"/testfile"').to_python()
+ temp_filename_strip = temp_filename[1:-1]
+ check_evaluation(f"40! >> {temp_filename_strip}", "Null")
+ check_evaluation(f"<< {temp_filename_strip}", "40!")
+ check_evaluation(f"DeleteFile[{temp_filename}]", "Null")
# I do not know what is it supposed to test with this...