Skip to content

Commit dcceee9

Browse files
committed
get 'er done
1 parent 416bad1 commit dcceee9

File tree

69 files changed

+5990
-3530
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+5990
-3530
lines changed

README.md

Lines changed: 98 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,57 +6,72 @@ A comprehensive Clojure library for numerical optimization, root-finding, interp
66

77
### Root-Finding
88

9-
- **`root-solvers`** — Univariate root-finding with multiple algorithms: Brent-Dekker, modified Newton-Raphson, Muller, plus Hipparchus methods (bisection, Brent, Illinois, Pegasus, Ridders, secant, Regula-Falsi). Includes quadratic equation solver.
9+
- **`roots.continuous`** — Univariate root-finding with multiple algorithms: Brent-Dekker, modified Newton-Raphson, Muller, plus Hipparchus methods (bisection, Brent, Illinois, Pegasus, Ridders, secant, Regula-Falsi). Includes quadratic equation solver.
1010

11-
- **`integer-root-solvers`** — Bisection algorithm for strictly increasing discrete functions. Returns the minimum integer with function value ≥ 0.
11+
- **`roots.integer`** — Bisection algorithm for strictly increasing discrete functions. Returns the minimum integer with function value ≥ 0.
1212

13-
- **`plateau-root-solvers`** — Root-finding for monotonic functions that return plateau values. Supports univariate and multivariate cases.
13+
- **`roots.plateau`** — Root-finding for monotonic functions that return plateau values. Supports univariate and multivariate cases.
14+
15+
- **`roots.polynomial`** — Polynomial root-finding using Laguerre's method via Hipparchus.
1416

1517
### Optimization
1618

17-
- **`optimize-univariate`** — Brent optimizer for 1D minimization/maximization over bounded intervals.
19+
- **`optimize.continuous-univariate`** — Brent optimizer for 1D minimization/maximization over bounded intervals.
20+
21+
- **`optimize.integer-univariate`** — Integer optimizer using exponential search or ternary search. Handles unimodal functions over integer domains.
22+
23+
- **`optimize.linear`** — Two-phase Simplex Method. Minimizes/maximizes linear objectives subject to linear constraints (equality, ≤, ≥).
24+
25+
- **`optimize.mixed-integer`** — Mixed Integer Programming (MIP) using OjAlgo. Extends linear programming to support integer and binary variable constraints.
26+
27+
- **`optimize.quadratic`** — Minimizes (1/2)x^T P x + q^T x subject to equality and inequality constraints using OjAlgo.
1828

19-
- **`integer-optimize`**Custom integer maximizer that exponentially focuses search around a guess. Handles functions with at most one sign change in derivative.
29+
- **`optimize.nlp-constrained`**Constrained nonlinear optimization using COBYLA. Minimizes objectives subject to nonlinear inequality constraints (≥ 0).
2030

21-
- **`linear-programming`** — Two-phase Simplex Method. Minimizes/maximizes linear objectives subject to linear constraints (equality, ≤, ≥).
31+
- **`optimize.nlp-unbounded`** — Unbounded nonlinear optimization with multiple pure-Clojure algorithms:
32+
- *Powell*: derivative-free direction-set method
33+
- *Nelder-Mead*: simplex-based derivative-free optimization
34+
- *L-BFGS*: limited-memory quasi-Newton with optional gradient
35+
- *Gauss-Newton*: nonlinear least-squares for residual minimization
36+
- Auto-selecting orchestrator tries multiple algorithms
2237

23-
- **`quadratic-programming`** — Minimizes (1/2)x^T P x + q^T x subject to equality and inequality constraints using OjAlgo.
38+
- **`optimize.nlp-bounded`** — Bounded nonlinear optimization with box constraints:
39+
- *COBYLA*: linear-approximation constrained optimization
40+
- *BOBYQA*: quadratic-model bound-constrained optimization
41+
- *CMA-ES*: evolutionary strategy for non-smooth/non-convex objectives
2442

