Download benchmarks/math/circle_packing/codebase/reference/optimization_patterns.py from JustinTX/sky2: direct link, hf CLI and curl.
- Browser
- Download file 3.16 kB
-
https://huggingface.co/JustinTX/sky2/resolve/main/benchmarks/math/circle_packing/codebase/reference/optimization_patterns.py
- Command line
-
hf download hf://JustinTX/sky2/benchmarks/math/circle_packing/codebase/reference/optimization_patterns.py
-
curl -L -o optimization_patterns.py https://huggingface.co/JustinTX/sky2/resolve/main/benchmarks/math/circle_packing/codebase/reference/optimization_patterns.py
3.16 kB
| """ | |
| Common patterns for constrained geometric optimization using scipy. | |
| This module shows how to use scipy.optimize.minimize with inequality | |
| constraints and the SLSQP solver — useful for any problem where you | |
| need to maximize/minimize an objective subject to geometric constraints. | |
| """ | |
| import numpy as np | |
| from scipy.optimize import minimize | |
| def example_constrained_optimization(): | |
| """ | |
| Template: pack n objects by optimizing positions + sizes jointly. | |
| Decision vector: x = [pos_0, pos_1, ..., pos_{n-1}, size_0, ..., size_{n-1}] | |
| Objective: maximize sum(sizes) => minimize -sum(sizes) | |
| Constraints: non-overlap + boundary containment (all >= 0) | |
| """ | |
| n = 10 # number of objects | |
| # --- Objective: negative sum of sizes (we minimize, so negate to maximize) --- | |
| def objective(x): | |
| sizes = x[2 * n:] | |
| return -np.sum(sizes) | |
| # --- Constraints as a single function returning array of values >= 0 --- | |
| def constraints_fn(x): | |
| positions = x[:2 * n].reshape(n, 2) | |
| sizes = x[2 * n:] | |
| c = [] | |
| # Pairwise non-overlap: dist(i,j) - size_i - size_j >= 0 | |
| for i in range(n): | |
| for j in range(i + 1, n): | |
| dist = np.linalg.norm(positions[i] - positions[j]) | |
| c.append(dist - sizes[i] - sizes[j]) | |
| # Boundary: each object stays inside [0, 1] x [0, 1] | |
| for i in range(n): | |
| c.append(positions[i, 0] - sizes[i]) # left | |
| c.append(1 - positions[i, 0] - sizes[i]) # right | |
| c.append(positions[i, 1] - sizes[i]) # bottom | |
| c.append(1 - positions[i, 1] - sizes[i]) # top | |
| return np.array(c) | |
| # --- Initial guess --- | |
| x0_pos = np.random.rand(n, 2) * 0.6 + 0.2 # avoid edges | |
| x0_sizes = np.full(n, 0.05) | |
| x0 = np.concatenate([x0_pos.flatten(), x0_sizes]) | |
| # --- Bounds --- | |
| pos_bounds = [(0, 1)] * (2 * n) | |
| size_bounds = [(0.01, 0.25)] * n | |
| bounds = pos_bounds + size_bounds | |
| # --- Solve --- | |
| result = minimize( | |
| objective, | |
| x0, | |
| method="SLSQP", | |
| bounds=bounds, | |
| constraints={"type": "ineq", "fun": constraints_fn}, | |
| options={"maxiter": 1000, "ftol": 1e-9}, | |
| ) | |
| opt_positions = result.x[:2 * n].reshape(n, 2) | |
| opt_sizes = result.x[2 * n:] | |
| return opt_positions, opt_sizes, -result.fun # return positive sum | |
| def multi_start_optimization(objective, constraint_fn, bounds, n_starts=5): | |
| """ | |
| Run SLSQP from multiple random starts and keep the best. | |
| This helps escape local optima — the solver is gradient-based | |
| and sensitive to the initial guess. | |
| """ | |
| best_result = None | |
| for _ in range(n_starts): | |
| x0 = np.array([np.random.uniform(lo, hi) for lo, hi in bounds]) | |
| result = minimize( | |
| objective, | |
| x0, | |
| method="SLSQP", | |
| bounds=bounds, | |
| constraints={"type": "ineq", "fun": constraint_fn}, | |
| options={"maxiter": 500, "ftol": 1e-8}, | |
| ) | |
| if best_result is None or result.fun < best_result.fun: | |
| best_result = result | |
| return best_result | |