osl-edu-math 0.2.1__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.
- osl_edu_math-0.2.1/LICENSE +28 -0
- osl_edu_math-0.2.1/PKG-INFO +86 -0
- osl_edu_math-0.2.1/README.md +47 -0
- osl_edu_math-0.2.1/pyproject.toml +119 -0
- osl_edu_math-0.2.1/src/edumath/__init__.py +5 -0
- osl_edu_math-0.2.1/src/edumath/algebra/__init__.py +34 -0
- osl_edu_math-0.2.1/src/edumath/algebra/concepts.py +131 -0
- osl_edu_math-0.2.1/src/edumath/algebra/exercises.py +81 -0
- osl_edu_math-0.2.1/src/edumath/algebra/plots.py +76 -0
- osl_edu_math-0.2.1/src/edumath/algebra/quizes.py +430 -0
- osl_edu_math-0.2.1/src/edumath/algebra/quizzes.py +3 -0
- osl_edu_math-0.2.1/src/edumath/algebra/validators.py +25 -0
- osl_edu_math-0.2.1/src/edumath/analysis/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/analysis/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/analysis/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/analysis/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/analysis/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/analysis/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/arithmetic/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/arithmetic/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/arithmetic/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/arithmetic/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/arithmetic/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/arithmetic/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/calculus/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/calculus/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/calculus/derivatives.py +47 -0
- osl_edu_math-0.2.1/src/edumath/calculus/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/calculus/integrals.py +59 -0
- osl_edu_math-0.2.1/src/edumath/calculus/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/calculus/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/calculus/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/combinatorics/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/combinatorics/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/combinatorics/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/combinatorics/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/combinatorics/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/combinatorics/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/complex_analysis/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/complex_analysis/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/complex_analysis/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/complex_analysis/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/complex_analysis/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/complex_analysis/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/core/__init__.py +83 -0
- osl_edu_math-0.2.1/src/edumath/core/answers.py +75 -0
- osl_edu_math-0.2.1/src/edumath/core/exercises.py +66 -0
- osl_edu_math-0.2.1/src/edumath/core/expressions.py +103 -0
- osl_edu_math-0.2.1/src/edumath/core/lessons.py +52 -0
- osl_edu_math-0.2.1/src/edumath/core/plots.py +245 -0
- osl_edu_math-0.2.1/src/edumath/core/quizzes.py +90 -0
- osl_edu_math-0.2.1/src/edumath/core/solutions.py +105 -0
- osl_edu_math-0.2.1/src/edumath/core/widgets.py +22 -0
- osl_edu_math-0.2.1/src/edumath/differential_equations/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/differential_equations/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/differential_equations/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/differential_equations/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/differential_equations/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/differential_equations/solvers.py +34 -0
- osl_edu_math-0.2.1/src/edumath/differential_equations/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/discrete_math/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/discrete_math/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/discrete_math/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/discrete_math/logic.py +31 -0
- osl_edu_math-0.2.1/src/edumath/discrete_math/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/discrete_math/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/discrete_math/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/geometry/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/geometry/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/geometry/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/geometry/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/geometry/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/geometry/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/graph_theory/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/graph_theory/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/graph_theory/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/graph_theory/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/graph_theory/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/graph_theory/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/linear_algebra/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/linear_algebra/concepts.py +48 -0
- osl_edu_math-0.2.1/src/edumath/linear_algebra/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/linear_algebra/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/linear_algebra/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/linear_algebra/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/logic/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/logic/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/logic/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/logic/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/logic/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/logic/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/number_theory/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/number_theory/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/number_theory/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/number_theory/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/number_theory/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/number_theory/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/numerical_methods/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/numerical_methods/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/numerical_methods/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/numerical_methods/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/numerical_methods/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/numerical_methods/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/optimization/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/optimization/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/optimization/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/optimization/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/optimization/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/optimization/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/probability/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/probability/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/probability/distributions.py +47 -0
- osl_edu_math-0.2.1/src/edumath/probability/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/probability/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/probability/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/probability/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/py.typed +0 -0
- osl_edu_math-0.2.1/src/edumath/python_fundamentals/__init__.py +17 -0
- osl_edu_math-0.2.1/src/edumath/python_fundamentals/arrays.py +32 -0
- osl_edu_math-0.2.1/src/edumath/python_fundamentals/basics.py +24 -0
- osl_edu_math-0.2.1/src/edumath/python_fundamentals/control_flow.py +24 -0
- osl_edu_math-0.2.1/src/edumath/python_fundamentals/plots.py +60 -0
- osl_edu_math-0.2.1/src/edumath/set_theory/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/set_theory/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/set_theory/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/set_theory/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/set_theory/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/set_theory/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/statistics/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/statistics/concepts.py +44 -0
- osl_edu_math-0.2.1/src/edumath/statistics/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/statistics/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/statistics/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/statistics/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/topology/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/topology/concepts.py +0 -0
- osl_edu_math-0.2.1/src/edumath/topology/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/topology/plots.py +0 -0
- osl_edu_math-0.2.1/src/edumath/topology/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/topology/validators.py +0 -0
- osl_edu_math-0.2.1/src/edumath/trigonometry/__init__.py +0 -0
- osl_edu_math-0.2.1/src/edumath/trigonometry/concepts.py +26 -0
- osl_edu_math-0.2.1/src/edumath/trigonometry/exercises.py +0 -0
- osl_edu_math-0.2.1/src/edumath/trigonometry/plots.py +185 -0
- osl_edu_math-0.2.1/src/edumath/trigonometry/quizzes.py +0 -0
- osl_edu_math-0.2.1/src/edumath/trigonometry/validators.py +0 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Open Science Labs Incubator
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: osl-edu-math
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Python tools for math education workflows.
|
|
5
|
+
License-Expression: BSD-3-Clause
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: education,math,python,open-science
|
|
8
|
+
Author: Open Science Labs Incubator
|
|
9
|
+
Requires-Python: >=3.10,<4
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Education
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Education
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Provides-Extra: docs
|
|
22
|
+
Requires-Dist: ipython (>=7)
|
|
23
|
+
Requires-Dist: ipywidgets (>=6)
|
|
24
|
+
Requires-Dist: makim (==1.29.0) ; extra == "dev"
|
|
25
|
+
Requires-Dist: matplotlib (>=2)
|
|
26
|
+
Requires-Dist: mypy (>=1.10) ; extra == "dev"
|
|
27
|
+
Requires-Dist: numpy (>=2)
|
|
28
|
+
Requires-Dist: pre-commit (>=3) ; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest (>=8) ; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-cov (>=5) ; extra == "dev"
|
|
31
|
+
Requires-Dist: ruff (>=0.6) ; extra == "dev"
|
|
32
|
+
Requires-Dist: sympy (>=1)
|
|
33
|
+
Project-URL: Documentation, https://osl-incubator.github.io/edu-math/
|
|
34
|
+
Project-URL: Homepage, https://github.com/osl-incubator/edu-math
|
|
35
|
+
Project-URL: Issues, https://github.com/osl-incubator/edu-math/issues
|
|
36
|
+
Project-URL: Repository, https://github.com/osl-incubator/edu-math
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# edu-math
|
|
40
|
+
|
|
41
|
+

