seeding expansion
also: replace energy output with energy output density
This commit is contained in:
@@ -153,6 +153,35 @@ class Repository:
|
||||
self.conn.commit()
|
||||
return dep
|
||||
|
||||
def replace_entity_dependencies(self, entity_id: int, deps: list[Dependency]) -> None:
|
||||
"""Delete all existing dependencies for an entity and insert new ones."""
|
||||
self.conn.execute("DELETE FROM dependencies WHERE entity_id = ?", (entity_id,))
|
||||
for dep in deps:
|
||||
cur = self.conn.execute(
|
||||
"""INSERT INTO dependencies
|
||||
(entity_id, category, key, value, unit, constraint_type)
|
||||
VALUES (?, ?, ?, ?, ?, ?)""",
|
||||
(entity_id, dep.category, dep.key, dep.value, dep.unit, dep.constraint_type),
|
||||
)
|
||||
dep.id = cur.lastrowid
|
||||
self.conn.commit()
|
||||
|
||||
def get_entity_by_name(self, dimension: str, name: str) -> Entity | None:
|
||||
row = self.conn.execute(
|
||||
"""SELECT e.id, e.name, e.description, d.name as dimension, e.dimension_id
|
||||
FROM entities e JOIN dimensions d ON e.dimension_id = d.id
|
||||
WHERE d.name = ? AND e.name = ?""",
|
||||
(dimension, name),
|
||||
).fetchone()
|
||||
if not row:
|
||||
return None
|
||||
deps = self._load_dependencies(row["id"])
|
||||
return Entity(
|
||||
id=row["id"], name=row["name"], description=row["description"] or "",
|
||||
dimension=row["dimension"], dimension_id=row["dimension_id"],
|
||||
dependencies=deps,
|
||||
)
|
||||
|
||||
def update_dependency(self, dep_id: int, dep: Dependency) -> None:
|
||||
self.conn.execute(
|
||||
"""UPDATE dependencies
|
||||
@@ -772,3 +801,20 @@ class Repository:
|
||||
(combo_id, domain_id),
|
||||
).fetchone()
|
||||
return dict(row) if row else None
|
||||
|
||||
# ── Admin ────────────────────────────────────────────────────
|
||||
|
||||
def clear_all(self) -> None:
|
||||
"""Delete all data from every table in FK-safe order."""
|
||||
self.conn.execute("DELETE FROM pipeline_runs")
|
||||
self.conn.execute("DELETE FROM combination_results")
|
||||
self.conn.execute("DELETE FROM combination_scores")
|
||||
self.conn.execute("DELETE FROM combination_entities")
|
||||
self.conn.execute("DELETE FROM combinations")
|
||||
self.conn.execute("DELETE FROM dependencies")
|
||||
self.conn.execute("DELETE FROM entities")
|
||||
self.conn.execute("DELETE FROM domain_metric_weights")
|
||||
self.conn.execute("DELETE FROM domains")
|
||||
self.conn.execute("DELETE FROM metrics")
|
||||
self.conn.execute("DELETE FROM dimensions")
|
||||
self.conn.commit()
|
||||
|
||||
@@ -41,7 +41,7 @@ class ConstraintResolver:
|
||||
self._check_requires_vs_excludes(all_deps, result)
|
||||
self._check_mutual_exclusion(all_deps, result)
|
||||
self._check_range_incompatibility(all_deps, result)
|
||||
self._check_force_scale(combination, result)
|
||||
self._check_power_density(combination, result)
|
||||
self._check_energy_density(combination, result)
|
||||
self._check_unmet_requirements(all_deps, result)
|
||||
|
||||
@@ -125,34 +125,32 @@ class ConstraintResolver:
|
||||
f"but {max_name} limits {key} <= {max_val}"
|
||||
)
|
||||
|
||||
def _check_force_scale(
|
||||
def _check_power_density(
|
||||
self, combination: Combination, result: ConstraintResult
|
||||
) -> None:
|
||||
"""Rule 4: If power source output << platform requirement → warn/block."""
|
||||
force_provided: list[tuple[str, float]] = []
|
||||
force_required: list[tuple[str, float]] = []
|
||||
"""Rule 4: If power source W/kg << platform required W/kg → warn/block."""
|
||||
density_provided: list[tuple[str, float]] = []
|
||||
density_required: list[tuple[str, float]] = []
|
||||
|
||||
for entity in combination.entities:
|
||||
for dep in entity.dependencies:
|
||||
if dep.key == "force_output_watts" and dep.constraint_type == "provides":
|
||||
force_provided.append((entity.name, float(dep.value)))
|
||||
elif dep.key == "force_required_watts" and dep.constraint_type == "range_min":
|
||||
force_required.append((entity.name, float(dep.value)))
|
||||
if dep.key == "power_density_w_kg" and dep.constraint_type == "provides":
|
||||
density_provided.append((entity.name, float(dep.value)))
|
||||
elif dep.key == "power_density_required_w_kg" and dep.constraint_type == "range_min":
|
||||
density_required.append((entity.name, float(dep.value)))
|
||||
|
||||
for req_name, req_watts in force_required:
|
||||
for prov_name, prov_watts in force_provided:
|
||||
if prov_watts < req_watts * 0.01:
|
||||
# Off by more than 100x — hard block
|
||||
for req_name, req_density in density_required:
|
||||
for prov_name, prov_density in density_provided:
|
||||
if prov_density < req_density * 0.01:
|
||||
result.violations.append(
|
||||
f"{prov_name} provides {prov_watts}W but "
|
||||
f"{req_name} requires {req_watts}W "
|
||||
f"(force deficit > 100x)"
|
||||
f"{prov_name} provides {prov_density} W/kg but "
|
||||
f"{req_name} requires {req_density} W/kg "
|
||||
f"(power density deficit > 100x)"
|
||||
)
|
||||
elif prov_watts < req_watts:
|
||||
# Under-powered but not impossibly so — warn
|
||||
elif prov_density < req_density:
|
||||
result.warnings.append(
|
||||
f"{prov_name} provides {prov_watts}W but "
|
||||
f"{req_name} requires {req_watts}W "
|
||||
f"{prov_name} provides {prov_density} W/kg but "
|
||||
f"{req_name} requires {req_density} W/kg "
|
||||
f"(under-powered)"
|
||||
)
|
||||
|
||||
|
||||
@@ -417,22 +417,25 @@ class Pipeline:
|
||||
"""Simple heuristic estimation from dependency data."""
|
||||
raw: dict[str, float] = {m: 0.0 for m in metric_names}
|
||||
|
||||
# Extract force output from power source
|
||||
force_watts = 0.0
|
||||
# Extract intrinsic properties from entities
|
||||
power_density = 0.0 # W/kg
|
||||
energy_density = 0.0 # Wh/kg
|
||||
mass_kg = 100.0 # default
|
||||
for entity in combo.entities:
|
||||
for dep in entity.dependencies:
|
||||
if dep.key == "force_output_watts" and dep.constraint_type == "provides":
|
||||
force_watts = max(force_watts, float(dep.value))
|
||||
if dep.key == "min_mass_kg" and dep.constraint_type == "range_min":
|
||||
if dep.key == "power_density_w_kg" and dep.constraint_type == "provides":
|
||||
power_density = max(power_density, float(dep.value))
|
||||
if dep.key == "energy_density_wh_kg" and dep.constraint_type == "provides":
|
||||
energy_density = max(energy_density, float(dep.value))
|
||||
if dep.key == "mass_kg" and dep.constraint_type == "range_min":
|
||||
mass_kg = max(mass_kg, float(dep.value))
|
||||
|
||||
# Rough speed estimate: F=ma -> v proportional to power/mass
|
||||
if "speed" in raw and mass_kg > 0:
|
||||
raw["speed"] = min(force_watts / mass_kg * 0.5, 300000)
|
||||
# Rough speed estimate: higher power density → faster
|
||||
if "speed" in raw:
|
||||
raw["speed"] = min(power_density * 0.5, 300000)
|
||||
|
||||
if "cost_efficiency" in raw:
|
||||
raw["cost_efficiency"] = max(0.01, 2.0 - force_watts / 100000)
|
||||
raw["cost_efficiency"] = max(0.01, 2.0 - power_density / 1000)
|
||||
|
||||
if "safety" in raw:
|
||||
raw["safety"] = 0.5
|
||||
@@ -441,9 +444,21 @@ class Pipeline:
|
||||
raw["availability"] = 0.5
|
||||
|
||||
if "range_fuel" in raw:
|
||||
raw["range_fuel"] = min(force_watts * 0.01, 1e10)
|
||||
raw["range_fuel"] = min(energy_density * 10, 1e10)
|
||||
|
||||
if "range_degradation" in raw:
|
||||
raw["range_degradation"] = 365
|
||||
|
||||
if "cargo_capacity" in raw:
|
||||
raw["cargo_capacity"] = mass_kg * 0.5
|
||||
|
||||
if "cargo_capacity_kg" in raw:
|
||||
raw["cargo_capacity_kg"] = mass_kg * 0.3
|
||||
|
||||
if "environmental_impact" in raw:
|
||||
raw["environmental_impact"] = max(0.0, power_density * 0.2)
|
||||
|
||||
if "reliability" in raw:
|
||||
raw["reliability"] = 0.5
|
||||
|
||||
return raw
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user