Add parallel Monte Carlo sweep engine writing every run to SQLite
optim/sweep.py: ProcessPoolExecutor workers sample+evaluate genomes in parallel; each result (feasible or not) is pushed through the queue-backed single writer built in Stage 5. Verified with real multiprocessing (not mocks): 12-run sweep across 2 worker processes lands all 12 rows in SQLite with parseable genome/summary JSON, and two independent sweeps with the same seed produce byte-identical results. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
53
tests/test_sweep.py
Normal file
53
tests/test_sweep.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import json
|
||||
|
||||
from gausse.optim.search_space import SearchBounds, genome_from_dict
|
||||
from gausse.optim.sweep import MODEL_VERSION, run_sweep
|
||||
from gausse.storage.database import count_runs, fetch_runs, open_connection
|
||||
|
||||
|
||||
def test_sweep_runs_all_seeds_and_records_everything(tmp_path):
|
||||
db_path = tmp_path / "runs.sqlite3"
|
||||
bounds = SearchBounds(max_stages=2) # маленькое пространство -> быстрый тест
|
||||
|
||||
summary = run_sweep(db_path, n_runs=12, bounds=bounds, n_workers=2, seed=123)
|
||||
|
||||
assert summary["n_runs"] == 12
|
||||
conn = open_connection(db_path)
|
||||
assert count_runs(conn) == 12
|
||||
# хотя бы какие-то честно попали и в успех, и в провал -- иначе тест
|
||||
# пространства слишком узкий/широкий, чтобы быть показательным
|
||||
rows = fetch_runs(conn)
|
||||
assert len(rows) == 12
|
||||
for row in rows:
|
||||
assert row.search_mode == "sweep"
|
||||
assert row.model_version == MODEL_VERSION
|
||||
# genome_json должен быть валидным и декодируемым геномом
|
||||
genome = genome_from_dict(json.loads(row.genome_json))
|
||||
assert len(genome.stages) >= 1
|
||||
summary_dict = json.loads(row.decoded_summary_json)
|
||||
assert "stages" in summary_dict
|
||||
if row.feasible:
|
||||
assert row.efficiency is not None
|
||||
assert row.infeasible_reason is None
|
||||
else:
|
||||
assert row.infeasible_reason is not None
|
||||
assert row.efficiency is None
|
||||
conn.close()
|
||||
|
||||
|
||||
def test_sweep_is_deterministic_given_same_seed(tmp_path):
|
||||
bounds = SearchBounds(max_stages=2)
|
||||
db_path_a = tmp_path / "a.sqlite3"
|
||||
db_path_b = tmp_path / "b.sqlite3"
|
||||
|
||||
run_sweep(db_path_a, n_runs=8, bounds=bounds, n_workers=1, seed=42)
|
||||
run_sweep(db_path_b, n_runs=8, bounds=bounds, n_workers=1, seed=42)
|
||||
|
||||
conn_a = open_connection(db_path_a)
|
||||
conn_b = open_connection(db_path_b)
|
||||
rows_a = sorted(fetch_runs(conn_a), key=lambda r: r.genome_json)
|
||||
rows_b = sorted(fetch_runs(conn_b), key=lambda r: r.genome_json)
|
||||
assert [r.genome_json for r in rows_a] == [r.genome_json for r in rows_b]
|
||||
assert [r.efficiency for r in rows_a] == [r.efficiency for r in rows_b]
|
||||
conn_a.close()
|
||||
conn_b.close()
|
||||
Reference in New Issue
Block a user