Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This file is used to track changes made to the project over time.
### Additions
- Support for Sobol sequences in polynomial problem sampling
- Support for periodic kernel
- Support for [`newton-sos`](https://github.com/agroudiev/newton-sos) Rust-based solver

## [0.2.2] - 2025-11-14
### Additions
Expand Down
4 changes: 2 additions & 2 deletions example.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# solver), newton-features or newton-kernel (more advanced solvers using
# feature or kernel matrices, respectively; adding e.g. a linesearch option
# and more advanced diagnostics to the original solver.
solver = "newton"
solver = "newton-rs"

# Which kernel to use: use Gauss for smooth, Laplace for less smooth,
# or provide a kernel of your choice.
Expand All @@ -31,5 +31,5 @@
solver=solver,
sigma=sigma,
)
print(f"Found solution: x={solution[0]:.4f}, f={info['cost']:.4f}")
print(f"Found solution: x={solution[0].reshape(-1).item():.4f}, f={info['cost']:.4f}")
print(f"True solution: x={-np.pi/2:.4f}, f=-1")
1 change: 1 addition & 0 deletions ksos_env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ dependencies:
- pytest
- pip:
- mosek
- newton_sos
- -e .
40 changes: 32 additions & 8 deletions ksos_tools/solvers/ksos.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ def solve(
verbose: bool
If True, prints the Sobolev norm and decay at each iteration.
solver: str
The solver to use. Either 'newton', 'newton-original','MOSEK', 'SCS', or 'naive'.
The solver to use. Either 'newton', 'newton-rs','MOSEK', 'SCS', or 'naive'.
- `newton`: uses the damped Newton method as suggested by Rudi et al.
- `newton-new`: uses a new interior-point Newton method.
- `newton-rs`: same as `newton`, using an efficient implementation in Rust
- `naive`: retrieves the best sample.
- others: uses CVXPY with the specified solver.
max_iters_scs: int
Expand Down Expand Up @@ -126,6 +126,7 @@ def solve(
assert isinstance(verbose, bool)
assert solver in [
"newton",
"newton-rs",
"newton-features",
"newton-kernel",
"MOSEK",
Expand Down Expand Up @@ -169,7 +170,12 @@ def solve(
else:
problem.register_fixed_samples(samples, f, None)

if solver != "naive":
if solver == "newton-rs":
import newton_sos
rs_problem = newton_sos.Problem(lambd, t, problem.samples.astype(np.float64), problem.f_samples.astype(np.float64))
# TODO: catch errors if any
rs_problem.initialize_native_kernel(kernel, sigma)
elif solver != "naive":
success = problem.initialize_kernel(
sigma, kernel, verbose=verbose, llt_method=llt_method
)
Expand All @@ -186,12 +192,17 @@ def solve(
)
if solver == "naive":
break

success = problem.initialize_kernel(
sigma, kernel, verbose=verbose, llt_method=llt_method
)
if success:
elif solver == "newton-rs":
import newton_sos
rs_problem = newton_sos.Problem(lambd, t, problem.samples.astype(np.float64), problem.f_samples.astype(np.float64))
rs_problem.initialize_native_kernel(kernel, sigma) # TODO: catch errors if any
break
else:
success = problem.initialize_kernel(
sigma, kernel, verbose=verbose, llt_method=llt_method
)
if success:
break

fail_count += 1
if fail_count >= MAX_FAIL_COUNT or sampling == "linspace":
Expand Down Expand Up @@ -223,6 +234,19 @@ def solve(
verbose=verbose,
return_B=return_B,
)
elif solver == "newton-rs":
solve_result = newton_sos.solve(rs_problem, max_iter=max_iters_newton, verbose=verbose, method="partial_piv_lu")
z = solve_result.z_hat
# TODO: lazy evaluation of phi and B
rs_problem.compute_phi()
info_here = {
"cost": solve_result.cost,
"alpha": solve_result.alpha,
"status": solve_result.status,
"success": solve_result.converged,
"B": solve_result.get_B(rs_problem),
# "X": X,
}
elif solver == "newton-features":
problem.use_K = False
z, info_here = newton.damped_newton_advanced(
Expand Down
Loading