From 791ffffe22affd7b9513abc1bc6c9ca21fc08a2d Mon Sep 17 00:00:00 2001 From: kalyan Date: Fri, 13 Mar 2026 07:11:28 +0000 Subject: [PATCH 1/3] docs: add status badges to README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index f010a40..bdeb562 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # Optimization Algorithms by Prof. R.V. Rao +![Language](https://img.shields.io/badge/language-JavaScript-F7DF1E) + + This package implements several powerful optimization algorithms developed by Prof. Ravipudi Venkata Rao: - **BMR (Best-Mean-Random) Algorithm** - **BWR (Best-Worst-Random) Algorithm** From b3eff103f43b2d2dd4288b4fbed4ac9be6fb0e55 Mon Sep 17 00:00:00 2001 From: Sandeep Kunkunuru Date: Tue, 21 Apr 2026 19:04:57 +0530 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20Rao=20family=20extensions=20v0.10.0?= =?UTF-8?q?=20=E2=80=94=20BMWR=20+=20MO-*=20+=20self-adaptive=20variants?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Python wrappers and Rust bindings for 7 new solvers from Prof. R.V. Rao's 2025–2026 papers (Metals 15/9/1057, Energies 19/1/34, JMMP 9/8/249) and related self-adaptive variants. New Python entry points (rao_algorithms.*): - BMWR_algorithm — Best-Mean-Worst-Random (Rao 2025) - SAMP_Jaya_algorithm — Self-Adaptive Multi-Population Jaya (2017) - EHRJaya_algorithm — Hybrid Jaya + Rao-1 (EAAI 2022) - QO_Rao_algorithm — Quasi-Oppositional Rao (JCDE 2020) New Rust bindings (samyama_optimization.*): - solve_bmwr, solve_samp_jaya, solve_ehrjaya, solve_qo_rao, solve_saphr - solve_mo_bmr, solve_mo_bwr, solve_mo_bmwr, solve_mo_rao_de (with PyMultiObjectiveResult / PyMultiObjectiveIndividual classes) Version bumps: - rao-algorithms (pip): 0.9.3 → 0.10.0 - samyama-optimization-python (Rust crate): 0.9.3 → 0.10.0 - Depends on samyama-optimization crate v1.1.0 (samyama-graph PR #174) Docs: docs/algorithms/bmwr.md, docs/algorithms/mo_bmwr_family.md; updated docs/references/rao_publications.md with 2025–2026 MO papers and implemented self-adaptive variants list. --- docs/algorithms/bmwr.md | 52 ++++++ docs/algorithms/mo_bmwr_family.md | 41 +++++ docs/references/rao_publications.md | 15 ++ pyproject.toml | 4 +- rao_algorithms/__init__.py | 10 +- rao_algorithms/algorithms.py | 26 +++ rust_bindings/Cargo.toml | 4 +- rust_bindings/src/lib.rs | 259 +++++++++++++++++++++++++++- 8 files changed, 405 insertions(+), 6 deletions(-) create mode 100644 docs/algorithms/bmwr.md create mode 100644 docs/algorithms/mo_bmwr_family.md diff --git a/docs/algorithms/bmwr.md b/docs/algorithms/bmwr.md new file mode 100644 index 0000000..b336330 --- /dev/null +++ b/docs/algorithms/bmwr.md @@ -0,0 +1,52 @@ +# BMWR — Best-Mean-Worst-Random + +Parameter-free, metaphor-free optimization algorithm introduced by R. Venkata Rao (2025) in *Optimization of Different Metal Casting Processes Using Three Simple and Efficient Advanced Algorithms* (MDPI Metals 15/9/1057). Combines BMR's best-vs-mean attraction with BWR's worst-vs-random repulsion. + +## Update rule + +For each candidate `V_{j,k}` (variable j, candidate k) at iteration i, with random factors `r1..r5 ∼ U(0,1)` and `T ∼ {1, 2}`: + +If `r4 > 0.5`: + +``` +V'_{j,k} = V_{j,k} + + r1 · (V_{j,best} − T · V_{j,mean}) + + r2 · (V_{j,best} − V_{j,random}) + − r5 · (V_{j,worst} − V_{j,random}) +``` + +Otherwise (random reset, exploration): + +``` +V'_{j,k} = U_j − (U_j − L_j) · r3 +``` + +Greedy acceptance: keep `V'` iff `f(V') < f(V)`. + +## Python usage + +```python +from rao_algorithms import BMWR_algorithm +import numpy as np + +bounds = np.array([[-10, 10], [-10, 10]]) +result = BMWR_algorithm( + bounds=bounds, + num_iterations=500, + population_size=50, + num_variables=2, + objective_func=lambda x: float(np.sum(x**2)), + track_history=True, +) +best_x, history, history_dict = result +``` + +## When to use + +- Problems where BMR alone over-exploits (only attraction terms). +- Problems where BWR alone under-exploits (no mean information). +- BMWR balances both — recommended default within the BMR/BWR/BMWR family. + +## Reference + +Rao, R. V. (2025). *Optimization of Different Metal Casting Processes Using Three Simple and Efficient Advanced Algorithms*. Metals, 15(9), 1057. https://www.mdpi.com/2075-4701/15/9/1057 diff --git a/docs/algorithms/mo_bmwr_family.md b/docs/algorithms/mo_bmwr_family.md new file mode 100644 index 0000000..1610eb6 --- /dev/null +++ b/docs/algorithms/mo_bmwr_family.md @@ -0,0 +1,41 @@ +# MO-BMR / MO-BWR / MO-BMWR + +Multi-objective extensions of the BMR/BWR/BMWR family (Rao 2025/2026). Wraps the per-variable single-objective base updates with five MOO features: + +1. **Elite seeding** — best solutions of rank 0 used as the "best" reference; rank-N solutions as "worst". +2. **Fast non-dominated sorting** (Deb et al. 2002) — O(M·c²) ranking. +3. **Constraint repairing** — bound-clipping first, then quadratic penalty fallback for inequality/equality violations. +4. **Local exploration** — per iteration, ~10% of the population is replaced by Gaussian-perturbed elites (σ = 5% of bound range). +5. **Edge boosting** — with probability `edge_boost_prob` per iteration, perturb the extreme solutions of each objective to extend the Pareto front. + +Total complexity per iteration: `O(M·c² + c·(m + tf + tp))` where `M` = number of objectives, `c` = population size, `m` = variables, `tf` = objective evaluation cost, `tp` = penalty evaluation cost. + +## Python usage + +```python +from rao_algorithms import samyama_optimization as rust_opt +import numpy as np + +def objs(x): + return np.array([x[0], (1 + 9*np.sum(x[1:])/(len(x)-1)) * (1 - np.sqrt(x[0] / (1 + 9*np.sum(x[1:])/(len(x)-1))))]) + +lower = np.zeros(30) +upper = np.ones(30) +result = rust_opt.solve_mo_bmwr(objs, lower, upper, 50, 100) # population, iterations +for ind in result.pareto_front: + print(ind.variables, ind.fitness, ind.rank, ind.crowding_distance) +``` + +`solve_mo_bmr`, `solve_mo_bwr`, `solve_mo_bmwr` all share the same signature. + +## Variant choice + +- **MO-BMR** — favors exploitation of the best solutions; smoother fronts on convex problems. +- **MO-BWR** — favors exploration via worst-repulsion; better on disconnected/discontinuous fronts (ZDT3-style). +- **MO-BMWR** — balanced, recommended default. Mirrors the JMMP 2025 paper's recommended choice for manufacturing problems. + +## References + +- Rao, R. V. (2025). *Optimization of Different Metal Casting Processes...*. Metals 15(9), 1057. https://www.mdpi.com/2075-4701/15/9/1057 +- Rao, R. V. (2026). MDPI Energies 19(1), 34. +- Rao, R. V. (2025). *Single, Multi-, and Many-Objective Optimization of Manufacturing Processes Using Two Novel and Efficient Algorithms with Integrated Decision-Making*. JMMP 9(8), 249. https://www.mdpi.com/2504-4494/9/8/249 diff --git a/docs/references/rao_publications.md b/docs/references/rao_publications.md index 4672df3..57ead28 100644 --- a/docs/references/rao_publications.md +++ b/docs/references/rao_publications.md @@ -99,3 +99,18 @@ His algorithms are particularly notable for being: Prof. Rao's research has received significant attention in the scientific community. His papers on optimization algorithms have been cited thousands of times, demonstrating the impact and usefulness of his contributions to the field. For the most up-to-date list of publications and citation metrics, please refer to [Prof. Rao's Google Scholar profile](https://scholar.google.com/citations?user=4NoqGCEAAAAJ). + +## 2025–2026 additions (MO family) + +- Rao, R. V. (2025). *Optimization of Different Metal Casting Processes Using Three Simple and Efficient Advanced Algorithms*. **MDPI Metals 15(9), 1057.** Introduces **BMWR** (best–mean–worst–random) and the multi-objective **MO-BMR / MO-BWR / MO-BMWR** with case studies on lost-foam, die-, low-pressure, and squeeze-casting. https://www.mdpi.com/2075-4701/15/9/1057 +- Rao, R. V. (2026). **MDPI Energies 19(1), 34.** Multi-objective MO-* application to energy systems. https://www.mdpi.com/1996-1073/19/1/34 +- Rao, R. V. (2025). *Single, Multi-, and Many-Objective Optimization of Manufacturing Processes Using Two Novel and Efficient Algorithms with Integrated Decision-Making*. **MDPI JMMP 9(8), 249.** Contains the MO-* "Algorithm 2" pseudocode (elite seeding + FNDS + constraint repair + local exploration + edge boosting). https://www.mdpi.com/2504-4494/9/8/249 +- Sample Python codes (BWR, BMR, BMWR, MO-BWR, MO-BMR, MO-BMWR): https://sites.google.com/d/1qNsqo0kHkQD9Bhi4-prZlxo5K7QuntgI/p/1OeRlPp5dhwkqfeNvLP4CtHqFhwk74DqB/edit + +## Related self-adaptive / hybrid variants implemented + +- **SAMP-Jaya** — Rao, R. V., & Saroj, A. (2017). *A self-adaptive multi-population based Jaya algorithm for engineering optimization.* Swarm and Evolutionary Computation 37, 1–26. +- **SAPHR** — *A Self-Adaptive Population-Based Hybrid Optimisation Technique for Multireservoir Benchmark Problems* (2025). Water Resources Management. doi:10.1007/s11269-025-04186-7 +- **EHR-Jaya** — Wang, Z. et al. (2022). *Self-adaptive classification learning hybrid JAYA and Rao-1 algorithm for large-scale numerical and engineering problems.* Engineering Applications of AI. +- **QO-Rao** — Rao, R. V., & Saroj, A. (2020). *Quasi-oppositional-based Rao algorithms for multi-objective design optimization of selected heat sinks.* JCDE 7(6), 830. +- **MO-Rao+DE** — *An efficient multi-objective algorithm based on Rao and differential evolution for solving bi-objective truss optimization* (2025). Engineering Optimization. doi:10.1080/0305215X.2025.2463976 diff --git a/pyproject.toml b/pyproject.toml index dd6bf8a..741deec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,8 +4,8 @@ build-backend = "maturin" [project] name = "rao-algorithms" -version = "0.9.3" -description = "High-performance optimization algorithms by Prof. R.V. Rao (Jaya, Rao, TLBO) backed by Rust" +version = "0.10.0" +description = "High-performance metaphor-free optimization algorithms by Prof. R.V. Rao (Jaya, Rao-1/2/3, TLBO, BMR, BWR, BMWR, QOJaya, ITLBO, GOTLBO, SAMP-Jaya, EHR-Jaya, QO-Rao, SAPHR, MO-BMR/BWR/BMWR, MO-Rao+DE, NSGA-II) backed by Rust" authors = [ { name = "Sandeep Kunkunuru", email = "sandeep.kunkunuru@gmail.com" } ] diff --git a/rao_algorithms/__init__.py b/rao_algorithms/__init__.py index c0a1083..7c02038 100644 --- a/rao_algorithms/__init__.py +++ b/rao_algorithms/__init__.py @@ -13,7 +13,11 @@ ITLBO_algorithm, MultiObjective_TLBO_algorithm, PSO_algorithm, - DE_algorithm + DE_algorithm, + BMWR_algorithm, + SAMP_Jaya_algorithm, + EHRJaya_algorithm, + QO_Rao_algorithm ) from .optimization import run_optimization, save_convergence_curve, save_convergence_history from .objective_functions import ( @@ -45,6 +49,10 @@ 'MultiObjective_TLBO_algorithm', 'PSO_algorithm', 'DE_algorithm', + 'BMWR_algorithm', + 'SAMP_Jaya_algorithm', + 'EHRJaya_algorithm', + 'QO_Rao_algorithm', 'run_optimization', 'save_convergence_curve', 'save_convergence_history', diff --git a/rao_algorithms/algorithms.py b/rao_algorithms/algorithms.py index d9bf3f6..1a665b4 100644 --- a/rao_algorithms/algorithms.py +++ b/rao_algorithms/algorithms.py @@ -136,3 +136,29 @@ def DE_algorithm(bounds, num_iterations, population_size, num_variables, objecti if RUST_AVAILABLE: return _run_rust_solver(rust_opt.solve_de, bounds, num_iterations, population_size, objective_func, constraints, track_history=track_history) raise NotImplementedError("Rust backend required") + +# --- New algorithms (Rao 2025 + self-adaptive variants) --- + +def BMWR_algorithm(bounds, num_iterations, population_size, num_variables, objective_func, constraints=None, track_history=True): + """Best-Mean-Worst-Random (Rao 2025, MDPI Metals 15/9/1057). Combines BMR + BWR terms.""" + if RUST_AVAILABLE: + return _run_rust_solver(rust_opt.solve_bmwr, bounds, num_iterations, population_size, objective_func, constraints, track_history=track_history) + raise NotImplementedError("Rust backend required") + +def SAMP_Jaya_algorithm(bounds, num_iterations, population_size, num_variables, objective_func, constraints=None, track_history=True): + """Self-Adaptive Multi-Population Jaya (Rao & Saroj 2017).""" + if RUST_AVAILABLE: + return _run_rust_solver(rust_opt.solve_samp_jaya, bounds, num_iterations, population_size, objective_func, constraints, track_history=track_history) + raise NotImplementedError("Rust backend required") + +def EHRJaya_algorithm(bounds, num_iterations, population_size, num_variables, objective_func, constraints=None, track_history=True): + """Hybrid Jaya + Rao-1 with classification-based update (Wang et al. 2022, EAAI).""" + if RUST_AVAILABLE: + return _run_rust_solver(rust_opt.solve_ehrjaya, bounds, num_iterations, population_size, objective_func, constraints, track_history=track_history) + raise NotImplementedError("Rust backend required") + +def QO_Rao_algorithm(bounds, num_iterations, population_size, num_variables, objective_func, constraints=None, variant="Rao1", track_history=True): + """Quasi-Oppositional Rao (Rao & Saroj 2020, JCDE). variant ∈ {Rao1, Rao2, Rao3}.""" + if RUST_AVAILABLE: + return _run_rust_solver(rust_opt.solve_qo_rao, bounds, num_iterations, population_size, objective_func, constraints, variant=variant, track_history=track_history) + raise NotImplementedError("Rust backend required") diff --git a/rust_bindings/Cargo.toml b/rust_bindings/Cargo.toml index 7150e1d..eca8ecb 100644 --- a/rust_bindings/Cargo.toml +++ b/rust_bindings/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "samyama-optimization-python" -version = "0.9.3" +version = "0.10.0" edition = "2021" authors = ["Sandeep Kunkunuru "] description = "Python bindings for Samyama Optimization Engine" @@ -13,5 +13,7 @@ crate-type = ["cdylib"] [dependencies] pyo3 = { version = "0.23", features = ["extension-module"] } samyama-optimization = { git = "https://github.com/samyama-ai/samyama-graph.git", branch = "main" } +# For local dev against unpublished crate changes, swap to: +# samyama-optimization = { path = "../../samyama-graph/crates/samyama-optimization" } ndarray = "0.15" numpy = "0.23" diff --git a/rust_bindings/src/lib.rs b/rust_bindings/src/lib.rs index 6aa70e9..3d49923 100644 --- a/rust_bindings/src/lib.rs +++ b/rust_bindings/src/lib.rs @@ -2,8 +2,9 @@ use pyo3::prelude::*; use pyo3::types::PyFunction; use ndarray::Array1; use numpy::{IntoPyArray, PyArray1, PyReadonlyArray1}; -use ::samyama_optimization::algorithms::{JayaSolver, RaoSolver, RaoVariant, TLBOSolver, BMRSolver, BWRSolver, QOJayaSolver, ITLBOSolver, PSOSolver, DESolver, GOTLBOSolver}; -use ::samyama_optimization::common::{Problem, SolverConfig}; +use ::samyama_optimization::algorithms::{JayaSolver, RaoSolver, RaoVariant, TLBOSolver, BMRSolver, BWRSolver, QOJayaSolver, ITLBOSolver, PSOSolver, DESolver, GOTLBOSolver, BMWRSolver, SAMPJayaSolver, EHRJayaSolver, QORaoSolver, MOBMWRSolver, MOBMWRVariant, MORaoDESolver, SAPHRSolver}; +use ::samyama_optimization::common::{MultiObjectiveProblem, Problem, SolverConfig}; +use pyo3::types::PyList; /// Wrapper to use a Python function as a Rust Problem struct PyProblem { @@ -269,6 +270,249 @@ fn solve_de( }) } +#[pyfunction] +#[pyo3(signature = (objective, lower, upper, population_size=50, max_iterations=100))] +fn solve_bmwr( + py: Python, + objective: Py, + lower: PyReadonlyArray1, + upper: PyReadonlyArray1, + population_size: usize, + max_iterations: usize, +) -> PyResult { + let lower_arr = lower.as_array().to_owned(); + let upper_arr = upper.as_array().to_owned(); + let problem = PyProblem { objective, dim: lower_arr.len(), lower: lower_arr, upper: upper_arr }; + let solver = BMWRSolver::new(SolverConfig { population_size, max_iterations }); + let result = py.allow_threads(|| solver.solve(&problem)); + Ok(PyOptimizationResult { + best_variables: result.best_variables.into_pyarray(py).to_owned().into(), + best_fitness: result.best_fitness, + history: result.history, + }) +} + +#[pyfunction] +#[pyo3(signature = (objective, lower, upper, population_size=50, max_iterations=100))] +fn solve_samp_jaya( + py: Python, + objective: Py, + lower: PyReadonlyArray1, + upper: PyReadonlyArray1, + population_size: usize, + max_iterations: usize, +) -> PyResult { + let lower_arr = lower.as_array().to_owned(); + let upper_arr = upper.as_array().to_owned(); + let problem = PyProblem { objective, dim: lower_arr.len(), lower: lower_arr, upper: upper_arr }; + let solver = SAMPJayaSolver::new(SolverConfig { population_size, max_iterations }); + let result = py.allow_threads(|| solver.solve(&problem)); + Ok(PyOptimizationResult { + best_variables: result.best_variables.into_pyarray(py).to_owned().into(), + best_fitness: result.best_fitness, + history: result.history, + }) +} + +#[pyfunction] +#[pyo3(signature = (objective, lower, upper, population_size=50, max_iterations=100))] +fn solve_ehrjaya( + py: Python, + objective: Py, + lower: PyReadonlyArray1, + upper: PyReadonlyArray1, + population_size: usize, + max_iterations: usize, +) -> PyResult { + let lower_arr = lower.as_array().to_owned(); + let upper_arr = upper.as_array().to_owned(); + let problem = PyProblem { objective, dim: lower_arr.len(), lower: lower_arr, upper: upper_arr }; + let solver = EHRJayaSolver::new(SolverConfig { population_size, max_iterations }); + let result = py.allow_threads(|| solver.solve(&problem)); + Ok(PyOptimizationResult { + best_variables: result.best_variables.into_pyarray(py).to_owned().into(), + best_fitness: result.best_fitness, + history: result.history, + }) +} + +#[pyfunction] +#[pyo3(signature = (objective, lower, upper, variant="Rao1", population_size=50, max_iterations=100))] +fn solve_qo_rao( + py: Python, + objective: Py, + lower: PyReadonlyArray1, + upper: PyReadonlyArray1, + variant: &str, + population_size: usize, + max_iterations: usize, +) -> PyResult { + let lower_arr = lower.as_array().to_owned(); + let upper_arr = upper.as_array().to_owned(); + let problem = PyProblem { objective, dim: lower_arr.len(), lower: lower_arr, upper: upper_arr }; + let rao_variant = match variant { + "Rao1" => RaoVariant::Rao1, + "Rao2" => RaoVariant::Rao2, + "Rao3" => RaoVariant::Rao3, + _ => return Err(PyErr::new::("Invalid Rao variant")), + }; + let solver = QORaoSolver::new(SolverConfig { population_size, max_iterations }, rao_variant); + let result = py.allow_threads(|| solver.solve(&problem)); + Ok(PyOptimizationResult { + best_variables: result.best_variables.into_pyarray(py).to_owned().into(), + best_fitness: result.best_fitness, + history: result.history, + }) +} + +// --- Multi-objective wrapper --- + +struct PyMOProblem { + objectives: Py, + num_objectives: usize, + dim: usize, + lower: Array1, + upper: Array1, +} + +impl MultiObjectiveProblem for PyMOProblem { + fn objectives(&self, variables: &Array1) -> Vec { + Python::with_gil(|py| { + let py_vars = variables.to_owned().into_pyarray(py); + let result = self + .objectives + .call1(py, (py_vars,)) + .expect("Python multi-objective function failed"); + // Accept list, tuple, or ndarray. + if let Ok(arr) = result.extract::>(py) { + arr + } else { + let arr = result.downcast_bound::>(py) + .expect("MO objective must return list, tuple, or ndarray"); + arr.readonly().as_array().to_vec() + } + }) + } + fn dim(&self) -> usize { self.dim } + fn num_objectives(&self) -> usize { self.num_objectives } + fn bounds(&self) -> (Array1, Array1) { + (self.lower.clone(), self.upper.clone()) + } +} + +#[pyclass] +pub struct PyMultiObjectiveIndividual { + #[pyo3(get)] pub variables: Py>, + #[pyo3(get)] pub fitness: Vec, + #[pyo3(get)] pub constraint_violation: f64, + #[pyo3(get)] pub rank: usize, + #[pyo3(get)] pub crowding_distance: f64, +} + +#[pyclass] +pub struct PyMultiObjectiveResult { + #[pyo3(get)] pub pareto_front: Py, + #[pyo3(get)] pub history: Vec, +} + +fn build_mo_result( + py: Python, + front: Vec<::samyama_optimization::common::MultiObjectiveIndividual>, + history: Vec, +) -> PyResult { + let items: Vec> = front + .into_iter() + .map(|ind| { + Py::new(py, PyMultiObjectiveIndividual { + variables: ind.variables.into_pyarray(py).to_owned().into(), + fitness: ind.fitness, + constraint_violation: ind.constraint_violation, + rank: ind.rank, + crowding_distance: ind.crowding_distance, + }).unwrap() + }) + .collect(); + let list = PyList::new(py, items)?; + Ok(PyMultiObjectiveResult { pareto_front: list.into(), history }) +} + +fn run_mo( + py: Python, + objectives: Py, + num_objectives: usize, + lower: PyReadonlyArray1, + upper: PyReadonlyArray1, + population_size: usize, + max_iterations: usize, + f: F, +) -> PyResult +where + F: FnOnce(&PyMOProblem, SolverConfig) -> ::samyama_optimization::common::MultiObjectiveResult + Send, +{ + let lower_arr = lower.as_array().to_owned(); + let upper_arr = upper.as_array().to_owned(); + let problem = PyMOProblem { + objectives, num_objectives, dim: lower_arr.len(), lower: lower_arr, upper: upper_arr, + }; + let cfg = SolverConfig { population_size, max_iterations }; + let result = f(&problem, cfg); + build_mo_result(py, result.pareto_front, result.history) +} + +#[pyfunction] +#[pyo3(signature = (objectives, lower, upper, population_size=50, max_iterations=100, num_objectives=2))] +fn solve_mo_bmr(py: Python, objectives: Py, lower: PyReadonlyArray1, upper: PyReadonlyArray1, + population_size: usize, max_iterations: usize, num_objectives: usize) -> PyResult { + run_mo(py, objectives, num_objectives, lower, upper, population_size, max_iterations, + |p, cfg| MOBMWRSolver::new(cfg, MOBMWRVariant::MOBMR).solve(p)) +} + +#[pyfunction] +#[pyo3(signature = (objectives, lower, upper, population_size=50, max_iterations=100, num_objectives=2))] +fn solve_mo_bwr(py: Python, objectives: Py, lower: PyReadonlyArray1, upper: PyReadonlyArray1, + population_size: usize, max_iterations: usize, num_objectives: usize) -> PyResult { + run_mo(py, objectives, num_objectives, lower, upper, population_size, max_iterations, + |p, cfg| MOBMWRSolver::new(cfg, MOBMWRVariant::MOBWR).solve(p)) +} + +#[pyfunction] +#[pyo3(signature = (objectives, lower, upper, population_size=50, max_iterations=100, num_objectives=2))] +fn solve_mo_bmwr(py: Python, objectives: Py, lower: PyReadonlyArray1, upper: PyReadonlyArray1, + population_size: usize, max_iterations: usize, num_objectives: usize) -> PyResult { + run_mo(py, objectives, num_objectives, lower, upper, population_size, max_iterations, + |p, cfg| MOBMWRSolver::new(cfg, MOBMWRVariant::MOBMWR).solve(p)) +} + +#[pyfunction] +#[pyo3(signature = (objectives, lower, upper, population_size=50, max_iterations=100, num_objectives=2))] +fn solve_mo_rao_de(py: Python, objectives: Py, lower: PyReadonlyArray1, upper: PyReadonlyArray1, + population_size: usize, max_iterations: usize, num_objectives: usize) -> PyResult { + run_mo(py, objectives, num_objectives, lower, upper, population_size, max_iterations, + |p, cfg| MORaoDESolver::new(cfg).solve(p)) +} + +#[pyfunction] +#[pyo3(signature = (objective, lower, upper, population_size=50, max_iterations=100))] +fn solve_saphr( + py: Python, + objective: Py, + lower: PyReadonlyArray1, + upper: PyReadonlyArray1, + population_size: usize, + max_iterations: usize, +) -> PyResult { + let lower_arr = lower.as_array().to_owned(); + let upper_arr = upper.as_array().to_owned(); + let problem = PyProblem { objective, dim: lower_arr.len(), lower: lower_arr, upper: upper_arr }; + let solver = SAPHRSolver::new(SolverConfig { population_size, max_iterations }); + let result = py.allow_threads(|| solver.solve(&problem)); + Ok(PyOptimizationResult { + best_variables: result.best_variables.into_pyarray(py).to_owned().into(), + best_fitness: result.best_fitness, + history: result.history, + }) +} + #[pyfunction] fn status() -> PyResult { Ok("Samyama Optimization Engine (Rust) is active".to_string()) @@ -287,6 +531,17 @@ fn samyama_optimization(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(solve_gotlbo, m)?)?; m.add_function(wrap_pyfunction!(solve_pso, m)?)?; m.add_function(wrap_pyfunction!(solve_de, m)?)?; + m.add_function(wrap_pyfunction!(solve_bmwr, m)?)?; + m.add_function(wrap_pyfunction!(solve_samp_jaya, m)?)?; + m.add_function(wrap_pyfunction!(solve_ehrjaya, m)?)?; + m.add_function(wrap_pyfunction!(solve_qo_rao, m)?)?; + m.add_class::()?; + m.add_class::()?; + m.add_function(wrap_pyfunction!(solve_mo_bmr, m)?)?; + m.add_function(wrap_pyfunction!(solve_mo_bwr, m)?)?; + m.add_function(wrap_pyfunction!(solve_mo_bmwr, m)?)?; + m.add_function(wrap_pyfunction!(solve_mo_rao_de, m)?)?; + m.add_function(wrap_pyfunction!(solve_saphr, m)?)?; m.add_function(wrap_pyfunction!(status, m)?)?; Ok(()) } \ No newline at end of file From 4e5ae81ed98e95190dd7050f31970456867f6f70 Mon Sep 17 00:00:00 2001 From: Sandeep Kunkunuru Date: Tue, 21 Apr 2026 19:07:35 +0530 Subject: [PATCH 3/3] fix(bindings): import PyArrayMethods trait for readonly() on pyo3 0.23 --- rust_bindings/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust_bindings/src/lib.rs b/rust_bindings/src/lib.rs index 3d49923..b93f313 100644 --- a/rust_bindings/src/lib.rs +++ b/rust_bindings/src/lib.rs @@ -1,7 +1,7 @@ use pyo3::prelude::*; use pyo3::types::PyFunction; use ndarray::Array1; -use numpy::{IntoPyArray, PyArray1, PyReadonlyArray1}; +use numpy::{IntoPyArray, PyArray1, PyArrayMethods, PyReadonlyArray1}; use ::samyama_optimization::algorithms::{JayaSolver, RaoSolver, RaoVariant, TLBOSolver, BMRSolver, BWRSolver, QOJayaSolver, ITLBOSolver, PSOSolver, DESolver, GOTLBOSolver, BMWRSolver, SAMPJayaSolver, EHRJayaSolver, QORaoSolver, MOBMWRSolver, MOBMWRVariant, MORaoDESolver, SAPHRSolver}; use ::samyama_optimization::common::{MultiObjectiveProblem, Problem, SolverConfig}; use pyo3::types::PyList;