Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
a297cd0
Support file_name:test_name on CLI
bdlucas1 Jan 2, 2026
f08e0e3
ContourPlot3D
bdlucas1 Jan 2, 2026
53cf528
Contours, Mesh options
bdlucas1 Jan 3, 2026
0d8f64e
Tests
bdlucas1 Jan 3, 2026
3003b16
Formatting
bdlucas1 Jan 3, 2026
71d6e79
Merge branch 'sphericalplot3d' into contourplot3d
bdlucas1 Jan 3, 2026
02e719e
Merge branch 'sphericalplot3d' into contourplot3d
bdlucas1 Jan 3, 2026
c18fc54
Add example and link
bdlucas1 Jan 3, 2026
3d29ba8
Merge branch 'sphericalplot3d' into contourplot3d
bdlucas1 Jan 3, 2026
0dbbdf3
Update mathics/builtin/drawing/plot_plot3d.py
bdlucas1 Jan 3, 2026
51cac24
Fix doc
bdlucas1 Jan 3, 2026
ce35374
Merge branch 'sphericalplot3d' into contourplot3d
bdlucas1 Jan 3, 2026
2d3fc2b
Fix doc
bdlucas1 Jan 3, 2026
1291cf1
Merge branch 'sphericalplot3d' into contourplot3d
bdlucas1 Jan 3, 2026
aeb40c6
Fix typo
bdlucas1 Jan 3, 2026
3d80b8b
Merge branch 'sphericalplot3d' into contourplot3d
mmatera Jan 10, 2026
27e6c40
Merge branch 'sphericalplot3d' into contourplot3d
mmatera Jan 19, 2026
191617b
More tweaks in InputForm (#1634)
mmatera Jan 19, 2026
bfd9708
OutputForm rebase (#1635)
mmatera Jan 20, 2026
c538823
Update the yaml examples of MathML and TeX Form outputs (#1639)
mmatera Jan 20, 2026
3313aaf
Use MathicsScanner tables for render LaTeX (#1644)
mmatera Jan 24, 2026
f4f9857
Format optional (#1649)
mmatera Jan 25, 2026
f11940b
Add FormBox (#1650)
mmatera Jan 25, 2026
6b14674
Go over Optional doc (#1636)
rocky Jan 25, 2026
137be41
Another independent, small part of #1651 (#1652)
mmatera Jan 25, 2026
501b9c6
Makeboxes overhault (#1651)
mmatera Jan 25, 2026
c322d6a
boxed -> boxes (#1656)
mmatera Jan 26, 2026
6539f04
Implement Format MakeBoxes and Format[...]//OutputForm (#1646)
mmatera Jan 26, 2026
3f80707
Typo in documentation (#1621)
mmatera Jan 26, 2026
7824f99
More on escape characters (#1658)
mmatera Jan 26, 2026
882a8f2
Fix error when integrate a non-sympy integrand. (#1662)
mmatera Jan 29, 2026
2b61d48
is_multiline property (#1664)
mmatera Jan 29, 2026
0df365f
Security/sandbox system commands rebased (#1667)
rocky Jan 31, 2026
66315b5
In CI Use newer URL form for pip git (#1669)
rocky Jan 31, 2026
7ed0d87
$BoxForms and ParentForm (#1666)
mmatera Jan 31, 2026
a34ebdf
Improve TeXForm (#1663)
mmatera Feb 3, 2026
23d2d93
Move implementation of MakeBoxes for Graphics and Graphics3d to math…
mmatera Feb 3, 2026
c7c11af
Add tests for BoxExpression (#1672)
mmatera Feb 3, 2026
3a11b75
Add Box type annotations to render routines. (#1674)
rocky Feb 3, 2026
4bcc264
Merge branch 'master' into sphericalplot3d
mmatera Feb 3, 2026
511bf37
Merge branch 'sphericalplot3d' into contourplot3d
mmatera Feb 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/consistency-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
sudo apt update -qq && sudo apt install llvm-dev remake
python -m pip install --upgrade pip
# We can comment out after next Mathics-Scanner release
python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full]
python -m pip install -e "Mathics-Scanner[full] @ git+https://github.com/Mathics3/mathics-scanner"
pip install -e .

- name: Install Mathics with minimum dependencies
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
run: |
# We can comment out after next Mathics-Scanner release
# python -m pip install Mathics-Scanner[full]
python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full]
python -m pip install -e "Mathics-Scanner[full] @ git+https://github.com/Mathics3/mathics-scanner"
pip install -e .
remake -x develop-full
- name: Test Mathics3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
run: |
python -m pip install --upgrade pip
# We can comment out after next Mathics-Scanner release
python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full]
python -m pip install -e "Mathics-Scanner[full] @ git+https://github.com/Mathics3/mathics-scanner"
- name: Run Mathics3 Combinatorica tests
run: |
git submodule init
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/plot-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
run: |
python -m pip install --upgrade pip
# We can comment out after next Mathics-Scanner release
python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full]
python -m pip install -e "Mathics-Scanner[full] @ git+https://github.com/Mathics3/mathics-scanner"
git clone --depth 1 https://github.com/Mathics3/mathics-scanner.git
cd mathics-scanner/
pip install -e .
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pyodide.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,5 @@ jobs:
python -m pip install --no-build-isolation -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner

pip install --no-build-isolation -e .
make mathics/data/op-tables.json mathics/data/operator-tables.json
make mathics/data/character-tables.json mathics/data/operator-tables.json
make -j3 check
2 changes: 1 addition & 1 deletion .github/workflows/ubuntu-bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
python -m pip install --upgrade pip
python -m pip install pytest-benchmark
# We can comment out after next Mathics-Scanner release
python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full]
python -m pip install -e "Mathics-Scanner[full] @ git+https://github.com/Mathics3/mathics-scanner"
# python -m pip install Mathics-Scanner[full]
pip install -e .
remake -x develop
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ubuntu-cython.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
sudo apt-get update -qq && sudo apt-get install -qq liblapack-dev llvm-dev tesseract-ocr
python -m pip install --upgrade pip
# We can comment out after next Mathics-Scanner release
python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full]
python -m pip install -e "Mathics-Scanner[full] @ git+https://github.com/Mathics3/mathics-scanner"
pip install -e .
cd ..

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- name: Install Mathics3 with Python dependencies
run: |
# We can comment out after next Mathics-Scanner release
python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full]
python -m pip install -e "Mathics-Scanner[full] @ git+https://github.com/Mathics3/mathics-scanner"
pip install -e .

# python -m pip install Mathics-Scanner[full]
Expand Down
18 changes: 9 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ MATHICS3_MODULE_OPTION ?= --load-module pymathics.graph,pymathics.natlang
test \
texdoc

SANDBOX ?=
MATHICS3_SANDBOX ?=
ifeq ($(OS),Windows_NT)
SANDBOX = t
MATHICS3_SANDBOX = t
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
SANDBOX = t
MATHICS3_SANDBOX = t
endif
endif

Expand All @@ -69,17 +69,17 @@ build:
# because pip install doesn't handle
# INSTALL_REQUIRES properly
#: Set up to run from the source tree
develop: mathics/data/op-tables.json mathics/data/operator-tables.json
develop: mathics/data/character-tables.json mathics/data/operator-tables.json
$(PIP) install -e .[dev]

# See note above on ./setup.py
#: Set up to run from the source tree with full dependencies
develop-full: mathics/data/op-tables.json mathics/data/operators.json
develop-full: mathics/data/character-tables.json mathics/data/operators.json
$(PIP) install -e .[dev,full]

# See note above on ./setup.py
#: Set up to run from the source tree with full dependencies and Cython
develop-full-cython: mathics/data/op-tables.json mathics/data/operators.json
develop-full-cython: mathics/data/character-tables.json mathics/data/operators.json
$(PIP) install -e .[dev,full,cython]


Expand Down Expand Up @@ -126,7 +126,7 @@ clean: clean-cython clean-cache
($(MAKE) -C "$$dir" clean); \
done; \
rm -f factorials || true; \
rm -f mathics/data/op-tables || true; \
rm -f mathics/data/character-tables.json || true; \
rm -rf build || true

mypy:
Expand Down Expand Up @@ -155,7 +155,7 @@ doctest-data: mathics/builtin/*.py mathics/doc/documentation/*.mdoc mathics/doc/

#: Run tests that appear in docstring in the code. Use environment variable "DOCTEST_OPTIONS" for doctest options
doctest:
MATHICS_CHARACTER_ENCODING="ASCII" SANDBOX=$(SANDBOX) $(PYTHON) mathics/docpipeline.py $(DOCTEST_OPTIONS)
MATHICS_CHARACTER_ENCODING="ASCII" MATHICS3_SANDBOX=$(MATHICS3_SANDBOX) $(PYTHON) mathics/docpipeline.py $(DOCTEST_OPTIONS)

#: Run tests that appear in docstring in the code, stopping on the first error.
doctest-x:
Expand All @@ -166,7 +166,7 @@ latexdoc texdoc doc:
(cd mathics/doc/latex && $(MAKE) doc)

#: Build JSON ASCII to unicode opcode table and operator table
mathics/data/operator-tables.json mathics/data/op-tables.json mathics/data/operators.json:
mathics/data/operator-tables.json mathics/data/character-tables.json mathics/data/operators.json:
$(BASH) ./admin-tools/make-JSON-tables.sh

#: Remove ChangeLog
Expand Down
2 changes: 2 additions & 0 deletions SYMBOLS_MANIFEST.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ ImportExport`RegisterExport
ImportExport`RegisterImport
Internal`RealValuedNumberQ
Internal`RealValuedNumericQ
JSON`Import`JSONImport
System`$Aborted
System`$Assumptions
System`$BaseDirectory
Expand Down Expand Up @@ -486,6 +487,7 @@ System`FoldList
System`FontColor
System`For
System`Format
System`FormatType
System`FormatValues
System`FractionBox
System`FractionalPart
Expand Down
9 changes: 1 addition & 8 deletions admin-tools/make-JSON-tables.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,7 @@ mydir=$(dirname $bs)
PYTHON=${PYTHON:-python}

cd $mydir/../mathics/data
mathics3-generate-json-table \
--field=ascii-operator-to-symbol \
--field=ascii-operator-to-unicode \
--field=ascii-operator-to-wl-unicode \
--field=operator-to-ascii \
--field=operator-to-amslatex \
--field=operator-to-unicode \
-o op-tables.json
mathics3-generate-json-table -o character-tables.json
mathics3-generate-operator-json-table -o operator-tables.json
# tokenizer looks for the table in the default place...
mathics3-generate-operator-json-table
5 changes: 4 additions & 1 deletion mathics/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,10 @@ def interactive_eval_loop(shell, full_form: bool, strict_wl_output: bool):

show_echo(source_code, evaluation)
if len(source_code) and source_code[0] == "!":
subprocess.run(source_code[1:], shell=True)
if not settings.ENABLE_SYSTEM_COMMANDS:
evaluation.message("Run", "dis")
else:
subprocess.run(source_code[1:], shell=True)
shell.definitions.increment_line_no(1)
continue
if query is None:
Expand Down
136 changes: 7 additions & 129 deletions mathics/builtin/arithfns/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,14 @@

"""

from mathics.builtin.arithmetic import create_infix
from mathics.core.atoms import (
Complex,
Integer,
Integer1,
Integer3,
Integer310,
IntegerM1,
Number,
Rational,
RationalOneHalf,
Real,
String,
)
from mathics.core.attributes import (
A_FLAT,
Expand All @@ -37,32 +32,20 @@
PrefixOperator,
SympyFunction,
)
from mathics.core.convert.expression import to_expression
from mathics.core.convert.sympy import from_sympy
from mathics.core.evaluation import Evaluation
from mathics.core.expression import Expression
from mathics.core.list import ListExpression
from mathics.core.symbols import (
Symbol,
SymbolDivide,
SymbolHoldForm,
SymbolNull,
SymbolPower,
SymbolTimes,
)
from mathics.core.symbols import Symbol, SymbolNull, SymbolPower, SymbolTimes
from mathics.core.systemsymbols import (
SymbolBlank,
SymbolComplexInfinity,
SymbolIndeterminate,
SymbolInfix,
SymbolLeft,
SymbolMinus,
SymbolPattern,
SymbolSequence,
)
from mathics.eval.arithfns.basic import eval_Plus, eval_Times
from mathics.eval.nevaluator import eval_N
from mathics.eval.numerify import numerify
from mathics.format.form_rule.arithfns import format_plus, format_times


class CubeRoot(Builtin):
Expand Down Expand Up @@ -303,54 +286,7 @@ def eval(self, elements, evaluation: Evaluation):

def format_plus(self, items, evaluation: Evaluation):
"Plus[items__]"

def negate(item): # -> Expression (see FIXME below)
if item.has_form("Times", 2, None):
if isinstance(item.elements[0], Number):
first, *rest = item.elements
first = -first
if first.sameQ(Integer1):
if len(rest) == 1:
return rest[0]
return Expression(SymbolTimes, *rest)

return Expression(SymbolTimes, first, *rest)
else:
return Expression(SymbolTimes, IntegerM1, *item.elements)
elif isinstance(item, Number):
return from_sympy(-item.to_sympy())
else:
return Expression(SymbolTimes, IntegerM1, item)

def is_negative(value) -> bool:
if isinstance(value, Complex):
real, imag = value.to_sympy().as_real_imag()
if real <= 0 and imag <= 0:
return True
elif isinstance(value, Number) and value.to_sympy() < 0:
return True
return False

elements = items.get_sequence()
values = [to_expression(SymbolHoldForm, element) for element in elements[:1]]
ops = []
for element in elements[1:]:
if (
element.has_form("Times", 1, None) and is_negative(element.elements[0])
) or is_negative(element):
element = negate(element)
op = "-"
else:
op = "+"
values.append(Expression(SymbolHoldForm, element))
ops.append(String(op))
return Expression(
SymbolInfix,
ListExpression(*values),
ListExpression(*ops),
Integer310,
SymbolLeft,
)
return format_plus(items, evaluation)


class Power(InfixOperator, MPMathFunction):
Expand Down Expand Up @@ -645,74 +581,16 @@ def eval(self, elements, evaluation: Evaluation):

def format_times(self, items, evaluation: Evaluation, op="\u2062"):
"Times[items__]"

def inverse(item):
if item.has_form("Power", 2) and isinstance( # noqa
item.elements[1], (Integer, Rational, Real)
):
neg = -item.elements[1]
if neg.sameQ(Integer1):
return item.elements[0]
else:
return Expression(SymbolPower, item.elements[0], neg)
else:
return item

items = items.get_sequence()
if len(items) < 2:
return
positive = []
negative = []
for item in items:
if (
item.has_form("Power", 2)
and isinstance(item.elements[1], (Integer, Rational, Real))
and item.elements[1].to_sympy() < 0
): # nopep8
negative.append(inverse(item))
elif isinstance(item, Rational):
numerator = item.numerator()
if not numerator.sameQ(Integer1):
positive.append(numerator)
negative.append(item.denominator())
else:
positive.append(item)

if positive and hasattr(positive[0], "value") and positive[0].value == -1:
del positive[0]
minus = True
else:
minus = False
positive = [Expression(SymbolHoldForm, item) for item in positive]
negative = [Expression(SymbolHoldForm, item) for item in negative]
if positive:
positive = create_infix(positive, op, 400, "Left")
else:
positive = Integer1
if negative:
negative = create_infix(negative, op, 400, "Left")
result = Expression(
SymbolDivide,
Expression(SymbolHoldForm, positive),
Expression(SymbolHoldForm, negative),
)
else:
result = positive
if minus:
result = Expression(
SymbolMinus, result
) # Expression('PrecedenceForm', result, 481))
result = Expression(SymbolHoldForm, result)
return result
return format_times(items, evaluation, op)

def format_inputform(self, items, evaluation):
"(InputForm,): Times[items__]"
return self.format_times(items, evaluation, op="*")
return format_times(items, evaluation, op="*")

def format_standardform(self, items, evaluation):
"(StandardForm,): Times[items__]"
return self.format_times(items, evaluation, op=" ")
return format_times(items, evaluation, op=" ")

def format_outputform(self, items, evaluation):
"(OutputForm,): Times[items__]"
return self.format_times(items, evaluation, op=" ")
return format_times(items, evaluation, op=" ")
2 changes: 1 addition & 1 deletion mathics/builtin/assignments/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class SubValues(Builtin):
>> SubValues[f]
= {HoldPattern[f[2][x_]] :> x ^ 2, HoldPattern[f[1][x_]] :> x}
>> Definition[f]
= f[2][x_] = x ^ 2
= f[2][x_] = x^2
.
. f[1][x_] = x
"""
Expand Down
2 changes: 1 addition & 1 deletion mathics/builtin/atomic/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -876,7 +876,7 @@ class ToString(Builtin):
>> "U" <> ToString[2]
= U2
>> ToString[Integrate[f[x],x], TeXForm]
= \\int f\\left(x\\right) \\, dx
= \\int f(x) \\, dx

"""

Expand Down
Loading