levycas 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. levycas-1.0.0/LICENSE.txt +21 -0
  2. levycas-1.0.0/MANIFEST.in +1 -0
  3. levycas-1.0.0/PKG-INFO +230 -0
  4. levycas-1.0.0/README.md +207 -0
  5. levycas-1.0.0/pyproject.toml +54 -0
  6. levycas-1.0.0/setup.cfg +4 -0
  7. levycas-1.0.0/src/levycas/__init__.py +13 -0
  8. levycas-1.0.0/src/levycas/__main__.py +160 -0
  9. levycas-1.0.0/src/levycas/cli/__init__.py +1 -0
  10. levycas-1.0.0/src/levycas/cli/__main__.py +59 -0
  11. levycas-1.0.0/src/levycas/cli/screens/__init__.py +5 -0
  12. levycas-1.0.0/src/levycas/cli/screens/graph.py +418 -0
  13. levycas-1.0.0/src/levycas/cli/screens/script.py +108 -0
  14. levycas-1.0.0/src/levycas/cli/screens/styles/graphing.tcss +118 -0
  15. levycas-1.0.0/src/levycas/cli/screens/styles/scripting.tcss +92 -0
  16. levycas-1.0.0/src/levycas/cli/screens/styles/welcome.tcss +24 -0
  17. levycas-1.0.0/src/levycas/cli/screens/welcome.py +16 -0
  18. levycas-1.0.0/src/levycas/expressions/__init__.py +33 -0
  19. levycas-1.0.0/src/levycas/expressions/exp.py +59 -0
  20. levycas-1.0.0/src/levycas/expressions/expression.py +872 -0
  21. levycas-1.0.0/src/levycas/expressions/trig.py +71 -0
  22. levycas-1.0.0/src/levycas/operations/__init__.py +101 -0
  23. levycas-1.0.0/src/levycas/operations/algebraic_ops.py +287 -0
  24. levycas-1.0.0/src/levycas/operations/calculus_ops.py +583 -0
  25. levycas-1.0.0/src/levycas/operations/equation_ops.py +41 -0
  26. levycas-1.0.0/src/levycas/operations/exponential_ops.py +156 -0
  27. levycas-1.0.0/src/levycas/operations/expression_ops.py +214 -0
  28. levycas-1.0.0/src/levycas/operations/factorization_ops.py +546 -0
  29. levycas-1.0.0/src/levycas/operations/numerical_ops.py +212 -0
  30. levycas-1.0.0/src/levycas/operations/polynomial_ops.py +896 -0
  31. levycas-1.0.0/src/levycas/operations/simplification_ops.py +461 -0
  32. levycas-1.0.0/src/levycas/operations/trig_ops.py +351 -0
  33. levycas-1.0.0/src/levycas/parser/__init__.py +8 -0
  34. levycas-1.0.0/src/levycas/parser/lexer.py +50 -0
  35. levycas-1.0.0/src/levycas/parser/parser.py +245 -0
  36. levycas-1.0.0/src/levycas/scripting/__init__.py +13 -0
  37. levycas-1.0.0/src/levycas/scripting/errors.py +7 -0
  38. levycas-1.0.0/src/levycas/scripting/execution.py +253 -0
  39. levycas-1.0.0/src/levycas/scripting/scripting.py +438 -0
  40. levycas-1.0.0/src/levycas.egg-info/PKG-INFO +230 -0
  41. levycas-1.0.0/src/levycas.egg-info/SOURCES.txt +58 -0
  42. levycas-1.0.0/src/levycas.egg-info/dependency_links.txt +1 -0
  43. levycas-1.0.0/src/levycas.egg-info/entry_points.txt +2 -0
  44. levycas-1.0.0/src/levycas.egg-info/requires.txt +12 -0
  45. levycas-1.0.0/src/levycas.egg-info/top_level.txt +1 -0
  46. levycas-1.0.0/tests/test_algebraic.py +65 -0
  47. levycas-1.0.0/tests/test_calculus.py +444 -0
  48. levycas-1.0.0/tests/test_exp.py +91 -0
  49. levycas-1.0.0/tests/test_expansion.py +76 -0
  50. levycas-1.0.0/tests/test_expression_ops.py +68 -0
  51. levycas-1.0.0/tests/test_factorization.py +122 -0
  52. levycas-1.0.0/tests/test_numerical.py +112 -0
  53. levycas-1.0.0/tests/test_ordering.py +81 -0
  54. levycas-1.0.0/tests/test_parse.py +92 -0
  55. levycas-1.0.0/tests/test_polynomials.py +406 -0
  56. levycas-1.0.0/tests/test_scripting.py +190 -0
  57. levycas-1.0.0/tests/test_simplification.py +167 -0
  58. levycas-1.0.0/tests/test_trig.py +196 -0
  59. levycas-1.0.0/tests/test_tui_graphing.py +28 -0
  60. levycas-1.0.0/tests/test_tui_scripting.py +35 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Alex Levy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ include src/levycas/cli/screens/styles/*
levycas-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,230 @@
1
+ Metadata-Version: 2.4
2
+ Name: levycas
3
+ Version: 1.0.0
4
+ Summary: A computer algebra system written in python, with an interactive text-based user interface complete with a built-in scripting language and graphing directly in the terminal.
5
+ Author-email: Alex Levy <ajlevy246@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: homepage, https://github.com/ajlevy246/LevyCAS
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE.txt
12
+ Provides-Extra: tui
13
+ Requires-Dist: textual; extra == "tui"
14
+ Requires-Dist: textual-plot; extra == "tui"
15
+ Provides-Extra: dev
16
+ Requires-Dist: textual; extra == "dev"
17
+ Requires-Dist: textual-plot; extra == "dev"
18
+ Requires-Dist: textual-dev; extra == "dev"
19
+ Requires-Dist: pytest-textual-snapshot; extra == "dev"
20
+ Requires-Dist: pytest-cov; extra == "dev"
21
+ Requires-Dist: pytest-asyncio; extra == "dev"
22
+ Dynamic: license-file
23
+
24
+ # Welcome to LevyCAS!
25
+
26
+ [![CI](https://github.com/ajlevy246/LevyCAS/actions/workflows/python-package.yml/badge.svg)](https://github.com/ajlevy246/LevyCAS/actions/workflows/python-package.yml)
27
+ [![codecov](https://codecov.io/gh/ajlevy246/LevyCAS/graph/badge.svg?token=MlatPlQxJ6)](https://codecov.io/gh/ajlevy246/LevyCAS)
28
+
29
+ **LevyCAS** is a lightweight symbolic computer algebra system (CAS) written in Python. It focuses on parsing natural mathematical expressions into symbolic objects and performing symbolic manipulation, calculus, simplification, and number-theoretic computations.
30
+
31
+ <img src="https://github.com/ajlevy246/LevyCAS/blob/main/assets/graph.png?raw=true" width=1000 alt="A screenshot of the LevyCAS graphing textual user interface. Expressions are entered on the left hand side, and an interactive graph is plotted on the right.">
32
+
33
+ <br/>
34
+
35
+ LevyCAS remains an educational project, exploring symbolic computation, expression trees, Pratt parsing, grammars, and terminal UIs. It's designed to combine the best of existing computational tools that I regularly use: Desmos, Sympy, and Matlab.
36
+
37
+ ## Features
38
+ - Parse natural mathematical expressions.
39
+ - Write scripts with a custom scripting language.
40
+ - Symbolic integrals & derivatives.
41
+ - Expression simplification & normalization.
42
+ - Integer factorization & number-theoretic operations.
43
+ - Multivariate polynomial operations: factoring, partial fractions, rationalization.
44
+ - Interactive Textual-based graphing & scripting interface.
45
+ - Python library core with no required dependencies.
46
+
47
+ <br/>
48
+
49
+ # Installation & Quick Start:
50
+
51
+ While the base package has no dependencies, it is designed for Python3.10+
52
+
53
+ ## Core package & CLI
54
+ LevyCAS is uploaded as a Python package on the TestPyPi index [here](https://test.pypi.org/project/levycas/). Install with pip:
55
+
56
+ ```bash
57
+ $ python3 -m pip install levycas --index-url https://test.pypi.org/simple/
58
+ ```
59
+
60
+ Then, get started by launching python and running:
61
+ ```python
62
+ from levycas import symbols, parse, derivative, integrate
63
+
64
+ x, y = symbols("x y")
65
+ expr = parse("sin(x)cos(y)")
66
+ print(expr)
67
+
68
+ print(derivative(expr, x))
69
+ print(integrate(expr, x))
70
+ ```
71
+
72
+ Or through the command-line interface:
73
+ ```bash
74
+ $ levycas integrate "xsin(x^2)"
75
+ ```
76
+
77
+ ## Terminal-Based TUI
78
+ To use the textual user interface, install with the `tui` extra. This extra depends on the [`Textual`](https://textual.textualize.io/) library, as well as the `textual-plot` package.
79
+
80
+ ```bash
81
+ $ python3 -m pip install levycas[tui] --extra-index-url https://test.pypi.org/simple/
82
+ ```
83
+
84
+ Launch the TUI directly in your terminal:
85
+
86
+ ```bash
87
+ $ levycas
88
+ ```
89
+
90
+ Or jump straight to the graphing interface:
91
+
92
+ ```bash
93
+ $ levycas graph "sin(x)" "x^2" "lnx" "exp(x)"
94
+ ```
95
+
96
+ <br/>
97
+
98
+ # Textual User Interface
99
+
100
+ By default, installing the `tui` extra adds the `levycas` script to PATH. Launch the powerful interface to write scripts or plot expressions:
101
+
102
+ <img src="https://github.com/ajlevy246/LevyCAS/blob/main/assets/script.png?raw=true" width=1000 alt="A screenshot of the LevyCAS scripting textual user interface. A script is entered on the left hand side, while output is printed on the right.">
103
+
104
+ <br/>
105
+
106
+ # Project Structure
107
+
108
+ The base package consists of a set of core expression objects, along with a set of routines acting on them.
109
+
110
+ In addition, LevyCAS includes a native Pratt parser capable of interpreting natural mathematical syntax such as `sin(x)cosx`, `1/2x`, and `3ln(x^2)` into symbolic expression trees.
111
+
112
+ ### [`src/levycas/`](./src/levycas/__init__.py)
113
+ - [`expressions/`](./src/levycas/expressions/__init__.py): Defines the symbolic expression tree classes used through LevyCAS. These classes make extensive use of Python's operator overloading and inheritance to provide a simple interface.
114
+
115
+ - [`operations/`](./src/levycas/operations/__init__.py): The routines consist of both the fundamental simplification operations (`simplify`, `sym_eval`), as well as useful symbolic computations like `derivative` and `integrate`.
116
+
117
+ - [`parser/`](./src/levycas/parser/__init__.py): All of the Pratt parsing logic is contained here. Lexing converts and input string into tokens, and the parsing logic converts it to native objects.
118
+
119
+ - [`cli/`](./src/levycas/cli/__init__.py): All of the logic for the textual user interface is contained here. This module does not expose any external functions, but the scripts here may be interesting to those building simple Textual apps themselves.
120
+
121
+ - [`scripting/`](./src/levycas/scripting/__init__.py): The custom scripting language logic is written here. See the grammar and examples in [`GRAMMAR.md`](./src/levycas/scripting/GRAMMAR.md). Use the TUI to run scripts or load them from disk.
122
+
123
+ <br/>
124
+
125
+ # Examples:
126
+
127
+ ### Parse
128
+ ```python
129
+ >>> from levycas import parse
130
+
131
+ # implicit multiplication & function args
132
+ >>> parse("1/2sin(x)cosx")
133
+ (1/2)Sin(x)Cos(x)
134
+
135
+ # symbol generation
136
+ >>> parse("ax^2 + bx + c")
137
+ ax² + bx + c
138
+
139
+ # automatic simplification/normalization
140
+ >>> parse("2(x+3) - x - 6y/y")
141
+ x
142
+ ```
143
+
144
+ ### Polynomial Factoring
145
+ ```python
146
+ >>> from levycas import Variable, factor
147
+ >>> x = Variable("x")
148
+
149
+ # repeated irreducible factors
150
+ >>> factor(x**8 + 2*x**6 - 6*x**5 - 12*x**3 + 9*x**2 + 18, x)
151
+ [1, x² + 2, (x³ - 3)^2]
152
+
153
+ # generalized polynomial variables
154
+ >>> factor(4*Ln(x)**2 + 10*Ln(x) + 6, Ln(x))
155
+ [2, Ln(x) + 1, 2Ln(x) + 3]
156
+ ```
157
+
158
+ ### Symbolic Integration
159
+ ```python
160
+ >>> from levycas.expressions import Variable, Sin, Cos, Ln,
161
+ >>> from levycas.operations import integrate, collect_terms
162
+ >>> x = Variable("x")
163
+
164
+ # u-substitution
165
+ >>> integrate(x*Sin(x**2), x)
166
+ -(1/2)(Cos(x)^2)
167
+
168
+ # partial fractions via Hermite reduction
169
+ >>> integrate(1 / ((x**2+1)*(x-2)), x)
170
+ -(1/10)Ln(x² + 1) + (1/5)Ln(x - 2) - (2/5)Arctan(x)
171
+
172
+ # integration by parts
173
+ >>> integrate(x**3 * Exp(x), x)
174
+ >>> collect_terms(_, Exp(x))
175
+ (x³ - 3x² + 6x - 6)Exp(x)
176
+ ```
177
+
178
+ ### Symbolic Derivatives
179
+ ```python
180
+ >>> from levycas.expression import Variable, Cos, Ln
181
+ >>> from levycas.operations import derivative, trig_simplify
182
+ >>> x = Variable('x')
183
+
184
+ >>> derivative(x**4 + x**3 + x**2 + x, x)
185
+ 1 + 2x + 3x² + 4x³
186
+
187
+ >>> derivative((Cos(x)+Sin(x))**2, x)
188
+ >>> trig_simplify(_)
189
+ 2Cos(2x)
190
+
191
+ >>> derivative(x*Ln(x) - x, x)
192
+ Ln(x)
193
+ ```
194
+
195
+ ### Algebraic Operations
196
+ ```python
197
+ >>> from levycas.expressions import Variable
198
+ >>> from levycas.operations import rationalize, partial_fractions as partial
199
+ >>> x = Variable('x')
200
+
201
+ # partial fractions
202
+ >>> partial(8*x+7, [x+2, x-1], x)
203
+ 3/(x+2) + 5/(x-1)
204
+
205
+ # rationalization
206
+ >>> rationalize(3/(x+2) + 5/(x-1))
207
+ (8x+7)/((x+2)*(x-1))
208
+ ```
209
+
210
+ ### Integer Operations
211
+ ```python
212
+ >>> from levycas import is_prime, factor_integer, gcd
213
+
214
+ >>> gcd(2**4 * 3**5 * 5**3, 7**4 * 11**4 * 13**5)
215
+ 1
216
+
217
+ >>> factor_integer(2**4 * 3**5 * 5**3 * 7**9)
218
+ {2: 4, 3: 5, 5: 3, 7: 9}
219
+
220
+ # integer radical
221
+ >>> def rad(n: Integer) -> Integer:
222
+ >>> rad, factors = 1, factor_integer(n).keys()
223
+ >>> for factor in factors:
224
+ >>> rad *= factor
225
+ >>> return rad
226
+
227
+ >>> rad(18)
228
+ 6
229
+ ```
230
+
@@ -0,0 +1,207 @@
1
+ # Welcome to LevyCAS!
2
+
3
+ [![CI](https://github.com/ajlevy246/LevyCAS/actions/workflows/python-package.yml/badge.svg)](https://github.com/ajlevy246/LevyCAS/actions/workflows/python-package.yml)
4
+ [![codecov](https://codecov.io/gh/ajlevy246/LevyCAS/graph/badge.svg?token=MlatPlQxJ6)](https://codecov.io/gh/ajlevy246/LevyCAS)
5
+
6
+ **LevyCAS** is a lightweight symbolic computer algebra system (CAS) written in Python. It focuses on parsing natural mathematical expressions into symbolic objects and performing symbolic manipulation, calculus, simplification, and number-theoretic computations.
7
+
8
+ <img src="https://github.com/ajlevy246/LevyCAS/blob/main/assets/graph.png?raw=true" width=1000 alt="A screenshot of the LevyCAS graphing textual user interface. Expressions are entered on the left hand side, and an interactive graph is plotted on the right.">
9
+
10
+ <br/>
11
+
12
+ LevyCAS remains an educational project, exploring symbolic computation, expression trees, Pratt parsing, grammars, and terminal UIs. It's designed to combine the best of existing computational tools that I regularly use: Desmos, Sympy, and Matlab.
13
+
14
+ ## Features
15
+ - Parse natural mathematical expressions.
16
+ - Write scripts with a custom scripting language.
17
+ - Symbolic integrals & derivatives.
18
+ - Expression simplification & normalization.
19
+ - Integer factorization & number-theoretic operations.
20
+ - Multivariate polynomial operations: factoring, partial fractions, rationalization.
21
+ - Interactive Textual-based graphing & scripting interface.
22
+ - Python library core with no required dependencies.
23
+
24
+ <br/>
25
+
26
+ # Installation & Quick Start:
27
+
28
+ While the base package has no dependencies, it is designed for Python3.10+
29
+
30
+ ## Core package & CLI
31
+ LevyCAS is uploaded as a Python package on the TestPyPi index [here](https://test.pypi.org/project/levycas/). Install with pip:
32
+
33
+ ```bash
34
+ $ python3 -m pip install levycas --index-url https://test.pypi.org/simple/
35
+ ```
36
+
37
+ Then, get started by launching python and running:
38
+ ```python
39
+ from levycas import symbols, parse, derivative, integrate
40
+
41
+ x, y = symbols("x y")
42
+ expr = parse("sin(x)cos(y)")
43
+ print(expr)
44
+
45
+ print(derivative(expr, x))
46
+ print(integrate(expr, x))
47
+ ```
48
+
49
+ Or through the command-line interface:
50
+ ```bash
51
+ $ levycas integrate "xsin(x^2)"
52
+ ```
53
+
54
+ ## Terminal-Based TUI
55
+ To use the textual user interface, install with the `tui` extra. This extra depends on the [`Textual`](https://textual.textualize.io/) library, as well as the `textual-plot` package.
56
+
57
+ ```bash
58
+ $ python3 -m pip install levycas[tui] --extra-index-url https://test.pypi.org/simple/
59
+ ```
60
+
61
+ Launch the TUI directly in your terminal:
62
+
63
+ ```bash
64
+ $ levycas
65
+ ```
66
+
67
+ Or jump straight to the graphing interface:
68
+
69
+ ```bash
70
+ $ levycas graph "sin(x)" "x^2" "lnx" "exp(x)"
71
+ ```
72
+
73
+ <br/>
74
+
75
+ # Textual User Interface
76
+
77
+ By default, installing the `tui` extra adds the `levycas` script to PATH. Launch the powerful interface to write scripts or plot expressions:
78
+
79
+ <img src="https://github.com/ajlevy246/LevyCAS/blob/main/assets/script.png?raw=true" width=1000 alt="A screenshot of the LevyCAS scripting textual user interface. A script is entered on the left hand side, while output is printed on the right.">
80
+
81
+ <br/>
82
+
83
+ # Project Structure
84
+
85
+ The base package consists of a set of core expression objects, along with a set of routines acting on them.
86
+
87
+ In addition, LevyCAS includes a native Pratt parser capable of interpreting natural mathematical syntax such as `sin(x)cosx`, `1/2x`, and `3ln(x^2)` into symbolic expression trees.
88
+
89
+ ### [`src/levycas/`](./src/levycas/__init__.py)
90
+ - [`expressions/`](./src/levycas/expressions/__init__.py): Defines the symbolic expression tree classes used through LevyCAS. These classes make extensive use of Python's operator overloading and inheritance to provide a simple interface.
91
+
92
+ - [`operations/`](./src/levycas/operations/__init__.py): The routines consist of both the fundamental simplification operations (`simplify`, `sym_eval`), as well as useful symbolic computations like `derivative` and `integrate`.
93
+
94
+ - [`parser/`](./src/levycas/parser/__init__.py): All of the Pratt parsing logic is contained here. Lexing converts and input string into tokens, and the parsing logic converts it to native objects.
95
+
96
+ - [`cli/`](./src/levycas/cli/__init__.py): All of the logic for the textual user interface is contained here. This module does not expose any external functions, but the scripts here may be interesting to those building simple Textual apps themselves.
97
+
98
+ - [`scripting/`](./src/levycas/scripting/__init__.py): The custom scripting language logic is written here. See the grammar and examples in [`GRAMMAR.md`](./src/levycas/scripting/GRAMMAR.md). Use the TUI to run scripts or load them from disk.
99
+
100
+ <br/>
101
+
102
+ # Examples:
103
+
104
+ ### Parse
105
+ ```python
106
+ >>> from levycas import parse
107
+
108
+ # implicit multiplication & function args
109
+ >>> parse("1/2sin(x)cosx")
110
+ (1/2)Sin(x)Cos(x)
111
+
112
+ # symbol generation
113
+ >>> parse("ax^2 + bx + c")
114
+ ax² + bx + c
115
+
116
+ # automatic simplification/normalization
117
+ >>> parse("2(x+3) - x - 6y/y")
118
+ x
119
+ ```
120
+
121
+ ### Polynomial Factoring
122
+ ```python
123
+ >>> from levycas import Variable, factor
124
+ >>> x = Variable("x")
125
+
126
+ # repeated irreducible factors
127
+ >>> factor(x**8 + 2*x**6 - 6*x**5 - 12*x**3 + 9*x**2 + 18, x)
128
+ [1, x² + 2, (x³ - 3)^2]
129
+
130
+ # generalized polynomial variables
131
+ >>> factor(4*Ln(x)**2 + 10*Ln(x) + 6, Ln(x))
132
+ [2, Ln(x) + 1, 2Ln(x) + 3]
133
+ ```
134
+
135
+ ### Symbolic Integration
136
+ ```python
137
+ >>> from levycas.expressions import Variable, Sin, Cos, Ln,
138
+ >>> from levycas.operations import integrate, collect_terms
139
+ >>> x = Variable("x")
140
+
141
+ # u-substitution
142
+ >>> integrate(x*Sin(x**2), x)
143
+ -(1/2)(Cos(x)^2)
144
+
145
+ # partial fractions via Hermite reduction
146
+ >>> integrate(1 / ((x**2+1)*(x-2)), x)
147
+ -(1/10)Ln(x² + 1) + (1/5)Ln(x - 2) - (2/5)Arctan(x)
148
+
149
+ # integration by parts
150
+ >>> integrate(x**3 * Exp(x), x)
151
+ >>> collect_terms(_, Exp(x))
152
+ (x³ - 3x² + 6x - 6)Exp(x)
153
+ ```
154
+
155
+ ### Symbolic Derivatives
156
+ ```python
157
+ >>> from levycas.expression import Variable, Cos, Ln
158
+ >>> from levycas.operations import derivative, trig_simplify
159
+ >>> x = Variable('x')
160
+
161
+ >>> derivative(x**4 + x**3 + x**2 + x, x)
162
+ 1 + 2x + 3x² + 4x³
163
+
164
+ >>> derivative((Cos(x)+Sin(x))**2, x)
165
+ >>> trig_simplify(_)
166
+ 2Cos(2x)
167
+
168
+ >>> derivative(x*Ln(x) - x, x)
169
+ Ln(x)
170
+ ```
171
+
172
+ ### Algebraic Operations
173
+ ```python
174
+ >>> from levycas.expressions import Variable
175
+ >>> from levycas.operations import rationalize, partial_fractions as partial
176
+ >>> x = Variable('x')
177
+
178
+ # partial fractions
179
+ >>> partial(8*x+7, [x+2, x-1], x)
180
+ 3/(x+2) + 5/(x-1)
181
+
182
+ # rationalization
183
+ >>> rationalize(3/(x+2) + 5/(x-1))
184
+ (8x+7)/((x+2)*(x-1))
185
+ ```
186
+
187
+ ### Integer Operations
188
+ ```python
189
+ >>> from levycas import is_prime, factor_integer, gcd
190
+
191
+ >>> gcd(2**4 * 3**5 * 5**3, 7**4 * 11**4 * 13**5)
192
+ 1
193
+
194
+ >>> factor_integer(2**4 * 3**5 * 5**3 * 7**9)
195
+ {2: 4, 3: 5, 5: 3, 7: 9}
196
+
197
+ # integer radical
198
+ >>> def rad(n: Integer) -> Integer:
199
+ >>> rad, factors = 1, factor_integer(n).keys()
200
+ >>> for factor in factors:
201
+ >>> rad *= factor
202
+ >>> return rad
203
+
204
+ >>> rad(18)
205
+ 6
206
+ ```
207
+
@@ -0,0 +1,54 @@
1
+ [project]
2
+ name = "levycas"
3
+ version = "1.0.0"
4
+ authors = [
5
+ {name = "Alex Levy", email = "ajlevy246@gmail.com"},
6
+ ]
7
+ description = "A computer algebra system written in python, with an interactive text-based user interface complete with a built-in scripting language and graphing directly in the terminal."
8
+ readme = "README.md"
9
+ classifiers = [
10
+ "Programming Language :: Python :: 3",
11
+ "Operating System :: OS Independent",
12
+ ]
13
+ license = "MIT"
14
+ license-files = ["LICENSE.txt"]
15
+
16
+ [project.optional-dependencies]
17
+ tui = [
18
+ "textual",
19
+ "textual-plot",
20
+ ]
21
+ dev = [
22
+ "textual",
23
+ "textual-plot",
24
+ "textual-dev",
25
+ "pytest-textual-snapshot",
26
+ "pytest-cov",
27
+ "pytest-asyncio",
28
+ ]
29
+
30
+ [project.urls]
31
+ homepage = "https://github.com/ajlevy246/LevyCAS"
32
+
33
+ [project.scripts]
34
+ levycas = "levycas.__main__:main"
35
+
36
+ [build-system]
37
+ requires = ["setuptools"]
38
+ build-backend = "setuptools.build_meta"
39
+
40
+ [tool.setuptools.packages.find]
41
+ where = ["src"]
42
+
43
+ [tool.pytest.ini_options]
44
+ asyncio_mode = "auto"
45
+
46
+ [tool.coverage.run]
47
+ source = ["levycas"]
48
+
49
+ [tool.coverage.report]
50
+ omit = [
51
+ "src/levycas/cli/*",
52
+ ]
53
+ show_missing = true
54
+ skip_covered = true
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,13 @@
1
+ """LevyCAS is an implementation of a Computer Algebra System written
2
+ in pure Python. It requires only the built-in regex (re) and math modules.
3
+
4
+ Install with the `tui` extra and run `levycas` for the interactive Textual user interface.
5
+ Or, check out https://alexlevy.me for an online LevyCAS demo, hosted with Gradio on Huggingface.
6
+
7
+ - Alex Levy (2025)
8
+ """
9
+ from .expressions import *
10
+ from .operations import *
11
+ from .parser import *
12
+ from .scripting import *
13
+ from .cli import *
@@ -0,0 +1,160 @@
1
+ from argparse import ArgumentParser
2
+
3
+ from levycas.parser import parse
4
+ from levycas.operations import derivative, integrate, get_symbols, factor, simplify
5
+ from levycas.expressions import Product
6
+
7
+ def print_version():
8
+ try:
9
+ from importlib.metadata import version
10
+ print(f"LevyCAS: version=={version('levycas')}")
11
+ except ImportError:
12
+ print("importlib not found in standard library... LevyCAS may not support this Python version.")
13
+
14
+ def launch_terminal_session():
15
+ raise NotImplementedError("Terminal session not yet implemented... ")
16
+
17
+ def integrate_action(args) -> None:
18
+ expr, wrt = parse(args.expr), parse(args.wrt)
19
+ print(f"{integrate(expr, wrt)}")
20
+
21
+ def diff_action(args) -> None:
22
+ expr, wrt = parse(args.expr), parse(args.wrt)
23
+ print(f"{derivative(expr, wrt)}")
24
+
25
+ def factor_action(args) -> None:
26
+ poly, var = parse(args.poly), parse(args.var)
27
+ factors = factor(poly, var)
28
+ print(simplify(Product(*factors)))
29
+
30
+ def graph_action(args) -> None:
31
+ try:
32
+ import textual, textual_plot
33
+ except ImportError as e:
34
+ raise ImportError(
35
+ f"The LevyCAS TUI requires the '{e.name}' package. "
36
+ f"Please see installation instructions in the README."
37
+ )
38
+
39
+ assert len(args.exprs) <= 4, f"Support for more than four graphs at once is not yet available."
40
+ from levycas.cli.__main__ import LevyCasApp
41
+ app = LevyCasApp(graphing=True, exprs=args.exprs)
42
+ app.run()
43
+
44
+ def launch_tui_action() -> None:
45
+ try:
46
+ import textual, textual_plot
47
+ except ImportError as e:
48
+ raise ImportError(
49
+ f"The LevyCAS TUI requires the '{e.name}' package. "
50
+ f"Please see installation instructions in the README."
51
+ )
52
+
53
+ from levycas.cli.__main__ import main as launch_tui
54
+ launch_tui()
55
+
56
+ def build_parser() -> ArgumentParser:
57
+ # Help opens with `levycas -h or --help`
58
+ parser = ArgumentParser(
59
+ prog="levycas",
60
+ description=(
61
+ "A set of symbolic computation tools, with a powerful text-based UI built with Textual. "
62
+ "Do calculus, simplification, graphing, scripting, and more. "
63
+ ),
64
+ epilog=(
65
+ "See github.com/ajlevy246/LevyCAS/ for examples and source. "
66
+ "Run with no arguments to launch the TUI."
67
+ )
68
+ )
69
+ parser.add_argument("-v", "--version", help="print the levycas version and exit.", action='store_true')
70
+ parser.add_argument("-i", "--interactive", help="launch an interactive python session with common commands already run.", action='store_true')
71
+
72
+ subparsers = parser.add_subparsers(
73
+ dest="command",
74
+ description="The specific command to run. Run with no command to launch the TUI.")
75
+
76
+ # Differentiate with `levycas diff ...`
77
+ diff_parser = subparsers.add_parser(
78
+ "diff",
79
+ help="compute the derivative of an expression.",
80
+ )
81
+ diff_parser.add_argument(
82
+ "expr", metavar="EXPR",
83
+ help="the expression to compute the derivative of, e.g. 'x^2ln(x)'",
84
+ )
85
+ diff_parser.add_argument(
86
+ "wrt", metavar="VAR",
87
+ nargs="?", default="x",
88
+ help="the variable of differentiation; 'x' by default.",
89
+ )
90
+
91
+ # Integrate with `levycas integrate ...`
92
+ int_parser = subparsers.add_parser(
93
+ "integrate",
94
+ help="compute the integral of an expression.",
95
+ )
96
+ int_parser.add_argument(
97
+ "expr", metavar="EXPR",
98
+ help="the expression to compute the integral of, e.g. 'xsin(x^2)",
99
+ )
100
+ int_parser.add_argument(
101
+ "wrt", metavar="VAR",
102
+ nargs="?", default="x",
103
+ help="the variable of integration; 'x' by default.",
104
+ )
105
+
106
+ # Factor with `levycas factor ...`
107
+ fact_parser = subparsers.add_parser(
108
+ "factor",
109
+ help="factor a univariate polynomial with rational coefficients.",
110
+ )
111
+ fact_parser.add_argument(
112
+ "poly", metavar="POLY",
113
+ help="the polynomial to factor, e.g. 'x^2 + 3x + 2'",
114
+ )
115
+ fact_parser.add_argument(
116
+ "var", metavar="VAR",
117
+ nargs="?", default="x",
118
+ help="the polynomial variable; 'x' by default.",
119
+ )
120
+
121
+ # Graph with `levycas graph ...`
122
+ graph_parser = subparsers.add_parser(
123
+ "graph",
124
+ help="graph up to four expressions.",
125
+ )
126
+ graph_parser.add_argument(
127
+ "exprs", metavar="EXPRS",
128
+ nargs="*",
129
+ help="enter up to four expressions to plot, e.g. 'sin(x)'",
130
+ )
131
+ return parser
132
+
133
+ def main():
134
+ parser = build_parser()
135
+ args = parser.parse_args()
136
+
137
+ # -v or -i launch actions and exit
138
+ if args.version:
139
+ print_version()
140
+ return
141
+
142
+ if args.interactive:
143
+ launch_terminal_session()
144
+ return
145
+
146
+ # otherwise, expect a command + optional arguments
147
+ command = args.command
148
+ if command is None:
149
+ launch_tui_action()
150
+ elif command == "integrate":
151
+ integrate_action(args)
152
+ elif command == "diff":
153
+ diff_action(args)
154
+ elif command == "factor":
155
+ factor_action(args)
156
+ elif command == "graph":
157
+ graph_action(args)
158
+
159
+ if __name__ == "__main__":
160
+ main()