From 453e416fd1f21fe13093fab037c87424f29b3205 Mon Sep 17 00:00:00 2001 From: Samuel Chen <119898205+sacchen@users.noreply.github.com> Date: Fri, 10 Apr 2026 23:18:42 -0700 Subject: [PATCH] Fix README accuracy and structure (#22) Accuracy fixes: - Separate always-on normalizations from relaxed-only implicit multiplication ({}->(), ln->log, ODE/Leibniz/LaTeX shorthand apply in all modes; 2x/sinx are relaxed-only) - Fix :tutorial docs: starts interactive tutorial mode, not just shows a tour - Soften WolframAlpha hint wording: suppressed for some local guardrail failures - Fix update-status: describes the two-line case when an update is available Structure: - Merge 60-Second Start and Learn by Doing into a single Quick Start near the top - Remove Inspiration, Release, Safety limits (not user-facing) - Fold WolframAlpha Helper into Output and Interop - Merge Local Development Install into Development - Move Examples above Reference - Inline Roadmap link in Install ROADMAP: add missing solve() ergonomics bullet to v0.3.0 scope Closes #22 Co-Authored-By: Claude Sonnet 4.6 --- README.md | 312 ++++++++++++++++++----------------------------------- ROADMAP.md | 1 + 2 files changed, 107 insertions(+), 206 deletions(-) diff --git a/README.md b/README.md index f0c087a..4151474 100644 --- a/README.md +++ b/README.md @@ -4,71 +4,45 @@ A minimal command-line calculator for exact arithmetic, symbolic differentiation Powered by [SymPy](https://www.sympy.org/). -## Positioning and Philosophy +## Why phil -- `phil` is 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 `phil` makes an assumption, it should make that interpretation visible to the user. +`phil` is designed to be the first-stop calculator for quick terminal math, homework, and symbolic workflows — before reaching for WolframAlpha, a Python REPL, or a graphing calculator. -## Inspiration - -- `phil` was inspired by [chadnauseam.com/coding/random/calculator-app](https://chadnauseam.com/coding/random/calculator-app). -- A core motivating example is exact arithmetic on very large expressions: - - `10^10000 + 1 - 10^10000 = 1` - -## Roadmap - -- See `ROADMAP.md` for planned `v0.3.0` and `v1.0.0` milestones. +It prioritizes exactness, speed, and discoverability. When it rewrites your input, it says so. ## Install Requires [uv](https://docs.astral.sh/uv/). -Install from PyPI (no clone required): - ```bash uv tool install philcalc ``` -Then run: - -```bash -phil -``` - -Project links: - -- PyPI: https://pypi.org/project/philcalc/ -- Source: https://github.com/sacchen/phil +- PyPI: [https://pypi.org/project/philcalc/](https://pypi.org/project/philcalc/) +- Source: [https://github.com/sacchen/phil](https://github.com/sacchen/phil) - Tutorial: [TUTORIAL.md](TUTORIAL.md) +- Roadmap: [ROADMAP.md](ROADMAP.md) -## Local Development Install - -From a local clone: - -```bash -uv tool install . -``` - -## 60-Second Start +## Quick Start ```bash -uv tool install philcalc -phil --help phil '1/3 + 1/6' phil '10^100000 + 1 - 10^100000' +phil 'd(x^3 + 2*x, x)' +phil 'int(sin(x), x)' +phil "ode y' = y, y(0)=1" phil '(1 - 25e^5)e^{-5t} + (25e^5 - 1)t e^{-5t} + t e^{-5t} ln(t)' -phil ``` -Then in REPL, try: +Or open the REPL (`phil`) and try these in order: -1. `d(x^3 + 2*x, x)` -2. `int(sin(x), x)` -3. `solve(x^2 - 4, x)` -4. `msolve(Matrix([[2,1],[1,3]]), Matrix([1,2]))` +1. `1/3 + 1/6` +2. `d(x^3 + 2*x, x)` +3. `int(sin(x), x)` +4. `solve(x^2 - 4, x)` +5. `N(pi, 20)` + +If stuck, run `:examples` or `:h`. ## Usage @@ -85,22 +59,18 @@ phil --latex-inline '' phil --latex-block '' phil --wa '' phil --wa --copy-wa '' -phil --color auto '' -phil --color always '' -phil --color never '' +phil --color always '' # also: auto (default), never 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 :linalg ``` -### Interactive +### Interactive REPL ```bash phil @@ -110,151 +80,105 @@ phil> REPL commands: - `:h` / `:help` show strict command reference -- `?` / `??` / `???` progressive feature discovery (quick start, speed shortcuts, advanced demos) -- `:examples` show runnable high-signal expression patterns -- `:tutorial` / `:t` / `:tour` show guided first-run tour +- `?`, `??`, `???` progressive feature discovery (quick start, speed shortcuts, advanced demos) +- `:examples` show runnable expression patterns +- `:tutorial` / `:t` / `:tour` start interactive tutorial mode - `:ode` show ODE cheat sheet and templates - `:linalg` / `:la` show linear algebra cheat sheet and templates -- `:next` / `:repeat` / `:done` control interactive tutorial mode (`Enter` advances to next step while tutorial is active) +- `:next` / `:repeat` / `:done` control interactive tutorial mode (`Enter` advances while tutorial is active) - `:v` / `:version` show current version - `:update` / `:check` compare current vs latest version and print update command - `:q` / `:quit` / `:x` exit -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]`). +The REPL starts with `phil vX.Y.Z REPL [status] (:h help, :t tutorial)` on interactive terminals. 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: `. -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`). - -### Help - -```bash -phil --help -``` - -### Wolfram helper - -- By default, complex expressions print a WolframAlpha equivalent link. -- Links are printed as full URLs for terminal auto-linking (including iTerm2). -- Use `--wa` to always print the link. -- Use `--copy-wa` to copy the link to your clipboard when shown. -- Full URLs are usually clickable directly in modern terminals. - -### Color diagnostics - -- Use `--color auto|always|never` to control ANSI color on diagnostic lines (`E:` and `hint:`). -- Default is `--color auto` (enabled only on TTY stderr, disabled for pipes/non-interactive output). -- `NO_COLOR` disables auto color. -- `--color always` forces color even when output is not a TTY. - -### Interop Output - -- `--format json` prints a compact JSON object with `input`, `parsed`, and `result`. -- `--format json` keeps diagnostics on `stderr`, so `stdout` remains machine-readable. - -### Clear Input/Output Mode - -- Use `--format pretty` for easier-to-scan rendered output. -- Use `--explain-parse` to print `hint: parsed as: ...` on `stderr` before evaluation. -- Combine with relaxed parsing for shorthand visibility, e.g. `phil --explain-parse 'sinx'`. -- `stdout` stays result-only, so pipes/scripts remain predictable. - -## Updates +Errors are prefixed with `E:` followed by a `hint:` line. +Most evaluation errors also include `hint: try WolframAlpha: ` (suppressed for some local guardrail failures). +Session keeps `ans` (last result) and supports assignment: `A = Matrix([[1,2],[3,4]])`. +Inline CLI options work per-expression: `--latex d(x^2, x)`. +For readable ODE solving, prefer `ode ...` input: `ode y' = y`. + +## Parsing and Input Style + +These normalizations apply in all modes (including `--strict`): + +- `{}` -> `()` +- `ln(t)` -> `log(t)` +- `!` factorial +- `sin^2(x)` accepted +- Leibniz shorthand accepted (`d(sin(x))/dx`, `df(t)/dt`) +- ODE shorthand accepted (`dy/dx = y`, `y' = y`, `y'' + y = 0`, `y'(0)=0`) +- LaTeX-style ODE accepted (`\frac{dy}{dx} = y`, `\frac{d^2y}{dx^2} + y = 0`) +- Common LaTeX wrappers and commands are normalized: `$...$`, `\(...\)`, `\sin`, `\cos`, `\ln`, `\sqrt{...}`, `\frac{a}{b}` -From published package (anywhere): +Relaxed parsing (default) also enables implicit multiplication: -```bash -uv tool upgrade philcalc -``` +- `2x` -> `2*x` +- `sinx` -> `sin(x)` (with a `hint:` notice) -From a local clone of this repo: +Use `--strict` to require explicit multiplication: ```bash -uv tool install --force --reinstall --refresh . +phil --strict '2*x' ``` -Quick check in CLI: - -```bash -phil :version -phil :update -phil :check -``` +Undefined symbols raise errors. +Built-in helper names are reserved for evaluation and cannot be reassigned. +In ODE input, prefer explicit multiplication (`20*y` instead of `20y`) for predictable parsing. -In REPL: +## Exact Arithmetic and Reliability -- Startup (interactive terminals) prints a one-line up-to-date or update-available status. -- `:version` shows your installed version. -- `:update`/`:check` show current version, latest known release, and update command. -- `?`, `??`, `???` progressively reveal shortcuts and capability demos. +`phil` defaults to exact symbolic arithmetic. -For release notifications on GitHub, use "Watch" -> "Custom" -> "Releases only" on the repo page. +Cancellable huge expressions stay fast and exact: -## Release +```text +10^10000000000 + 1 - 10^10000000000 -> 1 +2^(2^20) + 1 - 2^(2^20) -> 1 +``` -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 --body` to print copy/paste-ready GitHub Release text. +Non-cancellable explosive growth fails fast with a recovery hint rather than hanging: -```bash -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.0 +```text +10^10000000000 + 1 +2^(2^(2^20)) +100001! +factorial(10^10) ``` -Then verify: +Ambiguous shorthand is rejected with explicit guidance: -- GitHub Actions run: https://github.com/sacchen/phil/actions -- PyPI release page: https://pypi.org/project/philcalc/ +```text +sin x^2 +``` -### Long Expressions (easier input) +Precedence note: -`phil` now uses relaxed parsing by default: +- `-2^2` -> `-(2^2)` +- Use `(-2)^2` for a negative base squared. -- `2x` works like `2*x` -- `sinx` works like `sin(x)` (with a `hint:` notice) -- `{}` works like `()` -- `ln(t)` works like `log(t)` +## Output and Interop -So inputs like these work directly: +- `--format json` prints a compact JSON object with `input`, `parsed`, and `result`; diagnostics stay on `stderr` +- `--format pretty` improves matrix readability +- `--explain-parse` prints `hint: parsed as: ...` on `stderr` +- `--color auto|always|never` controls ANSI output on diagnostic lines; `NO_COLOR` also respected +- `stdout` stays result-only, so pipes and scripts remain predictable +- Complex expressions print a WolframAlpha equivalent link by default; `--wa` forces it, `--copy-wa` copies it to the clipboard -```bash -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: +## Updates ```bash -phil --strict '2*x' +uv tool upgrade philcalc ``` -### Reliability and Recovery - -`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 -> 1` - - `2^(2^20) + 1 - 2^(2^20) -> 1` -- Non-cancellable growth fails fast with local recovery hints: - - `10^10000000000 + 1` - - `2^(2^(2^20))` - - `100001!` - - `factorial(10^10)` -- Ambiguous high-risk shorthand is rejected with explicit guidance: - - `sin x^2` -> use `sin(x^2)` or `(sin(x))^2` +In REPL: -Precedence note: +- Startup prints a status badge on interactive terminals; when an update is available a second line prints the upgrade command +- `:version` shows your installed version +- `:update` / `:check` show current version, latest known release, and update command -- `-2^2` is interpreted as `-(2^2)`. -- Use `(-2)^2` if you want the negative base squared. +For release notifications on GitHub, use "Watch" -> "Custom" -> "Releases only" on the repo page. ## Examples @@ -290,41 +214,12 @@ $ phil --format pretty 'Matrix([[1,2],[3,4]])' [3 4] ``` -## Test - -```bash -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 -``` - -## GitHub - -- CI: `.github/workflows/ci.yml` runs tests on pushes and PRs. -- License: MIT (`LICENSE`). -- Ignore rules: Python/venv/cache (`.gitignore`). -- Contribution guide: `CONTRIBUTOR.md`. - -## Learn by Doing - -Try this sequence in REPL mode: - -1. `1/3 + 1/6` -2. `d(x^3 + 2*x, x)` -3. `int(sin(x), x)` -4. `solve(x^2 - 4, x)` -5. `N(pi, 20)` - -If you get stuck, run `:examples` or `:h`. - ## Reference -### Operations +### Core operations | Operation | Syntax | -|-----------|--------| +| --- | --- | | Derivative | `d(expr, var)` | | Integral | `int(expr, var)` | | Solve equation | `solve(expr, var)` | @@ -343,13 +238,13 @@ If you get stuck, run `:examples` or `:h`. | Solve linear system (Ax=b) | `msolve(Matrix([[...]]), Matrix([...]))` | | Symbolic linear solve | `linsolve((Eq(...), Eq(...)), (x, y))` | -### Symbols +### Common symbols `x`, `y`, `z`, `t`, `pi`, `e`, `f` ### Functions -`sin`, `cos`, `tan`, `exp`, `log`, `sqrt`, `abs` +`sin`, `cos`, `tan`, `exp`, `log`, `sqrt`, `abs`, `gamma`, `atan2`, `binomial`, `limit`, `series`, `factor`, `expand` ### Exact arithmetic helpers @@ -357,8 +252,8 @@ If you get stuck, run `:examples` or `:h`. ### Symbol helpers -- `symbols("A B C")` returns a tuple of symbols. -- `S("A")` is shorthand for `Symbol("A")`. +- `symbols("A B C")` returns a tuple of symbols +- `S("A")` is shorthand for `Symbol("A")` ### Matrix helpers @@ -367,22 +262,27 @@ If you get stuck, run `:examples` or `:h`. ### Syntax notes - `^` is exponentiation (`x^2`) -- function exponent notation is accepted (`sin^2(x)`, `cos^2(x)`) +- Function exponent notation is accepted (`sin^2(x)`, `cos^2(x)`) - `!` is factorial (`5!`) -- relaxed mode (default) allows implicit multiplication (`2x`); use `--strict` to require `2*x` +- Relaxed mode (default) allows implicit multiplication (`2x`); use `--strict` to require `2*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*y` instead of `20y`) for predictable parsing. -- Common LaTeX wrappers and commands are normalized: `$...$`, `\(...\)`, `\sin`, `\cos`, `\ln`, `\sqrt{...}`, `\frac{a}{b}` -- `name = expr` assigns in REPL session (`ans` is always last result) -- Built-in helper names are reserved for evaluation (for example `sin`, `gamma`, `atan2`, `I`) and cannot be reassigned. +- `name = expr` assigns in the REPL session (`ans` is always the last result) +- Built-in helper names are reserved and cannot be reassigned - Undefined symbols raise an error -## Safety limits +## Development + +From a local clone: -- Expressions longer than 2000 chars are rejected. -- Inputs containing blocked tokens like `__`, `;`, or newlines are rejected. +```bash +uv tool install . # install locally +uv run --group dev pytest # run tests +uv run --group dev pytest -m "not integration" # fast local loop +scripts/checks.sh # full quality gate +``` -See [DESIGN.md](DESIGN.md) for implementation details. +CI runs via GitHub Actions. License is MIT. +See [CONTRIBUTOR.md](CONTRIBUTOR.md) for contribution guide and release process. diff --git a/ROADMAP.md b/ROADMAP.md index 73f1d28..ffab3b0 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -14,6 +14,7 @@ Goal: make day-to-day terminal math workflows materially faster and clearer. - Equation-solving ergonomics: - Add a focused solve alias for equation/system workflows. - Prefer explicit errors and hints over implicit assumptions when unknowns are ambiguous. + - Keep `solve(...)` focused on symbolic solving; if users try matrix-style input like `solve(A=..., B=...)`, steer them to `linalg solve` or `msolve(A, b)` with an explicit recovery hint instead of overloading `solve`. - Parser and diagnostics quality: - Extend shorthand support where safe. - Always show rewrite/normalization hints when interpretation could surprise users.