|
|
42
|
+
[](https://pypi.org/project/osl-edu-math/)
|
|
43
|
+
[](https://pypi.org/project/osl-edu-math/)
|
|
44
|
+

|
|
45
|
+
|
|
46
|
+
`edu-math` is a Python package for math education workflows.
|
|
47
|
+
|
|
48
|
+
The PyPI distribution is `osl-edu-math`; the import package remains `edumath`.
|
|
49
|
+
|
|
50
|
+
The project is in its initial scaffold stage. The repository includes packaging,
|
|
51
|
+
testing, linting, documentation, release automation, and GitHub workflow
|
|
52
|
+
infrastructure adapted from the Open Science Labs Incubator Python package
|
|
53
|
+
template used by `prisma-flow`.
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install osl-edu-math
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Development
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
conda env create -f conda/dev.yaml
|
|
65
|
+
conda activate edumath
|
|
66
|
+
poetry config virtualenvs.create false
|
|
67
|
+
poetry install --extras "dev"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Run checks through Makim:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
makim tests.linter
|
|
74
|
+
makim tests.unit
|
|
75
|
+
makim package.build
|
|
76
|
+
makim docs.build
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Project layout
|
|
80
|
+
|
|
81
|
+
- `src/edumath/`: Python package source
|
|
82
|
+
- `tests/`: pytest test suite
|
|
83
|
+
- `docs/`: Quarto documentation website
|
|
84
|
+
- `conda/`: development and release environment files
|
|
85
|
+
- `.github/`: issue templates and GitHub Actions workflows
|
|
86
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# edu-math
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
[](https://pypi.org/project/osl-edu-math/)
|
|
5
|
+
[](https://pypi.org/project/osl-edu-math/)
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
`edu-math` is a Python package for math education workflows.
|
|
9
|
+
|
|
10
|
+
The PyPI distribution is `osl-edu-math`; the import package remains `edumath`.
|
|
11
|
+
|
|
12
|
+
The project is in its initial scaffold stage. The repository includes packaging,
|
|
13
|
+
testing, linting, documentation, release automation, and GitHub workflow
|
|
14
|
+
infrastructure adapted from the Open Science Labs Incubator Python package
|
|
15
|
+
template used by `prisma-flow`.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install osl-edu-math
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Development
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
conda env create -f conda/dev.yaml
|
|
27
|
+
conda activate edumath
|
|
28
|
+
poetry config virtualenvs.create false
|
|
29
|
+
poetry install --extras "dev"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Run checks through Makim:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
makim tests.linter
|
|
36
|
+
makim tests.unit
|
|
37
|
+
makim package.build
|
|
38
|
+
makim docs.build
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Project layout
|
|
42
|
+
|
|
43
|
+
- `src/edumath/`: Python package source
|
|
44
|
+
- `tests/`: pytest test suite
|
|
45
|
+
- `docs/`: Quarto documentation website
|
|
46
|
+
- `conda/`: development and release environment files
|
|
47
|
+
- `.github/`: issue templates and GitHub Actions workflows
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "osl-edu-math"
|
|
3
|
+
version = "0.2.1" # semantic-release
|
|
4
|
+
description = "Python tools for math education workflows."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10,<4"
|
|
7
|
+
license = "BSD-3-Clause"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Open Science Labs Incubator" }
|
|
10
|
+
]
|
|
11
|
+
keywords = [
|
|
12
|
+
"education",
|
|
13
|
+
"math",
|
|
14
|
+
"python",
|
|
15
|
+
"open-science",
|
|
16
|
+
]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 3 - Alpha",
|
|
19
|
+
"Intended Audience :: Education",
|
|
20
|
+
"Intended Audience :: Science/Research",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
"Topic :: Education",
|
|
27
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
28
|
+
]
|
|
29
|
+
dependencies = [
|
|
30
|
+
"matplotlib>=2",
|
|
31
|
+
"numpy>=2",
|
|
32
|
+
"ipywidgets>=6",
|
|
33
|
+
"ipython>=7",
|
|
34
|
+
"sympy>=1"
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.urls]
|
|
38
|
+
Homepage = "https://github.com/osl-incubator/edu-math"
|
|
39
|
+
Repository = "https://github.com/osl-incubator/edu-math"
|
|
40
|
+
Issues = "https://github.com/osl-incubator/edu-math/issues"
|
|
41
|
+
Documentation = "https://osl-incubator.github.io/edu-math/"
|
|
42
|
+
|
|
43
|
+
[project.optional-dependencies]
|
|
44
|
+
dev = [
|
|
45
|
+
"pytest>=8",
|
|
46
|
+
"pytest-cov>=5",
|
|
47
|
+
"ruff>=0.6",
|
|
48
|
+
"mypy>=1.10",
|
|
49
|
+
"pre-commit>=3",
|
|
50
|
+
"makim==1.29.0",
|
|
51
|
+
]
|
|
52
|
+
docs = []
|
|
53
|
+
|
|
54
|
+
[tool.poetry.group.dev.dependencies]
|
|
55
|
+
quarto-cli = ">=1.9.0"
|
|
56
|
+
pytest = ">=8"
|
|
57
|
+
pytest-cov = ">=5"
|
|
58
|
+
ruff = ">=0.6"
|
|
59
|
+
mypy = ">=1.10"
|
|
60
|
+
pre-commit = ">=3"
|
|
61
|
+
makim = "==1.29.0"
|
|
62
|
+
click = "^8.4.1"
|
|
63
|
+
|
|
64
|
+
[build-system]
|
|
65
|
+
requires = ["poetry-core>=2"]
|
|
66
|
+
build-backend = "poetry.core.masonry.api"
|
|
67
|
+
|
|
68
|
+
[tool.poetry]
|
|
69
|
+
packages = [
|
|
70
|
+
{ include = "edumath", from = "src" },
|
|
71
|
+
]
|
|
72
|
+
include = [
|
|
73
|
+
"src/edumath/py.typed",
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
[tool.ruff]
|
|
77
|
+
line-length = 88
|
|
78
|
+
target-version = "py310"
|
|
79
|
+
src = ["src", "tests"]
|
|
80
|
+
|
|
81
|
+
[tool.ruff.lint]
|
|
82
|
+
select = [
|
|
83
|
+
"E",
|
|
84
|
+
"F",
|
|
85
|
+
"I",
|
|
86
|
+
"UP",
|
|
87
|
+
"B",
|
|
88
|
+
"RUF",
|
|
89
|
+
]
|
|
90
|
+
ignore = [
|
|
91
|
+
"D203",
|
|
92
|
+
"D213",
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
[tool.ruff.lint.per-file-ignores]
|
|
96
|
+
"tests/**" = ["D"]
|
|
97
|
+
|
|
98
|
+
[tool.ruff.format]
|
|
99
|
+
quote-style = "double"
|
|
100
|
+
|
|
101
|
+
[tool.pytest.ini_options]
|
|
102
|
+
testpaths = ["tests"]
|
|
103
|
+
addopts = "-ra"
|
|
104
|
+
|
|
105
|
+
[tool.mypy]
|
|
106
|
+
python_version = "3.10"
|
|
107
|
+
strict = true
|
|
108
|
+
warn_unused_ignores = true
|
|
109
|
+
warn_redundant_casts = true
|
|
110
|
+
warn_unused_configs = true
|
|
111
|
+
show_error_codes = true
|
|
112
|
+
|
|
113
|
+
[[tool.mypy.overrides]]
|
|
114
|
+
module = [
|
|
115
|
+
"IPython.*",
|
|
116
|
+
"ipywidgets.*",
|
|
117
|
+
"sympy.*",
|
|
118
|
+
]
|
|
119
|
+
ignore_missing_imports = true
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Algebra learning tools."""
|
|
2
|
+
|
|
3
|
+
from edumath.algebra.concepts import COLLEGE_ALGEBRA_PATH
|
|
4
|
+
from edumath.algebra.exercises import (
|
|
5
|
+
expand_expression_exercise,
|
|
6
|
+
linear_equation_exercise,
|
|
7
|
+
)
|
|
8
|
+
from edumath.algebra.plots import compare_functions_scene, function_scene
|
|
9
|
+
from edumath.algebra.quizes import (
|
|
10
|
+
GuessingQuiz,
|
|
11
|
+
GuessingQuizWidget,
|
|
12
|
+
GuessQuestion,
|
|
13
|
+
GuessResult,
|
|
14
|
+
SympyGuessGame,
|
|
15
|
+
)
|
|
16
|
+
from edumath.algebra.validators import (
|
|
17
|
+
validate_expression_equivalence,
|
|
18
|
+
validate_numeric_solution,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"COLLEGE_ALGEBRA_PATH",
|
|
23
|
+
"GuessQuestion",
|
|
24
|
+
"GuessResult",
|
|
25
|
+
"GuessingQuiz",
|
|
26
|
+
"GuessingQuizWidget",
|
|
27
|
+
"SympyGuessGame",
|
|
28
|
+
"compare_functions_scene",
|
|
29
|
+
"expand_expression_exercise",
|
|
30
|
+
"function_scene",
|
|
31
|
+
"linear_equation_exercise",
|
|
32
|
+
"validate_expression_equivalence",
|
|
33
|
+
"validate_numeric_solution",
|
|
34
|
+
]
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""College algebra concept metadata."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from edumath.core import LearningObjective, Lesson, LessonSection, StudyPath
|
|
6
|
+
|
|
7
|
+
EXPRESSIONS_AND_EQUATIONS = Lesson(
|
|
8
|
+
title="Expressions and equations",
|
|
9
|
+
slug="expressions-and-equations",
|
|
10
|
+
objectives=(
|
|
11
|
+
LearningObjective("Distinguish expressions from equations."),
|
|
12
|
+
LearningObjective("Evaluate algebraic expressions by substitution."),
|
|
13
|
+
LearningObjective("Solve one-variable linear equations."),
|
|
14
|
+
),
|
|
15
|
+
sections=(
|
|
16
|
+
LessonSection(
|
|
17
|
+
title="Expressions",
|
|
18
|
+
body=(
|
|
19
|
+
"An expression is a mathematical phrase that can be simplified "
|
|
20
|
+
"or evaluated, such as 3*x + 2."
|
|
21
|
+
),
|
|
22
|
+
),
|
|
23
|
+
LessonSection(
|
|
24
|
+
title="Equations",
|
|
25
|
+
body=(
|
|
26
|
+
"An equation states that two expressions are equal. Solving an "
|
|
27
|
+
"equation means finding values that make the statement true."
|
|
28
|
+
),
|
|
29
|
+
),
|
|
30
|
+
),
|
|
31
|
+
tags=("algebra", "equations"),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
FUNCTIONS_AND_GRAPHS = Lesson(
|
|
35
|
+
title="Functions and graphs",
|
|
36
|
+
slug="functions-and-graphs",
|
|
37
|
+
objectives=(
|
|
38
|
+
LearningObjective("Interpret a function as an input-output rule."),
|
|
39
|
+
LearningObjective("Identify slope, intercepts, domain, and range."),
|
|
40
|
+
LearningObjective("Connect symbolic functions to their graphs."),
|
|
41
|
+
),
|
|
42
|
+
sections=(
|
|
43
|
+
LessonSection(
|
|
44
|
+
title="Functions",
|
|
45
|
+
body="A function assigns each input exactly one output.",
|
|
46
|
+
),
|
|
47
|
+
LessonSection(
|
|
48
|
+
title="Graphs",
|
|
49
|
+
body=("A graph shows the ordered pairs (x, f(x)) produced by a function."),
|
|
50
|
+
),
|
|
51
|
+
),
|
|
52
|
+
tags=("algebra", "functions", "graphs"),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
POLYNOMIALS = Lesson(
|
|
56
|
+
title="Polynomials",
|
|
57
|
+
slug="polynomials",
|
|
58
|
+
objectives=(
|
|
59
|
+
LearningObjective("Recognize polynomial degree and leading coefficient."),
|
|
60
|
+
LearningObjective("Factor common polynomial forms."),
|
|
61
|
+
LearningObjective("Use roots to interpret polynomial graphs."),
|
|
62
|
+
),
|
|
63
|
+
sections=(
|
|
64
|
+
LessonSection(
|
|
65
|
+
title="Polynomial structure",
|
|
66
|
+
body=(
|
|
67
|
+
"A polynomial is a sum of constant multiples of non-negative "
|
|
68
|
+
"integer powers of a variable."
|
|
69
|
+
),
|
|
70
|
+
),
|
|
71
|
+
),
|
|
72
|
+
tags=("algebra", "polynomials"),
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
EXPONENTIALS_AND_LOGARITHMS = Lesson(
|
|
76
|
+
title="Exponentials and logarithms",
|
|
77
|
+
slug="exponentials-and-logarithms",
|
|
78
|
+
objectives=(
|
|
79
|
+
LearningObjective("Recognize exponential growth and decay."),
|
|
80
|
+
LearningObjective("Use logarithms as inverse operations for exponentials."),
|
|
81
|
+
LearningObjective("Solve basic exponential and logarithmic equations."),
|
|
82
|
+
),
|
|
83
|
+
sections=(
|
|
84
|
+
LessonSection(
|
|
85
|
+
title="Inverse relationship",
|
|
86
|
+
body="A logarithm answers the question: what exponent produced this value?",
|
|
87
|
+
),
|
|
88
|
+
),
|
|
89
|
+
tags=("algebra", "exponentials", "logarithms"),
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
SYSTEMS_OF_EQUATIONS = Lesson(
|
|
93
|
+
title="Systems of equations",
|
|
94
|
+
slug="systems-of-equations",
|
|
95
|
+
objectives=(
|
|
96
|
+
LearningObjective("Interpret a solution as a point satisfying all equations."),
|
|
97
|
+
LearningObjective("Solve small linear systems by substitution or elimination."),
|
|
98
|
+
LearningObjective("Connect systems to line intersections."),
|
|
99
|
+
),
|
|
100
|
+
sections=(
|
|
101
|
+
LessonSection(
|
|
102
|
+
title="Shared solutions",
|
|
103
|
+
body=(
|
|
104
|
+
"A system asks for values that make every equation true at the "
|
|
105
|
+
"same time."
|
|
106
|
+
),
|
|
107
|
+
),
|
|
108
|
+
),
|
|
109
|
+
tags=("algebra", "systems"),
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
COLLEGE_ALGEBRA_PATH = StudyPath(
|
|
113
|
+
title="College Algebra",
|
|
114
|
+
lessons=(
|
|
115
|
+
EXPRESSIONS_AND_EQUATIONS,
|
|
116
|
+
FUNCTIONS_AND_GRAPHS,
|
|
117
|
+
POLYNOMIALS,
|
|
118
|
+
EXPONENTIALS_AND_LOGARITHMS,
|
|
119
|
+
SYSTEMS_OF_EQUATIONS,
|
|
120
|
+
),
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
__all__ = [
|
|
125
|
+
"COLLEGE_ALGEBRA_PATH",
|
|
126
|
+
"EXPONENTIALS_AND_LOGARITHMS",
|
|
127
|
+
"EXPRESSIONS_AND_EQUATIONS",
|
|
128
|
+
"FUNCTIONS_AND_GRAPHS",
|
|
129
|
+
"POLYNOMIALS",
|
|
130
|
+
"SYSTEMS_OF_EQUATIONS",
|
|
131
|
+
]
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""College algebra exercise builders."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from random import Random
|
|
6
|
+
from typing import SupportsFloat, cast
|
|
7
|
+
|
|
8
|
+
import sympy as sp
|
|
9
|
+
|
|
10
|
+
from edumath.core import (
|
|
11
|
+
AnswerCheck,
|
|
12
|
+
Exercise,
|
|
13
|
+
check_expression_answer,
|
|
14
|
+
check_numeric_answer,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def linear_equation_exercise(
|
|
19
|
+
*,
|
|
20
|
+
seed: int | None = None,
|
|
21
|
+
) -> Exercise:
|
|
22
|
+
"""Generate a one-variable linear equation exercise."""
|
|
23
|
+
|
|
24
|
+
rng = Random(seed)
|
|
25
|
+
x = sp.Symbol("x")
|
|
26
|
+
solution = rng.randint(-8, 8)
|
|
27
|
+
coefficient = _nonzero_int(rng, -6, 6)
|
|
28
|
+
constant = rng.randint(-10, 10)
|
|
29
|
+
equation = sp.Eq(coefficient * x + constant, coefficient * solution + constant)
|
|
30
|
+
expected = float(solution)
|
|
31
|
+
|
|
32
|
+
def validator(received: object) -> AnswerCheck:
|
|
33
|
+
return check_numeric_answer(float(cast(SupportsFloat, received)), expected)
|
|
34
|
+
|
|
35
|
+
return Exercise(
|
|
36
|
+
prompt=f"Solve for x: {sp.sstr(equation)}",
|
|
37
|
+
expected=expected,
|
|
38
|
+
validator=validator,
|
|
39
|
+
explanation=(
|
|
40
|
+
"Undo the addition/subtraction first, then divide by the coefficient of x."
|
|
41
|
+
),
|
|
42
|
+
tags=("algebra", "linear-equations"),
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def expand_expression_exercise(
|
|
47
|
+
*,
|
|
48
|
+
seed: int | None = None,
|
|
49
|
+
) -> Exercise:
|
|
50
|
+
"""Generate a polynomial expansion exercise."""
|
|
51
|
+
|
|
52
|
+
rng = Random(seed)
|
|
53
|
+
x = sp.Symbol("x")
|
|
54
|
+
a = _nonzero_int(rng, -5, 5)
|
|
55
|
+
b = rng.randint(-6, 6)
|
|
56
|
+
expression = (x + a) * (x + b)
|
|
57
|
+
expected = sp.expand(expression)
|
|
58
|
+
|
|
59
|
+
return Exercise(
|
|
60
|
+
prompt=f"Expand: {sp.sstr(expression)}",
|
|
61
|
+
expected=expected,
|
|
62
|
+
validator=lambda received: check_expression_answer(
|
|
63
|
+
str(received),
|
|
64
|
+
expected,
|
|
65
|
+
),
|
|
66
|
+
explanation=(
|
|
67
|
+
"Use distribution: multiply each term in the first factor by each "
|
|
68
|
+
"term in the second."
|
|
69
|
+
),
|
|
70
|
+
tags=("algebra", "polynomials"),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _nonzero_int(rng: Random, start: int, stop: int) -> int:
|
|
75
|
+
value = 0
|
|
76
|
+
while value == 0:
|
|
77
|
+
value = rng.randint(start, stop)
|
|
78
|
+
return value
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
__all__ = ["expand_expression_exercise", "linear_equation_exercise"]
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""College algebra plotting helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sympy as sp
|
|
6
|
+
|
|
7
|
+
from edumath.core import (
|
|
8
|
+
ExplicitFunction2D,
|
|
9
|
+
PlotRange,
|
|
10
|
+
PlotScene2D,
|
|
11
|
+
PlotStyle,
|
|
12
|
+
Viewport2D,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def function_scene(
|
|
17
|
+
expression: str | sp.Expr,
|
|
18
|
+
*,
|
|
19
|
+
x_min: float = -10,
|
|
20
|
+
x_max: float = 10,
|
|
21
|
+
y_min: float = -10,
|
|
22
|
+
y_max: float = 10,
|
|
23
|
+
title: str | None = None,
|
|
24
|
+
color: str = "#1a73e8",
|
|
25
|
+
) -> PlotScene2D:
|
|
26
|
+
"""Create a reusable scene for a single algebraic function."""
|
|
27
|
+
|
|
28
|
+
return PlotScene2D(
|
|
29
|
+
elements=(
|
|
30
|
+
ExplicitFunction2D(
|
|
31
|
+
expression,
|
|
32
|
+
domain=PlotRange(x_min, x_max),
|
|
33
|
+
style=PlotStyle(color=color, label=f"y = {expression}"),
|
|
34
|
+
),
|
|
35
|
+
),
|
|
36
|
+
viewport=Viewport2D(
|
|
37
|
+
x=PlotRange(x_min, x_max),
|
|
38
|
+
y=PlotRange(y_min, y_max),
|
|
39
|
+
),
|
|
40
|
+
title=title or f"y = {expression}",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def compare_functions_scene(
|
|
45
|
+
expressions: tuple[str | sp.Expr, ...],
|
|
46
|
+
*,
|
|
47
|
+
x_min: float = -10,
|
|
48
|
+
x_max: float = 10,
|
|
49
|
+
y_min: float = -10,
|
|
50
|
+
y_max: float = 10,
|
|
51
|
+
title: str = "Function comparison",
|
|
52
|
+
) -> PlotScene2D:
|
|
53
|
+
"""Create a scene comparing several functions."""
|
|
54
|
+
|
|
55
|
+
colors = ("#1a73e8", "#d93025", "#137333", "#9334e6")
|
|
56
|
+
return PlotScene2D(
|
|
57
|
+
elements=tuple(
|
|
58
|
+
ExplicitFunction2D(
|
|
59
|
+
expression,
|
|
60
|
+
domain=PlotRange(x_min, x_max),
|
|
61
|
+
style=PlotStyle(
|
|
62
|
+
color=colors[index % len(colors)],
|
|
63
|
+
label=f"y = {expression}",
|
|
64
|
+
),
|
|
65
|
+
)
|
|
66
|
+
for index, expression in enumerate(expressions)
|
|
67
|
+
),
|
|
68
|
+
viewport=Viewport2D(
|
|
69
|
+
x=PlotRange(x_min, x_max),
|
|
70
|
+
y=PlotRange(y_min, y_max),
|
|
71
|
+
),
|
|
72
|
+
title=title,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
__all__ = ["compare_functions_scene", "function_scene"]
|