25-
- **`nonlinear-programming`** — Multiple solvers for nonlinear optimization:
26-
- *Constrained*: Cobyla for inequality constraints
27-
- *Unbounded*: Powell, Nelder-Mead, Multi-directional Simplex, Conjugate Gradient (Polak-Ribière, Fletcher-Reeves)
28-
- *Bounded*: BOBYQA, Cobyla, CMA-ES (evolutionary, handles non-smooth/non-convex objectives)
43+
### Systems (Equation Solving)
2944

30-
### Constraint Satisfaction
45+
Solvers for systems of equations without an objective function to optimize:
3146

32-
- **`nonlinear-constraints-without-objective`** — Finds variable values that satisfy nonlinear constraints:
47+
- **`systems.linear`** — Iterative solvers for symmetric linear systems (A × y = b): SYMMLQ and Conjugate Gradient methods. For small/dense systems, use direct least squares from `provisdom.math.linear-algebra` instead.
48+
49+
- **`systems.nonlinear`** — Finds variable values that satisfy nonlinear constraints:
3350
- Nonlinear Least Squares (Levenberg-Marquardt, Gauss-Newton)
3451
- Nonlinear Ordered Constraints (prioritized constraint satisfaction)
3552

3653
### Interpolation & Curve Fitting
3754

3855
Interpolation is organized by dimensionality:
3956

40-
- **`interpolation-1d`** — 1D interpolation methods:
57+
- **`interpolation.univariate`** — 1D interpolation methods:
4158
- *Methods*: cubic, cubic-hermite, cubic-closed, Akima, PCHIP (monotone-preserving), barycentric-rational, linear, polynomial, step, LOESS (smoothing)
42-
- *Specialized*: quadratic with slope, cubic-clamped with 2nd derivatives, B-spline with knots
59+
- *Specialized*: quadratic with slope, cubic-clamped with 2nd derivatives, B-spline with knots, smoothing spline (with EDF control)
4360
- *Extras*: extrapolation modes (error/flat/linear), batch evaluation, spline integration, auto-selection
4461
- *Slope interpolation*: compute derivatives at query points
4562

46-
- **`interpolation-2d`** — 2D grid-based interpolation (x-vals × y-vals → f-matrix):
63+
- **`interpolation.grid-2d`** — 2D grid-based interpolation (x-vals × y-vals → f-matrix):
4764
- *Methods*: polynomial, bicubic, bicubic-Hermite, bilinear
4865

49-
- **`interpolation-3d`** — 3D grid-based interpolation (x-vals × y-vals × z-vals → f-tensor):
66+
- **`interpolation.grid-3d`** — 3D grid-based interpolation (x-vals × y-vals × z-vals → f-tensor):
5067
- *Methods*: tricubic
5168

52-
- **`interpolation-nd`** — N-D scattered (non-grid) data interpolation:
69+
- **`interpolation.scatter-nd`** — N-D scattered (non-grid) data interpolation:
5370
- *Methods*: microsphere projection, RBF (radial basis functions), natural neighbor (2D only)
5471

55-
- **`curve-fitting`** — Least-squares fitting to find best-fit parameters:
56-
- Gaussian: `a * exp(-((x-b)/c)²)`
57-
- Harmonic: `a * cos(ωx + φ)`
58-
- Polynomial of specified degree
59-
- Arbitrary parametric functions (with user-provided gradient)
72+
- **`fitting.curve`** — Least-squares fitting to find best-fit parameters:
73+
- *Nonlinear* (Levenberg-Marquardt): Gaussian, Harmonic, Polynomial, arbitrary parametric
74+
- *Linear basis* (closed-form): custom basis functions for univariate and multivariate data
6075

6176
#### Interpolation vs Curve Fitting
6277

@@ -71,41 +86,83 @@ Interpolation is organized by dimensionality:
7186

7287
**Note**: LOESS is in the interpolation namespace (same API) but doesn't pass through points—it performs local regression for smoothing noisy data.
7388

