diff --git a/README.md b/README.md index b54ba21..a39dbf1 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,26 @@
-Unlike Rastrigin, this Number Partitioning instance has many separate funnels: most of them end in a global optimum (red), and one ends in a worse local sink (blue).
-
### Custom Discrete Problems
-You can define your own discrete problem by subclassing `DiscreteProblem`. For bitstring problems, inherit from `BitstringProblem` instead; it provides `random_solution()`, `local_search()`, `perturb()`, and `solution_id()` out of the box. You only need to implement `evaluate()`.
+You can define your own discrete problem by subclassing `DiscreteProblem`. You can also extend built-in problems - for bitstring problems, extend `BitstringProblem`, which provides `random_solution()`, `local_search()`, `perturb()`, and `solution_id()` out of the box, so you only need to implement `evaluate()`.
## Documentation
-For full documentation, visit: [https://helix-agh.github.io/lonkit](https://helix-agh.github.io/lonkit)
+The full documentation is at [helix-agh.github.io/lonkit](https://helix-agh.github.io/lonkit/):
+
+- [Installation](https://helix-agh.github.io/lonkit/getting-started/installation/)
+- [Quick Start](https://helix-agh.github.io/lonkit/getting-started/quickstart/)
+- [Core Concepts: LONs and fitness landscapes](https://helix-agh.github.io/lonkit/getting-started/concepts/)
+- [Discrete Problems](https://helix-agh.github.io/lonkit/user-guide/discrete/)
+- [API Reference](https://helix-agh.github.io/lonkit/api/)
+
+## References
+
+- G. Ochoa, M. Tomassini, S. Vérel, C. Darabos. *A Study of NK Landscapes' Basins and Local Optima Networks.* GECCO 2008.
+- G. Ochoa, N. Veerapen, F. Daolio, M. Tomassini. *Understanding Phase Transitions with Local Optima Networks: Number Partitioning as a Case Study.* EvoCOP 2017.
+- J. Adair, G. Ochoa, K. M. Malan. *Local Optima Networks for Continuous Fitness Landscapes.* GECCO 2019 Companion.
## Contributing
diff --git a/docs/api/discrete.md b/docs/api/discrete.md
index 367e918..0c319a7 100644
--- a/docs/api/discrete.md
+++ b/docs/api/discrete.md
@@ -1,3 +1,7 @@
+---
+description: "API reference for lonkit discrete optimization: DiscreteProblem, BitstringProblem, NumberPartitioning, NKLandscape, OneMax, and the Iterated Local Search (ILS) sampler."
+---
+
# Discrete Module
## Problems
diff --git a/docs/api/lon.md b/docs/api/lon.md
index 035dde1..255e86e 100644
--- a/docs/api/lon.md
+++ b/docs/api/lon.md
@@ -1,3 +1,7 @@
+---
+description: "API reference for the lonkit LON and CMLON classes: building Local Optima Networks from trace data, computing landscape metrics, and compressing to CMLONs."
+---
+
# LON Module
::: lonkit.lon.LON
diff --git a/docs/api/sampling.md b/docs/api/sampling.md
index 8aa7ccb..292ae62 100644
--- a/docs/api/sampling.md
+++ b/docs/api/sampling.md
@@ -1,3 +1,7 @@
+---
+description: "API reference for lonkit continuous sampling: compute_lon, BasinHoppingSampler, and BasinHoppingSamplerConfig for building Local Optima Networks of continuous functions."
+---
+
# Continuous Sampling Module
::: lonkit.continuous.sampling.compute_lon
diff --git a/docs/api/step_size.md b/docs/api/step_size.md
index f9eaf6d..b552752 100644
--- a/docs/api/step_size.md
+++ b/docs/api/step_size.md
@@ -1,3 +1,7 @@
+---
+description: "API reference for lonkit StepSizeEstimator, which tunes the Basin-Hopping perturbation step size for continuous Local Optima Network sampling."
+---
+
# Step Size Module
::: lonkit.continuous.step_size.StepSizeEstimator
diff --git a/docs/api/visualization.md b/docs/api/visualization.md
index 62fecda..ca5029f 100644
--- a/docs/api/visualization.md
+++ b/docs/api/visualization.md
@@ -1,3 +1,7 @@
+---
+description: "API reference for LONVisualizer: 2D and 3D plots and animated GIFs of Local Optima Networks and CMLONs."
+---
+
# Visualization Module
::: lonkit.visualization.LONVisualizer
diff --git a/docs/contributing.md b/docs/contributing.md
index 5323f17..406c197 100644
--- a/docs/contributing.md
+++ b/docs/contributing.md
@@ -1,3 +1,7 @@
+---
+description: "How to contribute to lonkit, the Python library for Local Optima Networks: development setup, tests, code style, and documentation."
+---
+
# Contributing
Thank you for your interest in contributing to lonkit!
diff --git a/docs/index.md b/docs/index.md
index 4e6ce0b..579ce36 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,12 +1,13 @@
---
+title: Local Optima Networks in Python
description: lonkit - Python library for constructing, analyzing, and visualizing Local Optima Networks (LONs) for continuous and discrete optimization.
---
# lonkit
-**Local Optima Networks**
+**Local Optima Networks in Python**
-{ width="100%" }
+{ width="100%" }
lonkit is a Python library for constructing, analyzing, and visualizing Local Optima Networks (LONs) for both continuous and discrete optimization problems.
diff --git a/docs/overrides/main.html b/docs/overrides/main.html
index 0649b29..dde1a13 100644
--- a/docs/overrides/main.html
+++ b/docs/overrides/main.html
@@ -1,23 +1,52 @@
{% extends "base.html" %} {% block extrahead %}
{{ super() }}
+{% if config.extra.google_site_verification %}
+
+{% endif %}
+{% if page.meta and page.meta.title %}
+ {% set seo_title = page.meta.title ~ " - " ~ config.site_name %}
+{% elif page.title and not page.is_homepage %}
+ {% set seo_title = page.title | striptags ~ " - " ~ config.site_name %}
+{% else %}
+ {% set seo_title = config.site_name %}
+{% endif %}
+{% set seo_description = (page.meta.description if page.meta and page.meta.description else config.site_description) %}
+
+
+
+
+
+
+
+
+
+
+
{% endblock %}
diff --git a/docs/user-guide/discrete.md b/docs/user-guide/discrete.md
index 7885425..c0bf50b 100644
--- a/docs/user-guide/discrete.md
+++ b/docs/user-guide/discrete.md
@@ -1,3 +1,7 @@
+---
+description: "Build Local Optima Networks for discrete optimization problems with Iterated Local Search: Number Partitioning, NK Landscapes, OneMax, and custom bitstring problems."
+---
+
# Discrete Problems
lonkit supports Local Optima Networks for discrete optimization problems using
@@ -229,12 +233,13 @@ config = ILSSamplerConfig(
| `max_iter` | None | Hard limit on total iterations per run. Set to `None` for no limit (must set `n_iter_no_change`) |
| `accept_equal` | True | If `True`, accept moves to equal-fitness optima (greedy with equal acceptance). If `False`, only strictly improving moves |
| `seed` | None | Random seed controlling all search randomness |
-| `n_jobs` | 1 | Concurrent jobs using joblib semantics; `1` runs sequentially, `-1` uses all CPUs |
+| `n_jobs` | 1 | Maximum number of runs executed in parallel; `1` runs sequentially, `-1` uses all CPUs. See [Parallel Execution](sampling.md#parallel-execution) |
At least one of `n_iter_no_change` or `max_iter` must be set.
-See [parallel ILS sampling](sampling.md#discrete-sampling-with-ils) for an example,
-reproducibility guarantees, and progress callback semantics.
+See [parallel ILS sampling](sampling.md#discrete-sampling-with-ils) for an example and
+[Parallel Execution](sampling.md#parallel-execution) for `n_jobs` values, reproducibility
+guarantees, and progress callback semantics.
### Comparison with BasinHoppingSamplerConfig
diff --git a/docs/user-guide/sampling.md b/docs/user-guide/sampling.md
index c1652b8..aa6bf25 100644
--- a/docs/user-guide/sampling.md
+++ b/docs/user-guide/sampling.md
@@ -57,17 +57,7 @@ lon = sampler.sample_to_lon(result)
| `n_iter_no_change` | 250 | Max consecutive non-improving perturbations before stopping each run. At least one of `n_iter_no_change` or `max_iter` must be set. |
| `max_iter` | None | Max total perturbation steps per run. Use together with `n_iter_no_change` or alone. |
| `seed` | None | Random seed for reproducibility |
-| `n_jobs` | 1 | Number of parallel jobs. For interpretation, refer to the [joblib documentation](https://joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html#:~:text=Parameters%3A,int%2C%20default%3DNone). |
-
-**Parallelism and reproducibility:**
-
-- The behaviour of `n_jobs` parameter is in line with the one in [joblib documentation](https://joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html#:~:text=Parameters%3A,int%2C%20default%3DNone), that is:
- - `1` runs sequentially,
- - `-1` uses all available CPUs,
- - `N > 1` uses maximum of `N` processes,
- - `-N` uses maximum of `max(1, cpu_count - N + 1)` processes,
- - `None` is treated as `1`.
-- Setting `seed` guarantees **identical results** regardless of `n_jobs` value — each run receives a deterministic RNG seed derived from `SeedSequence(seed)`
+| `n_jobs` | 1 | Maximum number of runs executed in parallel; `1` runs sequentially, `-1` uses all CPUs. See [Parallel Execution](#parallel-execution). |
**Choosing `n_runs` and stopping criteria:**
@@ -187,7 +177,8 @@ perturbations), the starting point, and the reason for failure.
## Discrete Sampling with ILS
-Independent ILS runs can use multiple processes via `n_jobs`:
+Independent ILS runs can use multiple processes via `n_jobs`, with the same
+semantics as `BasinHoppingSampler` (see [Parallel Execution](#parallel-execution)):
```python
from lonkit import ILSSampler, ILSSamplerConfig, NumberPartitioning
@@ -198,28 +189,55 @@ result = sampler.sample(problem)
lon = sampler.sample_to_lon(result)
```
-`n_jobs` follows joblib semantics, as in `BasinHoppingSampler`: `1` (the default)
-runs sequentially, `-1` uses all available CPUs, and `-2` leaves one CPU unused.
-`None` uses the joblib context setting, or `1` without a context; `0` is invalid.
-When the effective number of jobs is one, ILS runs directly without workers.
-Parallel execution prefers processes. Custom problems must be serializable by
-joblib and must not hold mutable search state. All runs use the supplied problem's
-data; workers do not regenerate instances. For short runs, process startup and
-serialization overhead can outweigh parallelism's benefit. Worker errors propagate
-to the caller.
-
-Each run gets its own RNG from `SeedSequence(seed).spawn(n_runs)` in both modes.
-With a fixed seed and the same problem data, `raw_records` and `trace_df` are
-identical across `n_jobs` values, including run and record order. **Seeded ILS
-results change compared with earlier versions**, which shared one RNG across
-all runs. Custom problems must use the supplied RNG for all search randomness.
-
-`sample(problem, progress_callback=callback)` calls
-`callback(completed_runs, total_runs)` in the main process once after receiving
-each completed run, with counts from `1` through `n_runs`. Results are received
-in run order, so an earlier slow run can delay notifications for later runs.
-This also changes sequential callbacks from before a run to after its completion.
-The `ILSResult` format and `sample_to_lon()` usage remain unchanged.
+When running in parallel, custom problems must be serializable by joblib and must
+not hold mutable search state. All runs use the supplied problem's data; workers
+do not regenerate instances. Custom problems must also use the supplied RNG for
+all search randomness, otherwise results are not reproducible.
+
+**Seeded ILS results change compared with earlier versions**, which shared one
+RNG across all runs. Progress callbacks are now called after each run completes
+rather than before it starts. The `ILSResult` format and `sample_to_lon()` usage
+remain unchanged.
+
+## Parallel Execution
+
+Both samplers run their `n_runs` independent runs in parallel according to the
+`n_jobs` config parameter, which follows
+[joblib semantics](https://joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html):
+
+| `n_jobs` | Behaviour |
+| ------------- | ------------------------------------------------------------------------------------------ |
+| `1` (default) | Runs execute sequentially in the main process, without workers |
+| `N > 1` | Up to `N` worker processes |
+| `-1` | One worker process per CPU |
+| `-N` | Up to `max(1, cpu_count - N + 1)` worker processes, e.g. `-2` leaves one CPU free |
+| `None` | Value from an enclosing `joblib.parallel_config(n_jobs=...)` context, otherwise `1` |
+| `0` | Invalid, raises `ValueError` |
+
+Whenever the effective number of jobs is `1`, runs execute directly in the main
+process. Otherwise joblib worker processes are used, so the objective function
+(or discrete problem) must be serializable by joblib. For short runs, process
+startup and serialization overhead can outweigh the benefit of parallelism.
+Worker errors propagate to the caller. `BasinHoppingSampler` also re-emits
+warnings raised in workers (such as [failed local searches](#failed-local-searches))
+in the main process.
+
+#### Reproducibility
+
+Each run gets its own RNG from
+`SeedSequence(seed).spawn(n_runs)`, whatever the value of `n_jobs`. With a fixed
+`seed`, the resulting `trace_df` and LON are identical across `n_jobs` values.
+
+#### Ordering and progress callbacks
+
+`progress_callback(completed_runs, total_runs)`
+is always called in the main process, once per completed run, with counts from `1`
+through `n_runs`. The two samplers differ in how parallel results are collected:
+
+| Sampler | Results collected | `raw_records` order across `n_jobs` | Callback timing |
+| --------------------- | --------------------- | ----------------------------------- | --------------------------------------------------- |
+| `BasinHoppingSampler` | As runs finish | May differ (`trace_df` is sorted) | As soon as any run finishes |
+| `ILSSampler` | In run order | Identical | In run order; a slow early run delays later updates |
## LON Construction Configuration
diff --git a/mkdocs.yml b/mkdocs.yml
index 6704b5d..d466144 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -1,5 +1,5 @@
site_name: lonkit
-site_description: Local Optima Networks for Continuous Optimization
+site_description: lonkit is a Python library for constructing, analyzing, and visualizing Local Optima Networks (LONs) for continuous and discrete optimization and fitness landscape analysis.
site_author: HELIX AGH
site_url: https://helix-agh.github.io/lonkit
@@ -85,19 +85,25 @@ nav:
- Sampling: user-guide/sampling.md
- Analysis: user-guide/analysis.md
- Visualization: user-guide/visualization.md
+ - Discrete Problems: user-guide/discrete.md
- Examples: user-guide/examples.md
- API Reference:
- Overview: api/index.md
- LON: api/lon.md
- Sampling: api/sampling.md
+ - Step Size: api/step_size.md
+ - Discrete: api/discrete.md
- Visualization: api/visualization.md
- Contributing: contributing.md
extra:
+ # Google Search Console verification token (HTML tag method), e.g. "abc123...".
+ # Rendered as when set.
+ google_site_verification: ""
social:
- icon: fontawesome/brands/github
link: https://github.com/helix-agh/lonkit
- icon: fontawesome/brands/python
link: https://pypi.org/project/lonkit/
-copyright: Copyright © 2025 AGH University of Kraków
+copyright: Copyright © 2025-2026 AGH University of Kraków
diff --git a/src/lonkit/continuous/sampling.py b/src/lonkit/continuous/sampling.py
index ec828b4..0f8f627 100644
--- a/src/lonkit/continuous/sampling.py
+++ b/src/lonkit/continuous/sampling.py
@@ -52,7 +52,7 @@ class BasinHoppingSamplerConfig:
Reproducibility is guaranteed across different ``n_jobs`` values when ``seed`` is set. Default: ``1``.
preserve_runs_without_transitions: Keep runs with no accepted moves as
self-loop trace rows. If False, omit them from the trace, LON, and
- performance metrics, matching the earlier behavior. Default: True.
+ performance metrics. Default: True.
A local search fails if ``minimize`` raises ``ValueError`` or returns a non-finite
``fun``. A failed initial search skips the run; a failed perturbation is rejected
diff --git a/src/lonkit/discrete/sampling.py b/src/lonkit/discrete/sampling.py
index ff4f51b..2895004 100644
--- a/src/lonkit/discrete/sampling.py
+++ b/src/lonkit/discrete/sampling.py
@@ -39,7 +39,7 @@ class ILSSamplerConfig:
a context. 0 is invalid. Processes are preferred. Default: 1.
preserve_runs_without_transitions: Keep runs with no accepted moves as
self-loop trace rows. If False, omit them from the trace, LON, and
- performance metrics, matching the earlier behavior. Default: True.
+ performance metrics. Default: True.
"""
n_runs: int = 100