-
Notifications
You must be signed in to change notification settings - Fork 39
scipy minimize generator #424
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 12 commits
986e86c
68ab06b
caeb5f2
f85cf21
bbab28e
38a180a
5b4d53a
42f6071
b5b1686
711b718
6cf6af0
9eb7a74
406239d
cbf70fd
8d82e11
b1f28b2
4de94b6
ca1a4d1
f47a551
95f460a
bca8044
c0bbd6a
cd8a547
a28406e
54530c9
1749e41
929dd09
cf64fa0
eeea483
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| # Scipy Minimize Generator | ||
|
|
||
| `ScipyGenerator` exposes scipy's `optimize.minimize` methods through Xopt's sequential ask/tell interface. | ||
|
|
||
| ## Integration Model | ||
|
|
||
| Xopt evaluates objective functions externally, one point at a time. `scipy.optimize.minimize` expects an in-process callable objective. `ScipyGenerator` bridges this mismatch by replaying known evaluations: | ||
|
|
||
| 1. A cache is built from `X.data`. | ||
| 2. `minimize` is called with an objective wrapper that checks the cache first. | ||
| 3. If scipy asks for an unseen point, the generator raises an internal signal, exits `minimize`, and returns that point to Xopt. | ||
| 4. Xopt evaluates that point and appends the result. | ||
| 5. On the next `step`, `minimize` is called again with the larger cache. | ||
|
|
||
| ## Performance Notes | ||
|
|
||
| - Cache reconstruction is O(N) per `step`, where N is the number of collected evaluations. | ||
| - `minimize` restarts each `step`, so there is repeated optimizer bookkeeping overhead. | ||
| - For expensive evaluations, this overhead is usually negligible. | ||
| - For cheap synthetic test functions, this overhead can be a significant part of runtime. | ||
|
roussel-ryan marked this conversation as resolved.
Outdated
|
||
|
|
||
| ## Configuration | ||
|
|
||
| Typical fields: | ||
|
|
||
| - `method`: scipy minimization method name, e.g. `Powell`, `Nelder-Mead`, `L-BFGS-B`. | ||
| - `initial_point`: optional starting point dictionary. | ||
| - `tol`, `options`: passed directly to `scipy.optimize.minimize`. | ||
| - `scipy_kwargs`: additional keyword arguments forwarded to scipy. | ||
|
|
||
| ::: xopt.generators.sequential.scipy | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Formatting, make titles title case. Probably don't need a header for imports. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| { | ||
| "cells": [ | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "3841297f", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "# ScipyGenerator with scipy.optimize.minimize\n", | ||
| "\n", | ||
| "This notebook demonstrates how to use Xopt's `ScipyGenerator` to drive any supported scipy `optimize.minimize` method in a sequential ask/tell workflow." | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "ask/tell" isn't jargon we use anywhere else. This feels like an LLM'ism making up terms. I would recommend using the names used elsewhere for the generator. Check your PR for other uses of this phrase.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed |
||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "ece077aa", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "## Imports" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "2517dcff", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "import matplotlib.pyplot as plt\n", | ||
| "\n", | ||
| "from xopt import Evaluator, VOCS, Xopt\n", | ||
| "from xopt.generators.sequential.scipy import ScipyGenerator" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "ca499090", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "## Define a simple objective\n", | ||
| "\n", | ||
| "We will optimize the 2D Rosenbrock function, exposed through an Xopt evaluator function." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "7702f19c", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "def rosenbrock_eval(input_dict):\n", | ||
| " x0 = input_dict[\"x0\"]\n", | ||
| " x1 = input_dict[\"x1\"]\n", | ||
| " y = (1 - x0) ** 2 + 100.0 * (x1 - x0**2) ** 2\n", | ||
| " return {\"y\": float(y)}" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "29a8f4d5", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "## Configure `ScipyGenerator`\n", | ||
| "\n", | ||
| "Choose a scipy method using `method`. Here we use `Powell`, but methods such as `Nelder-Mead`, `L-BFGS-B`, and others can also be used." | ||
|
roussel-ryan marked this conversation as resolved.
Outdated
|
||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "b020f9b7", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "vocs = VOCS(\n", | ||
| " variables={\"x0\": [-2.0, 2.0], \"x1\": [-1.0, 3.0]},\n", | ||
| " objectives={\"y\": \"MINIMIZE\"},\n", | ||
| ")\n", | ||
| "\n", | ||
| "generator = ScipyGenerator(\n", | ||
| " vocs=vocs,\n", | ||
| " method=\"L-BFGS-B\",\n", | ||
| " initial_point={\"x0\": -1.2, \"x1\": 1.0},\n", | ||
| " options={\"maxiter\": 200},\n", | ||
| ")\n", | ||
| "\n", | ||
| "evaluator = Evaluator(function=rosenbrock_eval)\n", | ||
| "X = Xopt(generator=generator, evaluator=evaluator, vocs=vocs)" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "6b3fe58b", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "## Run optimization" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "775e0fe9", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "for _ in range(200):\n", | ||
| " X.step()\n", | ||
| "\n", | ||
| "best_idx = X.data[\"y\"].argmin()\n", | ||
| "best = X.data.iloc[best_idx]\n", | ||
| "\n", | ||
| "print(\"Evaluations:\", len(X.data))\n", | ||
| "print(\"Best point:\", {\"x0\": float(best[\"x0\"]), \"x1\": float(best[\"x1\"])})\n", | ||
| "print(\"Best objective:\", float(best[\"y\"]))" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "444a1f87", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "## Inspect convergence" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "a5518499", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "ax = X.data[\"y\"].plot(figsize=(7, 4), logy=True)\n", | ||
| "ax.set_xlabel(\"iteration\")\n", | ||
| "ax.set_ylabel(\"objective y (log scale)\")\n", | ||
| "ax.set_title(\"ScipyGenerator optimization progression\")\n", | ||
| "plt.tight_layout()" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "f693d7e1", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "## Notes on performance\n", | ||
| "\n", | ||
| "`ScipyGenerator` bridges scipy's in-process `minimize` API into Xopt's external evaluation loop by replaying cached points each step. This adds overhead that is small for expensive evaluations but can be noticeable for very fast toy objectives." | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Style thing: I don't know if I'd add low level details in the example |
||
| ] | ||
| } | ||
| ], | ||
| "metadata": { | ||
| "kernelspec": { | ||
| "display_name": "xopt-dev", | ||
| "language": "python", | ||
| "name": "python3" | ||
| }, | ||
| "language_info": { | ||
| "codemirror_mode": { | ||
| "name": "ipython", | ||
| "version": 3 | ||
| }, | ||
| "file_extension": ".py", | ||
| "mimetype": "text/x-python", | ||
| "name": "python", | ||
| "nbconvert_exporter": "python", | ||
| "pygments_lexer": "ipython3", | ||
| "version": "3.14.2" | ||
| } | ||
| }, | ||
| "nbformat": 4, | ||
| "nbformat_minor": 5 | ||
| } | ||
|
roussel-ryan marked this conversation as resolved.
|
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.