Metadata-Version: 2.4
Name: philcalc
Version: 0.2.2
Summary: Minimal symbolic CLI calculator powered by SymPy
License-File: LICENSE
Requires-Python: >=3.12
Requires-Dist: sympy>=1.12
Description-Content-Type: text/markdown

# phil

A minimal command-line calculator for exact arithmetic, symbolic differentiation, integration, algebraic equation solving, and ordinary differential equations.

Powered by [SymPy](https://www.sympy.org/).

## Positioning and Philosophy

- `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.

## 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.

## 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
- Tutorial: [TUTORIAL.md](TUTORIAL.md)

## Local Development Install

From a local clone:

```bash
uv tool install .
```

## 60-Second Start

```bash
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)'
phil
```

Then in REPL, try:

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]))`

## Usage

### One-shot

```bash
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 :linalg
```

### Interactive

```bash
phil
phil> <expression>
```

REPL commands:

- `:h` / `:help` show help
- `?` / `??` / `???` progressive feature discovery (standard help, power-user shortcuts, demos)
- `:examples` show sample expressions
- `:tutorial` / `:tour` show guided first-run tour
- `:ode` show ODE cheat sheet and templates
- `:linalg` / `:la` show linear algebra cheat sheet and templates
- `:next` / `:repeat` / `:done` control interactive tutorial mode
- `:v` / `:version` show current version
- `:update` / `:check` compare current vs latest version and print update command
- `:q` / `:quit` / `:x` exit

The REPL starts with a short hint line and prints targeted `hint:` messages on common errors.
On interactive terminals, REPL startup also prints whether your installed version is up to date.
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`).

### 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

From published package (anywhere):

```bash
uv tool upgrade philcalc
```

From a local clone of this repo:

```bash
uv tool install --force --reinstall --refresh .
```

Quick check in CLI:

```bash
phil :version
phil :update
phil :check
```

In REPL:

- 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.

For release notifications on GitHub, use "Watch" -> "Custom" -> "Releases only" on the repo page.

## Release

Tagged releases are published to PyPI automatically via GitHub Actions trusted publishing.

```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
```

Then verify:

- GitHub Actions run: https://github.com/sacchen/phil/actions
- PyPI release page: https://pypi.org/project/philcalc/

### Long Expressions (easier input)

`phil` now uses relaxed parsing by default:

- `2x` works like `2*x`
- `sinx` works like `sin(x)` (with a `hint:` notice)
- `{}` works like `()`
- `ln(t)` works like `log(t)`

So inputs like these work directly:

```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:

```bash
phil --strict '2*x'
```

## Examples

```bash
$ 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]
```

## 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

| 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)` |
| 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))` |

### Symbols

`x`, `y`, `z`, `t`, `pi`, `e`, `f`

### Functions

`sin`, `cos`, `tan`, `exp`, `log`, `sqrt`, `abs`

### Symbol helpers

- `symbols("A B C")` returns a tuple of symbols.
- `S("A")` is shorthand for `Symbol("A")`.

### Matrix helpers

`Matrix`, `eye`, `zeros`, `ones`, `det`, `inv`, `rank`, `eigvals`, `rref`, `nullspace`, `msolve`, `linsolve`

### Syntax notes

- `^` 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 `--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)
- Undefined symbols raise an error

## Safety limits

- Expressions longer than 2000 chars are rejected.
- Inputs containing blocked tokens like `__`, `;`, or newlines are rejected.

See [DESIGN.md](DESIGN.md) for implementation details.
