split actuators from energy storage
This commit is contained in:
@@ -78,9 +78,10 @@ def spaceship():
|
||||
def solar_sail():
|
||||
return Entity(
|
||||
name="Solar Sail",
|
||||
dimension="power_source",
|
||||
dimension="actuator",
|
||||
description="Propulsion via radiation pressure",
|
||||
dependencies=[
|
||||
Dependency("energy", "energy_form", "radiation_pressure", None, "requires"),
|
||||
Dependency("environment", "atmosphere", "vacuum_or_thin", None, "requires"),
|
||||
Dependency("force", "power_density_w_kg", "0.01", "W/kg", "provides"),
|
||||
Dependency("environment", "medium", "space", None, "requires"),
|
||||
@@ -88,13 +89,27 @@ def solar_sail():
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def solar_radiation():
|
||||
return Entity(
|
||||
name="Solar Radiation",
|
||||
dimension="energy_storage",
|
||||
description="Photon flux from a nearby star",
|
||||
dependencies=[
|
||||
Dependency("energy", "energy_form", "radiation_pressure", None, "provides"),
|
||||
Dependency("physical", "mass_kg", "0", "kg", "range_min"),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def human_pedalling():
|
||||
return Entity(
|
||||
name="Human Pedalling",
|
||||
dimension="power_source",
|
||||
dimension="actuator",
|
||||
description="Human-powered via pedalling",
|
||||
dependencies=[
|
||||
Dependency("energy", "energy_form", "biological", None, "requires"),
|
||||
Dependency("force", "power_density_w_kg", "1.5", "W/kg", "provides"),
|
||||
Dependency("physical", "mass_kg", "0", "kg", "range_min"),
|
||||
],
|
||||
@@ -102,14 +117,43 @@ def human_pedalling():
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def nuclear_reactor():
|
||||
def food_calories():
|
||||
return Entity(
|
||||
name="Modular Nuclear Reactor",
|
||||
dimension="power_source",
|
||||
description="Small modular nuclear fission reactor",
|
||||
name="Food/Calories",
|
||||
dimension="energy_storage",
|
||||
description="Metabolic energy from food",
|
||||
dependencies=[
|
||||
Dependency("energy", "energy_form", "biological", None, "provides"),
|
||||
Dependency("physical", "mass_kg", "0", "kg", "range_min"),
|
||||
Dependency("physical", "energy_density_wh_kg", "200", "Wh/kg", "provides"),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def nuclear_thermal_drive():
|
||||
return Entity(
|
||||
name="Nuclear Thermal Drive",
|
||||
dimension="actuator",
|
||||
description="Nuclear fission reactor for thrust",
|
||||
dependencies=[
|
||||
Dependency("energy", "energy_form", "nuclear_thermal", None, "requires"),
|
||||
Dependency("force", "power_density_w_kg", "50", "W/kg", "provides"),
|
||||
Dependency("physical", "mass_kg", "2000", "kg", "range_min"),
|
||||
Dependency("physical", "mass_kg", "1500", "kg", "range_min"),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def nuclear_fuel():
|
||||
return Entity(
|
||||
name="Nuclear Fuel",
|
||||
dimension="energy_storage",
|
||||
description="Enriched uranium fuel rods",
|
||||
dependencies=[
|
||||
Dependency("energy", "energy_form", "nuclear_thermal", None, "provides"),
|
||||
Dependency("physical", "mass_kg", "500", "kg", "range_min"),
|
||||
Dependency("physical", "energy_density_wh_kg", "500000", "Wh/kg", "provides"),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -118,11 +162,12 @@ def nuclear_reactor():
|
||||
def hydrogen_engine():
|
||||
return Entity(
|
||||
name="Hydrogen Combustion Engine",
|
||||
dimension="power_source",
|
||||
description="Hydrogen fuel cell",
|
||||
dimension="actuator",
|
||||
description="Hydrogen combustion engine",
|
||||
dependencies=[
|
||||
Dependency("energy", "energy_form", "chemical_combustible", None, "requires"),
|
||||
Dependency("force", "power_density_w_kg", "1500", "W/kg", "provides"),
|
||||
Dependency("physical", "mass_kg", "30", "kg", "range_min"),
|
||||
Dependency("physical", "mass_kg", "25", "kg", "range_min"),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -131,12 +176,41 @@ def hydrogen_engine():
|
||||
def ice_engine():
|
||||
return Entity(
|
||||
name="Internal Combustion Engine",
|
||||
dimension="power_source",
|
||||
description="Gas-powered engine",
|
||||
dimension="actuator",
|
||||
description="Spark-ignition engine",
|
||||
dependencies=[
|
||||
Dependency("energy", "energy_form", "chemical_combustible", None, "requires"),
|
||||
Dependency("force", "power_density_w_kg", "1000", "W/kg", "provides"),
|
||||
Dependency("environment", "atmosphere", "standard", None, "requires"),
|
||||
Dependency("physical", "mass_kg", "50", "kg", "range_min"),
|
||||
Dependency("physical", "mass_kg", "40", "kg", "range_min"),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def gasoline():
|
||||
return Entity(
|
||||
name="Gasoline",
|
||||
dimension="energy_storage",
|
||||
description="Liquid hydrocarbon fuel",
|
||||
dependencies=[
|
||||
Dependency("energy", "energy_form", "chemical_combustible", None, "provides"),
|
||||
Dependency("physical", "mass_kg", "10", "kg", "range_min"),
|
||||
Dependency("physical", "energy_density_wh_kg", "1500", "Wh/kg", "provides"),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def hydrogen():
|
||||
return Entity(
|
||||
name="Hydrogen",
|
||||
dimension="energy_storage",
|
||||
description="Compressed hydrogen gas",
|
||||
dependencies=[
|
||||
Dependency("energy", "energy_form", "chemical_combustible", None, "provides"),
|
||||
Dependency("physical", "mass_kg", "5", "kg", "range_min"),
|
||||
Dependency("physical", "energy_density_wh_kg", "600", "Wh/kg", "provides"),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ def test_reseed_after_clear_restores_data(seeded_repo):
|
||||
counts = load_transport_seed(repo)
|
||||
assert len(repo.list_entities()) == original_entities
|
||||
assert len(repo.list_domains()) == original_domains
|
||||
assert counts["platforms"] + counts["power_sources"] == original_entities
|
||||
assert counts["platforms"] + counts["actuators"] + counts["energy_storages"] == original_entities
|
||||
|
||||
|
||||
def test_additive_reseed_no_duplicates(seeded_repo):
|
||||
@@ -44,5 +44,5 @@ def test_additive_reseed_no_duplicates(seeded_repo):
|
||||
|
||||
assert len(repo.list_entities()) == before
|
||||
assert counts["platforms"] == 0
|
||||
assert counts["power_sources"] == 0
|
||||
assert counts["actuators"] + counts["energy_storages"] == 0
|
||||
assert counts["domains"] == 0
|
||||
|
||||
@@ -7,20 +7,21 @@ from physcom.models.entity import Entity
|
||||
|
||||
|
||||
def test_generates_cartesian_product(seeded_repo):
|
||||
from physcom.seed.transport_example import PLATFORMS, POWER_SOURCES
|
||||
from physcom.seed.transport_example import PLATFORMS, ACTUATORS, ENERGY_STORAGES
|
||||
|
||||
combos = generate_combinations(seeded_repo, ["platform", "power_source"])
|
||||
expected = len(PLATFORMS) * len(POWER_SOURCES)
|
||||
combos = generate_combinations(seeded_repo, ["platform", "actuator", "energy_storage"])
|
||||
expected = len(PLATFORMS) * len(ACTUATORS) * len(ENERGY_STORAGES)
|
||||
assert len(combos) == expected
|
||||
|
||||
|
||||
def test_each_combo_has_one_per_dimension(seeded_repo):
|
||||
combos = generate_combinations(seeded_repo, ["platform", "power_source"])
|
||||
combos = generate_combinations(seeded_repo, ["platform", "actuator", "energy_storage"])
|
||||
for combo in combos:
|
||||
dims = [e.dimension for e in combo.entities]
|
||||
assert "platform" in dims
|
||||
assert "power_source" in dims
|
||||
assert len(combo.entities) == 2
|
||||
assert "actuator" in dims
|
||||
assert "energy_storage" in dims
|
||||
assert len(combo.entities) == 3
|
||||
|
||||
|
||||
def test_missing_dimension_raises(seeded_repo):
|
||||
|
||||
@@ -5,37 +5,37 @@ from physcom.models.combination import Combination
|
||||
from physcom.models.entity import Entity, Dependency
|
||||
|
||||
|
||||
def test_compatible_ground_combo(bicycle, human_pedalling):
|
||||
"""Bicycle + Human Pedalling should be valid."""
|
||||
def test_compatible_ground_combo(bicycle, human_pedalling, food_calories):
|
||||
"""Bicycle + Human Pedalling + Food/Calories should be valid."""
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[bicycle, human_pedalling])
|
||||
combo = Combination(entities=[bicycle, human_pedalling, food_calories])
|
||||
result = resolver.resolve(combo)
|
||||
assert result.status != "p1_fail", f"Unexpected block: {result.violations}"
|
||||
|
||||
|
||||
def test_solar_sail_blocks_with_walking(walking, solar_sail):
|
||||
def test_solar_sail_blocks_with_walking(walking, solar_sail, solar_radiation):
|
||||
"""Walking (ground) + Solar Sail (space) should be blocked by medium mutex."""
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[walking, solar_sail])
|
||||
combo = Combination(entities=[walking, solar_sail, solar_radiation])
|
||||
result = resolver.resolve(combo)
|
||||
assert result.status == "p1_fail"
|
||||
assert any("mutually exclusive" in v for v in result.violations)
|
||||
|
||||
|
||||
def test_spaceship_compatible_with_solar_sail(spaceship, solar_sail):
|
||||
def test_spaceship_compatible_with_solar_sail(spaceship, solar_sail, solar_radiation):
|
||||
"""Spaceship + Solar Sail both need space/vacuum — should not conflict."""
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[spaceship, solar_sail])
|
||||
combo = Combination(entities=[spaceship, solar_sail, solar_radiation])
|
||||
result = resolver.resolve(combo)
|
||||
# Should not be blocked by atmosphere or medium
|
||||
medium_blocks = [v for v in result.violations if "mutually exclusive" in v]
|
||||
assert len(medium_blocks) == 0
|
||||
|
||||
|
||||
def test_nuclear_reactor_blocks_with_bicycle(bicycle, nuclear_reactor):
|
||||
"""Nuclear reactor min_mass=2000kg vs bicycle max_mass=30kg → range incompatibility."""
|
||||
def test_nuclear_drive_blocks_with_bicycle(bicycle, nuclear_thermal_drive, nuclear_fuel):
|
||||
"""Nuclear drive min_mass=1500kg + fuel min_mass=500kg vs bicycle max_mass=30kg → range incompatibility."""
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[bicycle, nuclear_reactor])
|
||||
combo = Combination(entities=[bicycle, nuclear_thermal_drive, nuclear_fuel])
|
||||
result = resolver.resolve(combo)
|
||||
assert result.status == "p1_fail"
|
||||
assert any("mass" in v.lower() for v in result.violations)
|
||||
@@ -50,7 +50,7 @@ def test_power_density_mismatch_blocks():
|
||||
],
|
||||
)
|
||||
power = Entity(
|
||||
name="TinyPower", dimension="power_source",
|
||||
name="TinyPower", dimension="actuator",
|
||||
dependencies=[
|
||||
Dependency("force", "power_density_w_kg", "0.01", "W/kg", "provides"),
|
||||
],
|
||||
@@ -71,7 +71,7 @@ def test_power_density_under_powered_warning():
|
||||
],
|
||||
)
|
||||
power = Entity(
|
||||
name="WeakPower", dimension="power_source",
|
||||
name="WeakPower", dimension="actuator",
|
||||
dependencies=[
|
||||
Dependency("force", "power_density_w_kg", "50", "W/kg", "provides"),
|
||||
],
|
||||
@@ -91,7 +91,7 @@ def test_requires_vs_excludes():
|
||||
dependencies=[Dependency("environment", "oxygen", "true", None, "requires")],
|
||||
)
|
||||
b = Entity(
|
||||
name="B", dimension="power_source",
|
||||
name="B", dimension="actuator",
|
||||
dependencies=[Dependency("environment", "oxygen", "true", None, "excludes")],
|
||||
)
|
||||
resolver = ConstraintResolver()
|
||||
@@ -101,21 +101,21 @@ def test_requires_vs_excludes():
|
||||
assert any("excludes" in v for v in result.violations)
|
||||
|
||||
|
||||
def test_ice_engine_blocks_with_spaceship(spaceship, ice_engine):
|
||||
def test_ice_engine_blocks_with_spaceship(spaceship, ice_engine, gasoline):
|
||||
"""ICE requires standard atmosphere, spaceship requires vacuum_or_thin → mutex."""
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[spaceship, ice_engine])
|
||||
combo = Combination(entities=[spaceship, ice_engine, gasoline])
|
||||
result = resolver.resolve(combo)
|
||||
assert result.status == "p1_fail"
|
||||
assert any("atmosphere" in v for v in result.violations)
|
||||
|
||||
|
||||
def test_hydrogen_bicycle_valid(bicycle, hydrogen_engine):
|
||||
def test_hydrogen_bicycle_valid(bicycle, hydrogen_engine, hydrogen):
|
||||
"""Hydrogen bike — the README's example of a plausible novel concept."""
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[bicycle, hydrogen_engine])
|
||||
combo = Combination(entities=[bicycle, hydrogen_engine, hydrogen])
|
||||
result = resolver.resolve(combo)
|
||||
# Should pass constraints (mass range is compatible: h2 min 30kg, bike max 30kg)
|
||||
# Should pass constraints (mass range is compatible: h2 engine min 25kg, bike max 30kg)
|
||||
# This is actually a borderline case — let's just verify no hard physics blocks
|
||||
range_blocks = [v for v in result.violations if "mutually exclusive" in v or "atmosphere" in v]
|
||||
assert len(range_blocks) == 0
|
||||
@@ -129,14 +129,14 @@ def test_energy_density_deficit_blocks():
|
||||
Dependency("physical", "energy_density_wh_kg", "2000", "Wh/kg", "range_min"),
|
||||
],
|
||||
)
|
||||
power = Entity(
|
||||
name="Battery", dimension="power_source",
|
||||
storage = Entity(
|
||||
name="Battery", dimension="energy_storage",
|
||||
dependencies=[
|
||||
Dependency("physical", "energy_density_wh_kg", "200", "Wh/kg", "provides"),
|
||||
],
|
||||
)
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[platform, power])
|
||||
combo = Combination(entities=[platform, storage])
|
||||
result = resolver.resolve(combo)
|
||||
assert result.status == "p1_fail"
|
||||
assert any("energy density deficit" in v for v in result.violations)
|
||||
@@ -150,14 +150,14 @@ def test_energy_density_under_density_warning():
|
||||
Dependency("physical", "energy_density_wh_kg", "400", "Wh/kg", "range_min"),
|
||||
],
|
||||
)
|
||||
power = Entity(
|
||||
name="Battery", dimension="power_source",
|
||||
storage = Entity(
|
||||
name="Battery", dimension="energy_storage",
|
||||
dependencies=[
|
||||
Dependency("physical", "energy_density_wh_kg", "200", "Wh/kg", "provides"),
|
||||
],
|
||||
)
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[platform, power])
|
||||
combo = Combination(entities=[platform, storage])
|
||||
result = resolver.resolve(combo)
|
||||
assert result.status != "p1_fail"
|
||||
assert any("under-density" in w for w in result.warnings)
|
||||
@@ -172,14 +172,14 @@ def test_energy_density_no_constraint_if_no_provider():
|
||||
],
|
||||
)
|
||||
# Solar Sail-style: no energy_density_wh_kg declared
|
||||
power = Entity(
|
||||
name="Solar Sail", dimension="power_source",
|
||||
actuator = Entity(
|
||||
name="Solar Sail", dimension="actuator",
|
||||
dependencies=[
|
||||
Dependency("force", "power_density_w_kg", "0.01", "W/kg", "provides"),
|
||||
],
|
||||
)
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[platform, power])
|
||||
combo = Combination(entities=[platform, actuator])
|
||||
result = resolver.resolve(combo)
|
||||
density_violations = [v for v in result.violations if "energy density" in v]
|
||||
assert len(density_violations) == 0
|
||||
|
||||
@@ -13,10 +13,10 @@ def test_pass1_filters_impossible_combos(seeded_repo):
|
||||
scorer = Scorer(domain)
|
||||
pipeline = Pipeline(seeded_repo, resolver, scorer)
|
||||
|
||||
result = pipeline.run(domain, ["platform", "power_source"], passes=[1])
|
||||
result = pipeline.run(domain, ["platform", "actuator", "energy_storage"], passes=[1])
|
||||
|
||||
from physcom.seed.transport_example import PLATFORMS, POWER_SOURCES
|
||||
expected = len(PLATFORMS) * len(POWER_SOURCES)
|
||||
from physcom.seed.transport_example import PLATFORMS, ACTUATORS, ENERGY_STORAGES
|
||||
expected = len(PLATFORMS) * len(ACTUATORS) * len(ENERGY_STORAGES)
|
||||
assert result.total_generated == expected
|
||||
assert result.pass1_failed > 0
|
||||
assert result.pass1_valid + result.pass1_conditional + result.pass1_failed == expected
|
||||
@@ -30,7 +30,7 @@ def test_pass123_produces_scored_results(seeded_repo):
|
||||
pipeline = Pipeline(seeded_repo, resolver, scorer)
|
||||
|
||||
result = pipeline.run(
|
||||
domain, ["platform", "power_source"],
|
||||
domain, ["platform", "actuator", "energy_storage"],
|
||||
score_threshold=0.01, passes=[1, 2, 3, 5],
|
||||
)
|
||||
|
||||
@@ -50,7 +50,7 @@ def test_pass4_with_mock_llm(seeded_repo):
|
||||
pipeline = Pipeline(seeded_repo, resolver, scorer, llm=mock_llm)
|
||||
|
||||
result = pipeline.run(
|
||||
domain, ["platform", "power_source"],
|
||||
domain, ["platform", "actuator", "energy_storage"],
|
||||
score_threshold=0.01, passes=[1, 2, 3, 4, 5],
|
||||
)
|
||||
|
||||
@@ -65,7 +65,7 @@ def test_blocked_combos_not_scored(seeded_repo):
|
||||
pipeline = Pipeline(seeded_repo, resolver, scorer)
|
||||
|
||||
result = pipeline.run(
|
||||
domain, ["platform", "power_source"],
|
||||
domain, ["platform", "actuator", "energy_storage"],
|
||||
score_threshold=0.0, passes=[1, 2, 3, 5],
|
||||
)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ def test_pipeline_run_lifecycle(seeded_repo):
|
||||
"""Pipeline run should transition: pending -> running -> completed."""
|
||||
repo = seeded_repo
|
||||
domain = repo.get_domain("urban_commuting")
|
||||
config = {"passes": [1, 2, 3], "threshold": 0.1, "dimensions": ["platform", "power_source"]}
|
||||
config = {"passes": [1, 2, 3], "threshold": 0.1, "dimensions": ["platform", "actuator", "energy_storage"]}
|
||||
run_id = repo.create_pipeline_run(domain.id, config)
|
||||
|
||||
run = repo.get_pipeline_run(run_id)
|
||||
@@ -19,10 +19,10 @@ def test_pipeline_run_lifecycle(seeded_repo):
|
||||
scorer = Scorer(domain)
|
||||
pipeline = Pipeline(repo, resolver, scorer)
|
||||
|
||||
pipeline.run(domain, ["platform", "power_source"], passes=[1, 2, 3], run_id=run_id)
|
||||
pipeline.run(domain, ["platform", "actuator", "energy_storage"], passes=[1, 2, 3], run_id=run_id)
|
||||
|
||||
from physcom.seed.transport_example import PLATFORMS, POWER_SOURCES
|
||||
expected = len(PLATFORMS) * len(POWER_SOURCES)
|
||||
from physcom.seed.transport_example import PLATFORMS, ACTUATORS, ENERGY_STORAGES
|
||||
expected = len(PLATFORMS) * len(ACTUATORS) * len(ENERGY_STORAGES)
|
||||
|
||||
run = repo.get_pipeline_run(run_id)
|
||||
assert run["status"] == "completed"
|
||||
@@ -35,7 +35,7 @@ def test_pipeline_run_failed(seeded_repo):
|
||||
"""Pipeline run should be marked failed on error."""
|
||||
repo = seeded_repo
|
||||
domain = repo.get_domain("urban_commuting")
|
||||
config = {"passes": [1], "threshold": 0.1, "dimensions": ["platform", "power_source"]}
|
||||
config = {"passes": [1], "threshold": 0.1, "dimensions": ["platform", "actuator", "energy_storage"]}
|
||||
run_id = repo.create_pipeline_run(domain.id, config)
|
||||
|
||||
# Manually mark as failed (simulating what the web route does on exception)
|
||||
@@ -58,7 +58,7 @@ def test_resume_skips_completed_combos(seeded_repo):
|
||||
# First run: passes 1-3
|
||||
run_id_1 = repo.create_pipeline_run(domain.id, {"passes": [1, 2, 3]})
|
||||
result1 = pipeline.run(
|
||||
domain, ["platform", "power_source"],
|
||||
domain, ["platform", "actuator", "energy_storage"],
|
||||
score_threshold=0.01, passes=[1, 2, 3], run_id=run_id_1,
|
||||
)
|
||||
assert result1.pass2_estimated > 0
|
||||
@@ -67,7 +67,7 @@ def test_resume_skips_completed_combos(seeded_repo):
|
||||
# Second run: same passes — should skip all combos (already pass_reached >= 3)
|
||||
run_id_2 = repo.create_pipeline_run(domain.id, {"passes": [1, 2, 3]})
|
||||
result2 = pipeline.run(
|
||||
domain, ["platform", "power_source"],
|
||||
domain, ["platform", "actuator", "energy_storage"],
|
||||
score_threshold=0.01, passes=[1, 2, 3], run_id=run_id_2,
|
||||
)
|
||||
# pass2_estimated still counted (reloaded from DB) but no new estimation work
|
||||
@@ -93,7 +93,7 @@ def test_cancellation_stops_processing(seeded_repo):
|
||||
repo.update_pipeline_run(run_id, status="cancelled")
|
||||
|
||||
result = pipeline.run(
|
||||
domain, ["platform", "power_source"],
|
||||
domain, ["platform", "actuator", "energy_storage"],
|
||||
score_threshold=0.01, passes=[1, 2, 3], run_id=run_id,
|
||||
)
|
||||
|
||||
@@ -115,7 +115,7 @@ def test_status_guard_no_downgrade_reviewed(seeded_repo):
|
||||
|
||||
# Run pipeline to get scored combos
|
||||
result = pipeline.run(
|
||||
domain, ["platform", "power_source"],
|
||||
domain, ["platform", "actuator", "energy_storage"],
|
||||
score_threshold=0.01, passes=[1, 2, 3],
|
||||
)
|
||||
|
||||
@@ -148,7 +148,7 @@ def test_human_notes_preserved_on_rerun(seeded_repo):
|
||||
|
||||
# First run
|
||||
pipeline.run(
|
||||
domain, ["platform", "power_source"],
|
||||
domain, ["platform", "actuator", "energy_storage"],
|
||||
score_threshold=0.01, passes=[1, 2, 3],
|
||||
)
|
||||
|
||||
@@ -177,7 +177,7 @@ def test_human_notes_preserved_on_rerun(seeded_repo):
|
||||
|
||||
# Re-run pipeline
|
||||
pipeline.run(
|
||||
domain, ["platform", "power_source"],
|
||||
domain, ["platform", "actuator", "energy_storage"],
|
||||
score_threshold=0.01, passes=[1, 2, 3],
|
||||
)
|
||||
|
||||
@@ -212,7 +212,7 @@ def test_get_combo_pass_reached(seeded_repo):
|
||||
pipeline = Pipeline(repo, resolver, scorer)
|
||||
|
||||
pipeline.run(
|
||||
domain, ["platform", "power_source"],
|
||||
domain, ["platform", "actuator", "energy_storage"],
|
||||
score_threshold=0.01, passes=[1, 2, 3],
|
||||
)
|
||||
|
||||
@@ -238,7 +238,7 @@ def test_blocked_combos_have_results(seeded_repo):
|
||||
pipeline = Pipeline(repo, resolver, scorer)
|
||||
|
||||
result = pipeline.run(
|
||||
domain, ["platform", "power_source"],
|
||||
domain, ["platform", "actuator", "energy_storage"],
|
||||
score_threshold=0.01, passes=[1, 2, 3],
|
||||
)
|
||||
|
||||
@@ -269,7 +269,7 @@ def test_all_passes_run_and_tracked(seeded_repo):
|
||||
|
||||
run_id = repo.create_pipeline_run(domain.id, {"passes": [1, 2, 3]})
|
||||
result = pipeline.run(
|
||||
domain, ["platform", "power_source"],
|
||||
domain, ["platform", "actuator", "energy_storage"],
|
||||
score_threshold=0.01, passes=[1, 2, 3], run_id=run_id,
|
||||
)
|
||||
|
||||
@@ -289,7 +289,9 @@ def test_save_combination_loads_existing_status(seeded_repo):
|
||||
repo = seeded_repo
|
||||
from physcom.models.combination import Combination
|
||||
|
||||
entities = repo.list_entities(dimension="platform")[:1] + repo.list_entities(dimension="power_source")[:1]
|
||||
entities = (repo.list_entities(dimension="platform")[:1]
|
||||
+ repo.list_entities(dimension="actuator")[:1]
|
||||
+ repo.list_entities(dimension="energy_storage")[:1])
|
||||
combo = Combination(entities=entities)
|
||||
saved = repo.save_combination(combo)
|
||||
assert saved.status == "pending"
|
||||
@@ -316,7 +318,7 @@ def test_p3_fail_below_threshold(seeded_repo):
|
||||
|
||||
# Use a very high threshold so most combos fail pass 3
|
||||
result = pipeline.run(
|
||||
domain, ["platform", "power_source"],
|
||||
domain, ["platform", "actuator", "energy_storage"],
|
||||
score_threshold=0.99, passes=[1, 2, 3],
|
||||
)
|
||||
|
||||
@@ -350,7 +352,7 @@ def test_p4_fail_implausible(seeded_repo):
|
||||
pipeline = Pipeline(repo, resolver, scorer, llm=mock_llm)
|
||||
|
||||
result = pipeline.run(
|
||||
domain, ["platform", "power_source"],
|
||||
domain, ["platform", "actuator", "energy_storage"],
|
||||
score_threshold=0.0, passes=[1, 2, 3, 4],
|
||||
)
|
||||
|
||||
@@ -381,7 +383,7 @@ def test_p4_pass_plausible(seeded_repo):
|
||||
pipeline = Pipeline(repo, resolver, scorer, llm=mock_llm)
|
||||
|
||||
result = pipeline.run(
|
||||
domain, ["platform", "power_source"],
|
||||
domain, ["platform", "actuator", "energy_storage"],
|
||||
score_threshold=0.01, passes=[1, 2, 3, 4],
|
||||
)
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ def test_add_and_get_entity(repo):
|
||||
def test_list_entities_by_dimension(repo):
|
||||
repo.add_entity(Entity(name="A", dimension="platform"))
|
||||
repo.add_entity(Entity(name="B", dimension="platform"))
|
||||
repo.add_entity(Entity(name="C", dimension="power_source"))
|
||||
repo.add_entity(Entity(name="C", dimension="actuator"))
|
||||
|
||||
platforms = repo.list_entities(dimension="platform")
|
||||
assert len(platforms) == 2
|
||||
@@ -65,7 +65,7 @@ def test_add_and_get_domain(repo):
|
||||
|
||||
def test_combination_save_and_dedup(repo):
|
||||
e1 = repo.add_entity(Entity(name="A", dimension="platform"))
|
||||
e2 = repo.add_entity(Entity(name="B", dimension="power_source"))
|
||||
e2 = repo.add_entity(Entity(name="B", dimension="actuator"))
|
||||
|
||||
from physcom.models.combination import Combination
|
||||
combo = Combination(entities=[e1, e2])
|
||||
@@ -79,12 +79,14 @@ def test_combination_save_and_dedup(repo):
|
||||
|
||||
|
||||
def test_seed_loads(seeded_repo):
|
||||
from physcom.seed.transport_example import PLATFORMS, POWER_SOURCES, ALL_DOMAINS
|
||||
from physcom.seed.transport_example import PLATFORMS, ACTUATORS, ENERGY_STORAGES, ALL_DOMAINS
|
||||
|
||||
platforms = seeded_repo.list_entities(dimension="platform")
|
||||
power_sources = seeded_repo.list_entities(dimension="power_source")
|
||||
actuators = seeded_repo.list_entities(dimension="actuator")
|
||||
energy_storages = seeded_repo.list_entities(dimension="energy_storage")
|
||||
assert len(platforms) == len(PLATFORMS)
|
||||
assert len(power_sources) == len(POWER_SOURCES)
|
||||
assert len(actuators) == len(ACTUATORS)
|
||||
assert len(energy_storages) == len(ENERGY_STORAGES)
|
||||
|
||||
domains = seeded_repo.list_domains()
|
||||
assert len(domains) == len(ALL_DOMAINS)
|
||||
|
||||
@@ -71,7 +71,7 @@ class TestScorer:
|
||||
scorer = Scorer(urban_domain)
|
||||
combo = Combination(entities=[
|
||||
Entity(name="Car", dimension="platform"),
|
||||
Entity(name="ICE", dimension="power_source"),
|
||||
Entity(name="ICE", dimension="actuator"),
|
||||
])
|
||||
combo.id = 1
|
||||
raw = {"speed": 60.0, "cost_efficiency": 0.5, "safety": 0.7,
|
||||
|
||||
Reference in New Issue
Block a user