89+
#### Curve Fitting vs Regression
90+
91+
| Aspect | Curve Fitting | Regression |
92+
|--------|---------------|------------|
93+
| **Goal** | Find parameters of a known functional form | Model statistical relationships between X and y |
94+
| **Functional form** | Arbitrary: `a·e^(-((x-b)/c)²)`, `a·cos(ωx+φ)` | Linear in parameters: `y = Xβ` (possibly transformed) |
95+
| **Optimization** | Nonlinear least squares (Levenberg-Marquardt) | Closed-form (OLS/Ridge) or IRLS (GLMs) |
96+
| **Assumptions** | Just minimize residuals | Error distribution, link function |
97+
| **Output** | Parameters of the specific function | Coefficients + diagnostics (R², MSE, precision) |
98+
99+
**Curve fitting** answers: "Given this formula, what parameters fit best?"
100+
101+
**Regression** answers: "What's the statistical relationship between predictors X and response y?"
102+
103+
Logistic and beta regression aren't just curve fitting—they model the *distribution* of y given X (Bernoulli, Beta) with appropriate link functions, using Iteratively Reweighted Least Squares (IRLS).
104+
74105
### Regression
75106

76-
- **`logistic-regression`** — Iteratively Reweighted Least Squares (IRLS) with optional ridge regularization.
107+
All regression methods are in the `provisdom.solvers.regression` namespace hierarchy:
108+
109+
- **`regression.ordinary`** — Ordinary least squares with optional regularization:
110+
- *OLS* — Standard least squares via QR decomposition
111+
- *Ridge (L2)* — Closed-form solution with λI penalty
112+
- *LASSO (L1)* — Coordinate descent for sparse solutions
113+
- *Elastic Net* — Combined L1+L2 via coordinate descent
114+
115+
- **`regression.logistic`** — Binary logistic regression using IRLS with optional ridge regularization.
116+
117+
- **`regression.multinomial-logistic`** — Multi-class logistic regression (one-vs-all approach).
118+
119+
- **`regression.beta`** — Beta regression for responses bounded in (0, 1) using IRLS.
120+
121+
- **`regression.kernel-grnn`** — Generalized Regression Neural Network (Nadaraya-Watson kernel regression) with automatic spread optimization.
122+
123+
- **`regression.stepwise`** — Stepwise variable selection:
124+
- *Forward* — Start empty, iteratively add best predictor
125+
- *Backward* — Start full, iteratively remove worst predictor
126+
- *Both* — Combine forward and backward steps
127+
- Supports AIC/BIC scoring with ordinary, logistic, or beta regression
128+
129+
#### IRLS (Iteratively Reweighted Least Squares)
77130

78-
- **`multinomial-logistic-regression`** IRLS for multi-class classification.
131+
Logistic and beta regression use IRLS, which fits generalized linear models by iteratively solving weighted least squares problems:
79132

80-
- **`generalized-regression-neural-network`** — GRNN for non-parametric regression with automatic spread parameter optimization.
133+
1. Compute working weights W based on current predictions
134+
2. Compute working response z (adjusted dependent variable)
135+
3. Solve weighted OLS: `β = (X'WX)⁻¹ X'Wz`
136+
4. Repeat until convergence
81137

82-
### Linear Systems
138+
For logistic regression: `W = diag(μ(1-μ))`, `z = η + (y-μ)/(μ(1-μ))`
83139

84-
- **`iterative-linear-least-squares`** — Iterative solvers for symmetric linear systems (A × y = b): SYMMLQ and Conjugate Gradient methods.
140+
For beta regression: `W = diag(φ·μ(1-μ))`, `z = η + (y-μ)/(μ(1-μ))`
85141

86142
## Usage
87143

