Add a new single-objective optimizer
SkillDev toolsAdd a new single-objective optimization algorithm to the sci-comp library. Use when the user asks to implement a new optimizer (e.g. gradient descent, BFGS, simulated annealing, differential evolution).
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Add a new single-objective optimizer skill
What this skill tells your AI
The instructions your AI receives, as published by datagrok-ai/public in libraries/sci-comp/.claude/skills/add-optimizer/SKILL.md and read by ahel’s review.
The user wants to add a new optimizer: $ARGUMENTS
Follow these steps exactly. Do not skip any step.
Step 1: Understand the algorithm
Before writing code, research the algorithm:
- What are its tunable hyperparameters?
- Is it population-based or single-point?
- Does it require gradients?
- What is the iteration logic?
Step 2: Read the reference implementation
Read these files to understand codebase patterns:
src/optimization/single-objective/optimizers/nelder-mead.ts— reference optimizersrc/optimization/single-objective/__tests__/nelder-mead.test.ts— reference tests (the new optimizer MUST include all the same test cases)src/optimization/single-objective/__tests__/helpers.ts— test functions and helperssrc/optimization/single-objective/examples/unconstrained.ts— reference example
Step 3: Create the optimizer file
Create src/optimization/single-objective/optimizers/<name>.ts following the pattern from nelder-mead.ts.
Rules (beyond what's visible in the reference)
runInternalreceives the already-penalized objective — do NOT handle constraintsrunInternalreceives settings with defaults already applied viawithDefaults- Set
converged = trueonly if a convergence criterion was met, not just maxIterations - Pre-allocate all buffers before the loop — zero allocations inside the iteration body
- Helper methods must write into caller-provided buffers (out-parameter pattern), not allocate new arrays
costHistory: pre-allocateFloat64Array(maxIter)with a separatecostLencounter; returncostHistory.subarray(0, costLen)
Step 4: Export from index.ts
Edit src/optimization/single-objective/index.ts:
-
Add export for the class and settings type (in the "Built-in optimizers" section):
export {<Name>} from './optimizers/<name>'; export type {<Name>Settings} from './optimizers/<name>'; -
Add auto-registration (in the "Auto-register" section at the bottom):
import {<Name>} from './optimizers/<name>'; registerOptimizer('<kebab-name>', () => new <Name>());
Step 5: Write tests
Create src/optimization/single-objective/__tests__/<name>.test.ts.
The new test file MUST replicate ALL test cases from nelder-mead.test.ts — every describe block, each with both sync and async variants.
You may adjust:
x0starting points (if the algorithm needs a closer start)maxIterations,tolerance, and algorithm-specific settings- Precision in
toBeCloseTo/expectPointClose(if the algorithm is less precise)
You must NOT:
- Remove any test group
- Change expected values or expected points
Step 6: Create example file
Create src/optimization/single-objective/examples/<name>.ts following the structure of unconstrained.ts. Must show minimize, maximize, and at least one constrained example with boxConstraints + applyPenalty.
Step 7: Verify
Run in order:
npm run lint-fixnpm run build— must compile without errorsnpm test— run all tests
CRITICAL: If any tests fail, do NOT silently fix or skip them. Instead:
- Collect the full list of failing test names and reasons
- Present the list to the user
- Wait for the user's response — do NOT proceed until the user explicitly approves a course of action This rule applies to every test run, including re-runs after fixes.
Step 8: Add to benchmarks
The benchmark suite is split into two runners that share objective functions via
benchmarks/test-functions.ts. Register the new optimizer in both runners:
src/optimization/single-objective/benchmarks/unconstrained-benchmarks.ts— single x₀ per problemsrc/optimization/single-objective/benchmarks/multistart-benchmarks.ts— three x₀ per problem
In each file:
-
Import the new optimizer class
-
Add an entry to the
optimizersarray:{ name: '<Name>', optimizer: new <Name>(), settings: {maxIterations: 10_000, /* algorithm-specific defaults */}, }, -
Run both benchmarks:
npx tsx src/optimization/single-objective/benchmarks/unconstrained-benchmarks.tsnpx tsx src/optimization/single-objective/benchmarks/multistart-benchmarks.ts
-
Regenerate both markdown reports (
unconstrained-benchmarks.mdandmultistart-benchmarks.md) with the new optimizer's rows/columns. -
Update the problem count / optimizer count in the banner if changed.
Do NOT add new objective functions inline — export them from test-functions.ts so both runners pick them up.
Step 9: Update CLAUDE.md
In CLAUDE.md, update the architecture tree — add the new optimizer file under optimizers/.
Step 10: Add to README.md
In README.md, add the new optimizer to the list under "Single-objective" section, with a Wikipedia or reference link.
Signals
- GitHub stars
- 72
- Forks
- 32
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
add-optimizer- Source
- github.com/datagrok-ai/public