A minimal command-line calculator for exact arithmetic, symbolic differentiation, integration, algebraic equation solving, and ordinary differential equations.
Powered by SymPy.
philis built to be the first-stop calculator for quick terminal math, homework, and symbolic workflows.- It aims to be the fastest practical choice before opening WolframAlpha, Google, Python REPL, or Calculate84.
- It is not trying to replace Desmos for graphing-first workflows.
- Priorities: speed, correctness, and discoverability.
- Input should be forgiving: when
philmakes an assumption, it should make that interpretation visible to the user.
philwas inspired by chadnauseam.com/coding/random/calculator-app.- A core motivating example is exact arithmetic on very large expressions:
10^10000 + 1 - 10^10000 = 1
- See
ROADMAP.mdfor plannedv0.3.0andv1.0.0milestones.
Requires uv.
Install from PyPI (no clone required):
uv tool install philcalcThen run:
philProject links:
- PyPI: https://pypi.org/project/philcalc/
- Source: https://github.com/sacchen/phil
- Tutorial: TUTORIAL.md
From a local clone:
uv tool install .uv tool install philcalc
phil --help
phil '1/3 + 1/6'
phil '10^100000 + 1 - 10^100000'
phil '(1 - 25e^5)e^{-5t} + (25e^5 - 1)t e^{-5t} + t e^{-5t} ln(t)'
philThen in REPL, try:
d(x^3 + 2*x, x)int(sin(x), x)solve(x^2 - 4, x)msolve(Matrix([[2,1],[1,3]]), Matrix([1,2]))
phil '<expression>'
phil --format pretty '<expression>'
phil --format json '<expression>'
phil --no-simplify '<expression>'
phil --explain-parse '<expression>'
phil --latex '<expression>'
phil --latex-inline '<expression>'
phil --latex-block '<expression>'
phil --wa '<expression>'
phil --wa --copy-wa '<expression>'
phil --color auto '<expression>'
phil --color always '<expression>'
phil --color never '<expression>'
phil "ode y' = y"
phil "ode y' = y, y(0)=1"
phil "linalg solve A=[[2,1],[1,3]] b=[1,2]"
phil "linalg rref A=[[1,2],[2,4]]"
phil --latex 'dy/dx = y'
phil 'dsolve(Eq(d(y(x), x), y(x)), y(x))'
phil :examples
phil :tutorial
phil :ode
phil :linalgphil
phil> <expression>REPL commands:
:h/:helpshow strict command reference?/??/???progressive feature discovery (quick start, speed shortcuts, advanced demos):examplesshow runnable high-signal expression patterns:tutorial/:t/:tourshow guided first-run tour:odeshow ODE cheat sheet and templates:linalg/:lashow linear algebra cheat sheet and templates:next/:repeat/:donecontrol interactive tutorial mode (Enteradvances to next step while tutorial is active):v/:versionshow current version:update/:checkcompare current vs latest version and print update command:q/:quit/:xexit
The REPL starts with phil vX.Y.Z REPL [status] (:h help, :t tutorial) on interactive terminals (for example, [latest] or [vX.Y.Z available]).
When an update is available, startup prints uv tool upgrade philcalc on the next line.
REPL prints targeted hint: messages on common errors.
Unknown : commands return a short correction hint.
Evaluation errors also include: hint: try WolframAlpha: <url>.
Complex expressions also print a WolframAlpha equivalent hint after successful evaluation.
REPL sessions also keep ans (last result) and support assignment such as A = Matrix([[1,2],[3,4]]).
REPL also accepts inline CLI options, e.g. --latex d(x^2, x) or phil --latex "d(x^2, x)".
For readable ODE solving, use ode ... input (example: ode y' = y).
phil --help- By default, complex expressions print a WolframAlpha equivalent link.
- Links are printed as full URLs for terminal auto-linking (including iTerm2).
- Use
--wato always print the link. - Use
--copy-wato copy the link to your clipboard when shown. - Full URLs are usually clickable directly in modern terminals.
- Use
--color auto|always|neverto control ANSI color on diagnostic lines (E:andhint:). - Default is
--color auto(enabled only on TTY stderr, disabled for pipes/non-interactive output). NO_COLORdisables auto color.--color alwaysforces color even when output is not a TTY.
--format jsonprints a compact JSON object withinput,parsed, andresult.--format jsonkeeps diagnostics onstderr, sostdoutremains machine-readable.
- Use
--format prettyfor easier-to-scan rendered output. - Use
--explain-parseto printhint: parsed as: ...onstderrbefore evaluation. - Combine with relaxed parsing for shorthand visibility, e.g.
phil --explain-parse 'sinx'. stdoutstays result-only, so pipes/scripts remain predictable.
From published package (anywhere):
uv tool upgrade philcalcFrom a local clone of this repo:
uv tool install --force --reinstall --refresh .Quick check in CLI:
phil :version
phil :update
phil :checkIn REPL:
- Startup (interactive terminals) prints a one-line up-to-date or update-available status.
:versionshows your installed version.:update/:checkshow current version, latest known release, and update command.?,??,???progressively reveal shortcuts and capability demos.
For release notifications on GitHub, use "Watch" -> "Custom" -> "Releases only" on the repo page.
Tagged releases are published to PyPI automatically via GitHub Actions trusted publishing.
Draft GitHub Release notes live under release-notes/ and should be finalized at tag time.
Use scripts/release_notes.sh <version> --body to print copy/paste-ready GitHub Release text.
git pull
git tag -a v0.2.0 -m "Release v0.2.0"
git push origin v0.2.0
# or
scripts/release.sh 0.2.0Then verify:
- GitHub Actions run: https://github.com/sacchen/phil/actions
- PyPI release page: https://pypi.org/project/philcalc/
phil now uses relaxed parsing by default:
2xworks like2*xsinxworks likesin(x)(with ahint:notice){}works like()ln(t)works likelog(t)
So inputs like these work directly:
phil '(1 - 25e^5)e^{-5t} + (25e^5 - 1)t e^{-5t} + t e^{-5t} ln(t)'
phil '(854/2197)e^{8t}+(1343/2197)e^{-5t}+((9/26)t^2 -(9/169)t)e^{8t}'
phil 'dy/dx = y'Use strict parsing if needed:
phil --strict '2*x'phil is optimized to recover quickly on pathological input while keeping exact math behavior where possible.
- Cancellable huge expressions stay fast and exact:
10^10000000000 + 1 - 10^10000000000 -> 12^(2^20) + 1 - 2^(2^20) -> 1
- Non-cancellable growth fails fast with local recovery hints:
10^10000000000 + 12^(2^(2^20))100001!factorial(10^10)
- Ambiguous high-risk shorthand is rejected with explicit guidance:
sin x^2-> usesin(x^2)or(sin(x))^2
Precedence note:
-2^2is interpreted as-(2^2).- Use
(-2)^2if you want the negative base squared.
$ phil '1/3 + 1/6'
1/2
$ phil 'd(x^3 + 2*x, x)'
3*x**2 + 2
$ phil 'int(sin(x), x)'
-cos(x)
$ phil 'solve(x^2 - 4, x)'
[-2, 2]
$ phil 'N(pi, 30)'
3.14159265358979323846264338328
$ phil --latex 'd(x^2, x)'
2 x
$ phil --latex-inline 'd(x^2, x)'
$2 x$
$ phil --latex-block 'd(x^2, x)'
$$
2 x
$$
$ phil --format pretty 'Matrix([[1,2],[3,4]])'
[1 2]
[3 4]uv run --group dev pytest
# quick local loop (skip process-heavy integration tests)
uv run --group dev pytest -m "not integration"
# full local quality gate
scripts/checks.sh- CI:
.github/workflows/ci.ymlruns tests on pushes and PRs. - License: MIT (
LICENSE). - Ignore rules: Python/venv/cache (
.gitignore). - Contribution guide:
CONTRIBUTOR.md.
Try this sequence in REPL mode:
1/3 + 1/6d(x^3 + 2*x, x)int(sin(x), x)solve(x^2 - 4, x)N(pi, 20)
If you get stuck, run :examples or :h.
| Operation | Syntax |
|---|---|
| Derivative | d(expr, var) |
| Integral | int(expr, var) |
| Solve equation | solve(expr, var) |
| Solve ODE | dsolve(Eq(...), func) |
| Equation | Eq(lhs, rhs) |
| Numeric eval | N(expr, digits) |
| Integer GCD/LCM | gcd(a, b), lcm(a, b) |
| Primality / factorization | isprime(n), factorint(n) |
| Rational parts | num(expr), den(expr) |
| Matrix determinant | det(Matrix([[...]])) |
| Matrix inverse | inv(Matrix([[...]])) |
| Matrix rank | rank(Matrix([[...]])) |
| Matrix eigenvalues | eigvals(Matrix([[...]])) |
| Matrix RREF | rref(Matrix([[...]])) |
| Matrix nullspace | nullspace(Matrix([[...]])) |
| Solve linear system (Ax=b) | msolve(Matrix([[...]]), Matrix([...])) |
| Symbolic linear solve | linsolve((Eq(...), Eq(...)), (x, y)) |
x, y, z, t, pi, e, f
sin, cos, tan, exp, log, sqrt, abs
gcd, lcm, isprime, factorint, num, den
symbols("A B C")returns a tuple of symbols.S("A")is shorthand forSymbol("A").
Matrix, eye, zeros, ones, det, inv, rank, eigvals, rref, nullspace, msolve, linsolve
^is exponentiation (x^2)- function exponent notation is accepted (
sin^2(x),cos^2(x)) !is factorial (5!)- relaxed mode (default) allows implicit multiplication (
2x); use--strictto require2*x d(expr)/int(expr)infer the variable when exactly one symbol is present- Leibniz shorthand is accepted:
d(sin(x))/dx,df(t)/dt - ODE shorthand is accepted:
dy/dx = y,y' = y,y'' + y = 0,y'(0)=0 - LaTeX-style ODE shorthand is accepted:
\frac{dy}{dx} = y,\frac{d^2y}{dx^2} + y = 0 - In ODE input, prefer explicit multiplication (
20*yinstead of20y) for predictable parsing. - Common LaTeX wrappers and commands are normalized:
$...$,\(...\),\sin,\cos,\ln,\sqrt{...},\frac{a}{b} name = exprassigns in REPL session (ansis always last result)- Undefined symbols raise an error
- Expressions longer than 2000 chars are rejected.
- Inputs containing blocked tokens like
__,;, or newlines are rejected.
See DESIGN.md for implementation details.