88144
```clojure
89-
(require '[provisdom.solvers.root-solvers :as root])
90-
(require '[provisdom.solvers.nonlinear-programming :as nlp])
91-
(require '[provisdom.solvers.interpolation-1d :as interp-1d])
145+
(require '[provisdom.solvers.roots.continuous :as roots])
146+
(require '[provisdom.solvers.common :as common])
147+
(require '[provisdom.solvers.optimize.nlp-bounded :as nlp])
148+
(require '[provisdom.solvers.interpolation.univariate :as interp])
92149

93150
;; Find root of f(x) = x³ - 3x
94-
(root/root-solver
95-
{::root/univariate-f (fn [x] (- (* x x x) (* 3 x)))
96-
::root/guess 2.0
97-
::root/interval [-5.0 5.0]})
151+
(roots/root-solver
152+
{::roots/univariate-f (fn [x] (- (* x x x) (* 3 x)))
153+
::roots/guess 2.0
154+
::roots/interval [-5.0 5.0]})
98155

99156
;; Minimize f(x,y) = x² + y² subject to bounds
100-
(nlp/bounded-nonlinear-programming-without-evolutionary
101-
{::nlp/objective (fn [da] (let [[x y] da] (+ (* x x) (* y y))))
102-
::nlp/vars-guess [1.0 1.0]
157+
(nlp/bounded-nlp-without-evolutionary
158+
{::common/objective (fn [da] (let [[x y] da] (+ (* x x) (* y y))))
159+
::common/vars-guess [1.0 1.0]
103160
::nlp/var-intervals [[-10.0 10.0] [-10.0 10.0]]})
104161

105162
;; Cubic spline interpolation
106-
(let [f (interp-1d/interpolation-1D
107-
{::interp-1d/f-vals [0.0 1.0 4.0 9.0]
108-
::interp-1d/x-vals [0.0 1.0 2.0 3.0]})]
163+
(let [f (interp/interpolation-1D
164+
{::interp/f-vals [0.0 1.0 4.0 9.0]
165+
::interp/x-vals [0.0 1.0 2.0 3.0]})]
109166
(f 1.5))
110167
```
111168

siderail/spline.clj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
:end)
6060

6161

62+
6263
(comment
6364
(def rho 0.9)
6465
(def x (vec (sort (repeatedly 100 #(rand (* 10.0 2.0 Math/PI))))))
@@ -85,4 +86,4 @@
8586
#_(pprint data)
8687
(oz/v! (scatter data :log-variance :dof nil)))
8788

88-
:end)
89+
:end)

siderail/stepwise.clj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
(defonce foo (ost/instrument))
1212

13-
1413
(update
1514
(stepwise/solve
1615
{::stepwise/x-mx [[7.0 2.8] [8.0 9.3] [3.0 9.9]
@@ -39,4 +38,4 @@
3938
::stepwise/prob-of-model-fn (fn [component-group]
4039
1.0)})
4140
::stepwise/component-group
42-
keys)
41+
keys)

src/provisdom/solvers/common.clj

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
(s/def ::solver-category
1515
#{::bad-supplied-function ; user-provided function has issues (wrong arity, throws, returns invalid values)
1616
::diverged ; algorithm diverged (rounding errors, etc.)
17+
::infeasible ; constraints are contradictory or cannot be satisfied
1718
::invalid-input ; input violates solver requirements
1819
::max-iterations-exceeded ; solver hit iteration limit without converging
1920
::not-bracketed ; root not bracketed (for bracketing root solvers)
2021
::out-of-bounds ; query point outside valid interpolation range
21-
::singular-matrix}) ; matrix is singular or ill-conditioned
22+
::singular-matrix ; matrix is singular or ill-conditioned
23+
::unbounded}) ; objective can improve infinitely
2224

2325
;;;CONSTANTS
2426
(def accu-precision
@@ -191,3 +193,20 @@
191193
(s/with-gen (s/and ::m/int+ #(<= % 20))
192194
#(gen/choose 2 8)))
193195

196+
;;; Smoothing Spline Specs
197+
(s/def ::smoothing-lambda
198+
(s/with-gen ::m/non-
199+
#(s/gen (s/double-in :min 0.0 :max 10.0 :NaN? false :infinite? false))))
200+
201+
(s/def ::effective-df
202+
(s/with-gen (s/and ::m/finite+ #(>= % 2.0))
203+
#(s/gen (s/double-in :min 2.0 :max 10.0 :NaN? false :infinite? false))))
204+
205+
;;;NLP (Nonlinear Programming)
206+
(s/def ::parallel? boolean?)
207+
(s/def ::objective ::array->number)
208+
209+
(s/def ::cobyla-initial-change
210+
(s/with-gen ::m/finite+
211+
#(s/gen (s/double-in :infinite? false :NaN? false :min 1e-3 :max 1e3))))
212+

0 commit comments

Comments
 (0)