EOIL compute optimisation SDK
Project description
EOIL Python SDK
Python client for the EOIL optimisation API.
Version:
0.5.0— beta. API is stable.
Installation
pip install eoil
Requires Python ≥ 3.10. NumPy is optional but recommended — the SDK passes np.ndarray to
your objective function when it's installed, otherwise list[float].
Authentication
Get an API key from app.eoil.ltd → API Keys.
import eoil
client = eoil.Client(api_key="eoil_sk_...")
# Or set the environment variable EOIL_API_KEY and omit api_key=
1. Custom objective functions (stream_optimize)
Run your own Python function against the EOIL optimizer. Your code never leaves your machine — only candidate coordinate vectors and scalar values cross the network.
def rosenbrock(x):
# x is np.ndarray (if numpy installed) or list[float]
f = (1 - x[0])**2 + 100*(x[1] - x[0]**2)**2
grad = [
-2*(1 - x[0]) - 400*x[0]*(x[1] - x[0]**2),
200*(x[1] - x[0]**2),
]
return f, grad # return (f, grad) to supply gradient directly
result = client.stream_optimize(
rosenbrock,
dimension=2,
budget_steps=500,
bounds=(-5.0, 5.0),
)
print(result.x_best) # [1.0, 1.0] best solution found
print(result.f_best) # ~0.0 best objective value
print(result.converged) # True / False
print(result.steps) # int evaluations consumed
print(result.eoil_charged) # "5.0" compute units charged
Gradient options
gradient= |
Behaviour |
|---|---|
"auto" (default) |
Inspect return type on first call — tuple → use grad; scalar → finite differences |
True |
Function must return (f, grad). Raises StreamError if it returns a scalar. |
False |
Always use finite differences, even if function returns a tuple. |
When finite differences are used, the SDK prints a one-time warning and costs 2 × dimension
extra function calls per step. Supply an analytic gradient to avoid this.
Live progress
def on_step(step, x, f_best):
if f_best is not None:
print(f"step {step:4d} | f_best={f_best:.6f}")
result = client.stream_optimize(
my_fn,
dimension=10,
budget_steps=1000,
on_step=on_step,
)
All parameters
| Parameter | Default | Description |
|---|---|---|
fn |
required | Objective function. Returns float or (float, list[float]). |
dimension |
required | Problem dimensionality (1–1000). |
budget_steps |
200 |
Approximate number of function evaluations (100–100 000). |
bounds |
(-5.0, 5.0) |
Box bounds (lower, upper) applied uniformly. |
x0 |
None |
Initial point. Server picks randomly if omitted. |
gradient |
"auto" |
Gradient supply mode — see table above. |
fd_step |
1e-5 |
Finite-difference step size. |
on_step |
None |
Callback on_step(step, x, f_best) called after each evaluation. |
timeout_s |
3600.0 |
Total session wall-clock timeout in seconds. |
eval_timeout_s |
80.0 |
Per-evaluation timeout. Raises if function exceeds this. |
verify_ssl |
True |
Set False for staging or self-signed certs. |
2. Catalogue (client.catalogue)
Run built-in optimisation problems — no objective function needed.
Benchmark functions
result = client.catalogue.rastrigin(dimension=20, budget_steps=1000)
result = client.catalogue.sphere(dimension=10, budget_steps=500)
result = client.catalogue.rosenbrock(dimension=15, budget_steps=2000)
result = client.catalogue.ackley(dimension=10, budget_steps=1000)
result = client.catalogue.levy(dimension=10, budget_steps=1000)
result = client.catalogue.griewank(dimension=10, budget_steps=1000)
result = client.catalogue.quadratic(dimension=10, budget_steps=1000)
Portfolio optimisation
import numpy as np
# Maximise Sharpe ratio — pass a (T × N) returns matrix
returns = np.random.randn(252, 5) * 0.01 # 252 trading days, 5 assets
result = client.catalogue.portfolio_sharpe(
returns=returns,
dimension=5,
budget_steps=2000,
)
weights = result.x_best # portfolio weights, sum to 1
# Minimise portfolio variance — pass an (N × N) covariance matrix
cov = np.cov(returns.T)
result = client.catalogue.portfolio_minvol(
cov=cov,
dimension=5,
budget_steps=2000,
)
Plain Python nested lists are accepted wherever NumPy arrays are shown.
Available catalogue methods
| Method | Description |
|---|---|
catalogue.sphere() |
Convex, global min at origin |
catalogue.rastrigin() |
Highly multimodal |
catalogue.rosenbrock() |
Narrow curved valley |
catalogue.quadratic() |
Coupled quadratic (ill-conditioned) |
catalogue.ackley() |
Many local minima |
catalogue.levy() |
Global min at x=(1,…,1) |
catalogue.griewank() |
Regularly spaced local minima |
catalogue.portfolio_sharpe() |
Maximise Sharpe ratio |
catalogue.portfolio_minvol() |
Minimise portfolio variance |
3. Optimizer presets
Presets are heuristics_override dicts tuned for common scenarios.
from eoil import PRESETS, get_preset
result = client.catalogue.rastrigin(
dimension=50,
budget_steps=5000,
heuristics_override=PRESETS["thorough"],
)
# get_preset() returns a copy — safe to modify
opts = get_preset("portfolio")
opts["escape_strength"] = 0.8
result = client.catalogue.portfolio_sharpe(
returns=returns,
dimension=5,
budget_steps=3000,
heuristics_override=opts,
)
| Preset | Best for |
|---|---|
fast |
CI checks and quick feasibility runs |
balanced |
General-purpose (default) |
thorough |
Production-quality results |
portfolio |
Sharpe ratio and minimum-variance problems |
ml_hyperparam |
Machine learning hyperparameter search |
high_dimensional |
Problems with dimension ≥ 100 |
4. Async job submission
# Submit and get a job ID immediately
job_id = client.submit_job(objective_type="ackley", dimension=20)
# Retrieve the result later (polling)
result = client.get_job(job_id)
5. Result object
Both stream_optimize() and catalogue methods return a result object with these fields:
| Field | Alias | Description |
|---|---|---|
x_best |
.x |
Best solution vector found |
f_best |
.f |
Best objective value |
converged |
— | Whether the optimizer declared convergence |
total_steps |
.steps |
Evaluations consumed |
eoil_charged |
— | Compute units charged (stream_optimize only) |
6. Error handling
from eoil import (
AuthError,
InsufficientBalanceError,
RateLimitError,
StreamError,
SessionExpiredError,
EoilError,
)
try:
result = client.stream_optimize(my_fn, dimension=10, budget_steps=500)
except AuthError:
print("Invalid or missing API key — check app.eoil.ltd → API Keys")
except InsufficientBalanceError:
print("Insufficient compute balance")
except RateLimitError:
print("Rate limit hit — retry shortly")
except SessionExpiredError:
print("Session expired — try again")
except StreamError as e:
print(f"Stream error [{e.code}]: {e}")
except EoilError as e:
print(f"API error: {e}")
What's New in 0.5.0
eoil.adapters.scipy— drop-in replacement forscipy.optimize.minimizeeoil.adapters.sklearn—EOILSearchCVreplacesGridSearchCV/RandomizedSearchCVeoil.adapters.pytorch—EOILOptimizerfornn.Moduletraining loopseoil.adapters.pandas—EOILPortfolioOptimizerfor portfolio optimisation onpd.DataFrame- Promoted to Beta — all adapters tested against production API
Development
# Install in editable mode with dev dependencies
pip install -e ".[dev]"
# Run tests (no API key needed — HTTP and WebSocket are mocked)
pytest tests/ -v
Links
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file eoil-0.5.0.tar.gz.
File metadata
- Download URL: eoil-0.5.0.tar.gz
- Upload date:
- Size: 47.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1704bc3b7bf5a90dab56837bc943d5a5712f0c2974ace3191d082e299bcef8cd
|
|
| MD5 |
ac086813efce483439d0cc7c02c9b61f
|
|
| BLAKE2b-256 |
d8c366921680d56f3f5b620b9bc517b5fb71c843657dbc5b71159b69d7793572
|
Provenance
The following attestation bundles were made for eoil-0.5.0.tar.gz:
Publisher:
publish.yml on EOIL-TEAM/EOIL-PYTHON
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
eoil-0.5.0.tar.gz -
Subject digest:
1704bc3b7bf5a90dab56837bc943d5a5712f0c2974ace3191d082e299bcef8cd - Sigstore transparency entry: 1717211018
- Sigstore integration time:
-
Permalink:
EOIL-TEAM/EOIL-PYTHON@6daf489a42c95d5d6ca89b010e0b46f069d9d0d0 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/EOIL-TEAM
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6daf489a42c95d5d6ca89b010e0b46f069d9d0d0 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file eoil-0.5.0-py3-none-any.whl.
File metadata
- Download URL: eoil-0.5.0-py3-none-any.whl
- Upload date:
- Size: 35.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b447cab1db44f20a104c9500139968442cc345eda0c34d7169d15942d576c044
|
|
| MD5 |
f2ccb2da06ef68891aaa2becf723677b
|
|
| BLAKE2b-256 |
014a8e076dd2d5123f20b21090325be7a1434a46145b95af6716777a10c486f0
|
Provenance
The following attestation bundles were made for eoil-0.5.0-py3-none-any.whl:
Publisher:
publish.yml on EOIL-TEAM/EOIL-PYTHON
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
eoil-0.5.0-py3-none-any.whl -
Subject digest:
b447cab1db44f20a104c9500139968442cc345eda0c34d7169d15942d576c044 - Sigstore transparency entry: 1717211079
- Sigstore integration time:
-
Permalink:
EOIL-TEAM/EOIL-PYTHON@6daf489a42c95d5d6ca89b010e0b46f069d9d0d0 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/EOIL-TEAM
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6daf489a42c95d5d6ca89b010e0b46f069d9d0d0 -
Trigger Event:
workflow_dispatch
-
Statement type: