Remove legacy continuous optimizer

This commit is contained in:
Meta Vens 2026-04-24 00:03:05 +01:00
commit 0808271d05
19 changed files with 360 additions and 3434 deletions

View file

@ -3,7 +3,7 @@ from __future__ import annotations
import numpy as np
from .metrics import luminance
from .types import ContinuousSourceAnalysis, TileGraphSourceAnalysis
from .types import PhaseFieldSourceAnalysis, TileGraphSourceAnalysis
def _require_torch():
@ -55,23 +55,23 @@ def _compute_edge_map_torch(torch, rgba_t):
return edge.to(dtype=torch.float32)
def analyze_continuous_source(
def analyze_phase_field_source(
rgba: np.ndarray,
seed: int,
device: str | None = None,
) -> ContinuousSourceAnalysis:
) -> PhaseFieldSourceAnalysis:
del seed
if device is not None:
torch = _require_torch()
resolved_device = _resolve_device(torch, device)
rgba_t = torch.from_numpy(rgba).to(device=resolved_device, dtype=torch.float32)
edge_map_t = _compute_edge_map_torch(torch, rgba_t)
return ContinuousSourceAnalysis(
return PhaseFieldSourceAnalysis(
edge_map=edge_map_t.detach().cpu().numpy().astype(np.float32),
)
edge_map = _compute_edge_map(rgba)
return ContinuousSourceAnalysis(
return PhaseFieldSourceAnalysis(
edge_map=edge_map,
)

View file

@ -35,8 +35,8 @@ def build_parser() -> argparse.ArgumentParser:
target.add_argument("--device", default="auto", choices=("auto", "cpu", "cuda"), help="Torch device")
target.add_argument(
"--reconstruction-mode",
default="continuous",
choices=("continuous", "phase-field", "tile-graph"),
default="phase-field",
choices=("phase-field", "tile-graph"),
help="Reconstruction engine to run after lattice estimation",
)
target.add_argument(

View file

@ -70,7 +70,7 @@ def run_compare(
steps: int = 200,
device: str = "auto",
strip_background: bool = False,
reconstruction_mode: str = "continuous",
reconstruction_mode: str = "phase-field",
enable_phase_rerank: bool = True,
) -> dict[str, Any]:
diagnostics_path = Path(diagnostics_dir) if diagnostics_dir else Path(output_path).with_suffix("")

File diff suppressed because it is too large Load diff

View file

@ -18,59 +18,7 @@ class SolverHyperParams:
phase_field_magnitude_weight: float = 0.08
phase_field_learning_rate: float = 0.10
phase_field_max_displacement_ratio: float = 0.48
representative_softmax_scale: float = 18.0
source_edge_reliability_gain: float = 1.6
source_edge_reliability_floor: float = 0.25
source_edge_alpha_floor: float = 0.45
source_edge_detail_mix: float = 0.65
source_edge_detail_threshold: float = 0.25
boundary_probe_scale: float = 0.22
boundary_signed_weight: float = 0.55
boundary_direction_weight: float = 0.30
boundary_magnitude_weight: float = 0.15
snap_base_match_weight: float = 0.65
snap_representative_match_weight: float = 0.15
snap_source_match_weight: float = 0.85
snap_neighbor_weight: float = 0.35
snap_diagonal_weight: float = 0.14
snap_representative_delta_weight: float = 0.20
snap_source_delta_weight: float = 0.80
refine_anchor_weight: float = 0.60
refine_source_weight: float = 0.20
refine_alpha_weight: float = 0.10
refine_distance_weight: float = 0.10
refine_source_delta_weight: float = 0.25
refine_orthogonal_weight: float = 0.24
refine_diagonal_weight: float = 0.08
refine_motif_weight: float = 0.12
refine_line_weight: float = 0.10
refine_candidate_extent: float = 0.70
refine_candidate_levels: int = 7
guided_candidate_edge_threshold: float = 0.06
guided_candidate_inner_scale: float = 0.32
guided_candidate_outer_scale: float = 0.60
relax_iterations: int = 24
relax_start_temperature: float = 0.95
relax_end_temperature: float = 0.18
relax_damping: float = 0.10
relax_anchor_scale: float = 0.50
relax_orthogonal_weight: float = 0.34
relax_diagonal_weight: float = 0.12
relax_source_adjacency_weight: float = 0.35
relax_motif_weight: float = 0.22
relax_line_weight: float = 0.06
relax_source_motif_weight: float = 0.30
relax_source_line_weight: float = 0.12
relax_handoff_weight: float = 0.18
structure_boundary_weight: float = 0.60
structure_anchor_adjacency_weight: float = 0.15
structure_anchor_motif_weight: float = 0.20
structure_anchor_line_weight: float = 0.10
structure_source_adjacency_weight: float = 0.35
structure_source_motif_weight: float = 0.40
structure_source_line_weight: float = 0.20
alpha_foreground_threshold: float = 0.50
alpha_representative_foreground_threshold: float = 0.60
alpha_opaque_threshold: float = 0.95
alpha_transparent_threshold: float = 0.05
phase_rerank_support_weight: float = 0.45

View file

@ -5,7 +5,7 @@ from dataclasses import dataclass
import numpy as np
from .io import premultiply
from .types import ContinuousSourceAnalysis, InferenceResult, SolverArtifacts
from .types import InferenceResult, PhaseFieldSourceAnalysis, SolverArtifacts
from .params import SolverHyperParams
@ -222,7 +222,7 @@ def _prepare_phase_field(
F,
rgba: np.ndarray,
inference: InferenceResult,
analysis: ContinuousSourceAnalysis,
analysis: PhaseFieldSourceAnalysis,
solver_params: SolverHyperParams,
*,
device: str,
@ -379,7 +379,7 @@ def _nearest_source_rgba(source_rgba: np.ndarray, sample_x: np.ndarray, sample_y
def optimize_phase_field(
rgba: np.ndarray,
inference: InferenceResult,
analysis: ContinuousSourceAnalysis,
analysis: PhaseFieldSourceAnalysis,
steps: int,
seed: int,
device: str,

View file

@ -6,8 +6,7 @@ from typing import Any
import numpy as np
from .analysis import analyze_continuous_source, analyze_tile_graph_source
from .continuous import optimize_lattice_pixels
from .analysis import analyze_phase_field_source, analyze_tile_graph_source
from .diagnostics import (
summarize_run,
write_alpha_preview,
@ -31,7 +30,7 @@ from .phase_field import optimize_phase_field
from .palette import load_palette, quantize_rgba, save_palette_report
from .preprocess import strip_edge_background
from .tile_graph import optimize_tile_graph
from .types import ContinuousSourceAnalysis, InferenceResult, RunResult, TileGraphSourceAnalysis
from .types import InferenceResult, PhaseFieldSourceAnalysis, RunResult, TileGraphSourceAnalysis
def run_pipeline(
@ -51,7 +50,7 @@ def run_pipeline(
device: str = "auto",
solver_params: SolverHyperParams | None = None,
strip_background: bool = False,
reconstruction_mode: str = "continuous",
reconstruction_mode: str = "phase-field",
enable_phase_rerank: bool = True,
) -> RunResult:
started = time.perf_counter()
@ -191,10 +190,10 @@ def _prepare_analysis(
seed: int,
device: str,
reconstruction_mode: str,
) -> ContinuousSourceAnalysis | TileGraphSourceAnalysis:
) -> PhaseFieldSourceAnalysis | TileGraphSourceAnalysis:
if reconstruction_mode == "tile-graph":
return analyze_tile_graph_source(source, device=device)
return analyze_continuous_source(source, seed=seed)
return analyze_phase_field_source(source, seed=seed, device=device)
def _select_phase_candidate(
@ -205,7 +204,7 @@ def _select_phase_candidate(
seed: int,
device: str,
solver_params: SolverHyperParams | None = None,
reconstruction_mode: str = "continuous",
reconstruction_mode: str = "phase-field",
enable_phase_rerank: bool = True,
) -> InferenceResult:
return _select_phase_candidate_with_reconstruction(
@ -228,13 +227,13 @@ def _select_phase_candidate_with_reconstruction(
seed: int,
device: str,
solver_params: SolverHyperParams | None = None,
reconstruction_mode: str = "continuous",
reconstruction_mode: str = "phase-field",
enable_phase_rerank: bool = True,
) -> InferenceResult:
solver_params = solver_params or SolverHyperParams()
if not enable_phase_rerank:
return inference
if reconstruction_mode != "continuous":
if reconstruction_mode != "phase-field":
return inference
if len(inference.top_candidates) <= 1 or inference.confidence >= solver_params.phase_rerank_confidence_threshold:
return inference
@ -451,20 +450,12 @@ def _run_reconstruction(
device=device,
solver_params=solver_params,
)
phase_field_metrics = getattr(solver, "stage_diagnostics", {}).get("phase_field", {})
return solver, {
"mode": "phase-field",
**{
f"phase_field_{key}": value
for key, value in solver.stage_diagnostics.get("phase_field", {}).items()
for key, value in phase_field_metrics.items()
},
}
solver = optimize_lattice_pixels(
source,
inference=inference,
analysis=analysis,
steps=steps,
seed=seed,
device=device,
solver_params=solver_params,
)
return solver, {"mode": "continuous"}
raise ValueError(f"Unknown reconstruction mode: {reconstruction_mode}")

View file

@ -38,17 +38,6 @@ def _score_summary(summary: dict[str, Any]) -> dict[str, float]:
}
def _normalize_group(values: np.ndarray) -> np.ndarray:
values = np.clip(values.astype(np.float64), 1e-4, None)
return values / np.sum(values)
def _mutate_group(rng: np.random.Generator, values: list[float], scale: float) -> np.ndarray:
base = np.asarray(values, dtype=np.float64)
noise = np.exp(rng.normal(0.0, 0.28 * scale, size=base.shape))
return _normalize_group(base * noise)
def _mutate_positive(
rng: np.random.Generator,
value: float,
@ -75,162 +64,160 @@ def _mutate_linear(
def _mutate_params(base: SolverHyperParams, rng: np.random.Generator, scale: float) -> SolverHyperParams:
refine_group = _mutate_group(
rng,
[
base.refine_anchor_weight,
base.refine_source_weight,
base.refine_alpha_weight,
base.refine_distance_weight,
],
scale,
)
structure_group = _mutate_group(
rng,
[
base.structure_boundary_weight,
base.structure_anchor_adjacency_weight,
base.structure_anchor_motif_weight,
base.structure_anchor_line_weight,
],
scale,
)
return replace(
base,
representative_softmax_scale=_mutate_positive(
phase_field_patch_extent=_mutate_linear(
rng,
base.representative_softmax_scale,
base.phase_field_patch_extent,
scale=scale,
low=8.0,
high=36.0,
),
boundary_probe_scale=_mutate_linear(
rng,
base.boundary_probe_scale,
scale=scale,
sigma=0.03,
low=0.14,
high=0.32,
),
refine_anchor_weight=float(refine_group[0]),
refine_source_weight=float(refine_group[1]),
refine_alpha_weight=float(refine_group[2]),
refine_distance_weight=float(refine_group[3]),
refine_source_delta_weight=_mutate_linear(
rng,
base.refine_source_delta_weight,
scale=scale,
sigma=0.08,
sigma=0.035,
low=0.05,
high=0.45,
),
refine_orthogonal_weight=_mutate_linear(
rng,
base.refine_orthogonal_weight,
scale=scale,
sigma=0.05,
low=0.10,
high=0.40,
),
refine_diagonal_weight=_mutate_linear(
rng,
base.refine_diagonal_weight,
scale=scale,
sigma=0.025,
low=0.02,
high=0.18,
),
refine_motif_weight=_mutate_linear(
rng,
base.refine_motif_weight,
scale=scale,
sigma=0.05,
low=0.02,
high=0.40,
),
refine_line_weight=_mutate_linear(
rng,
base.refine_line_weight,
scale=scale,
sigma=0.04,
low=0.02,
high=0.30,
),
relax_anchor_scale=_mutate_linear(
rng,
base.relax_anchor_scale,
scale=scale,
sigma=0.16,
low=0.15,
high=1.0,
),
relax_orthogonal_weight=_mutate_linear(
rng,
base.relax_orthogonal_weight,
scale=scale,
sigma=0.08,
low=0.10,
high=0.70,
),
relax_diagonal_weight=_mutate_linear(
rng,
base.relax_diagonal_weight,
scale=scale,
sigma=0.05,
low=0.02,
high=0.35,
),
relax_source_adjacency_weight=_mutate_linear(
phase_field_data_coherence_weight=_mutate_positive(
rng,
base.relax_source_adjacency_weight,
base.phase_field_data_coherence_weight,
scale=scale,
sigma=0.10,
low=0.05,
high=0.80,
low=0.15,
high=3.0,
),
relax_source_motif_weight=_mutate_linear(
phase_field_data_edge_weight=_mutate_positive(
rng,
base.relax_source_motif_weight,
base.phase_field_data_edge_weight,
scale=scale,
sigma=0.10,
low=0.05,
high=0.80,
high=2.5,
),
relax_source_line_weight=_mutate_linear(
phase_field_data_center_edge_weight=_mutate_positive(
rng,
base.relax_source_line_weight,
base.phase_field_data_center_edge_weight,
scale=scale,
sigma=0.08,
low=0.02,
low=0.10,
high=3.0,
),
phase_field_spacing_weight=_mutate_positive(
rng,
base.phase_field_spacing_weight,
scale=scale,
low=0.01,
high=1.0,
),
phase_field_smoothness_weight=_mutate_positive(
rng,
base.phase_field_smoothness_weight,
scale=scale,
low=0.01,
high=1.2,
),
phase_field_edge_gate_strength=_mutate_positive(
rng,
base.phase_field_edge_gate_strength,
scale=scale,
low=1.0,
high=30.0,
),
phase_field_collapse_weight=_mutate_positive(
rng,
base.phase_field_collapse_weight,
scale=scale,
low=0.05,
high=4.0,
),
phase_field_min_spacing_ratio=_mutate_linear(
rng,
base.phase_field_min_spacing_ratio,
scale=scale,
sigma=0.05,
low=0.01,
high=0.45,
),
structure_boundary_weight=float(structure_group[0]),
structure_anchor_adjacency_weight=float(structure_group[1]),
structure_anchor_motif_weight=float(structure_group[2]),
structure_anchor_line_weight=float(structure_group[3]),
structure_source_adjacency_weight=_mutate_linear(
phase_field_max_spacing_ratio=_mutate_linear(
rng,
base.structure_source_adjacency_weight,
base.phase_field_max_spacing_ratio,
scale=scale,
sigma=0.12,
low=0.05,
high=0.90,
low=0.8,
high=1.8,
),
structure_source_motif_weight=_mutate_linear(
phase_field_magnitude_weight=_mutate_positive(
rng,
base.structure_source_motif_weight,
base.phase_field_magnitude_weight,
scale=scale,
sigma=0.12,
low=0.05,
high=0.90,
low=0.001,
high=0.5,
),
structure_source_line_weight=_mutate_linear(
phase_field_learning_rate=_mutate_positive(
rng,
base.structure_source_line_weight,
base.phase_field_learning_rate,
scale=scale,
low=0.005,
high=0.5,
),
phase_field_max_displacement_ratio=_mutate_linear(
rng,
base.phase_field_max_displacement_ratio,
scale=scale,
sigma=0.08,
low=0.02,
high=0.50,
low=0.10,
high=1.0,
),
phase_rerank_support_weight=_mutate_positive(
rng,
base.phase_rerank_support_weight,
scale=scale,
low=0.05,
high=1.5,
),
phase_rerank_edge_position_weight=_mutate_positive(
rng,
base.phase_rerank_edge_position_weight,
scale=scale,
low=0.01,
high=1.0,
),
phase_rerank_wobble_weight=_mutate_positive(
rng,
base.phase_rerank_wobble_weight,
scale=scale,
low=0.01,
high=1.0,
),
phase_rerank_edge_concentration_weight=_mutate_positive(
rng,
base.phase_rerank_edge_concentration_weight,
scale=scale,
low=0.01,
high=1.0,
),
phase_rerank_size_penalty_weight=_mutate_positive(
rng,
base.phase_rerank_size_penalty_weight,
scale=scale,
low=0.01,
high=1.0,
),
phase_rerank_inference_penalty_weight=_mutate_positive(
rng,
base.phase_rerank_inference_penalty_weight,
scale=scale,
low=0.0,
high=0.5,
),
phase_rerank_confidence_threshold=_mutate_linear(
rng,
base.phase_rerank_confidence_threshold,
scale=scale,
sigma=0.035,
low=0.0,
high=0.5,
),
phase_rerank_max_size_delta_ratio=_mutate_linear(
rng,
base.phase_rerank_max_size_delta_ratio,
scale=scale,
sigma=0.08,
low=0.05,
high=1.0,
),
phase_rerank_margin=_mutate_linear(
rng,

View file

@ -28,7 +28,7 @@ class InferenceResult:
@dataclass(slots=True)
class ContinuousSourceAnalysis:
class PhaseFieldSourceAnalysis:
edge_map: np.ndarray
@ -37,7 +37,7 @@ class TileGraphSourceAnalysis:
edge_map: np.ndarray
SourceAnalysis = ContinuousSourceAnalysis | TileGraphSourceAnalysis
SourceAnalysis = PhaseFieldSourceAnalysis | TileGraphSourceAnalysis
@dataclass(slots=True)
@ -86,7 +86,7 @@ class RunResult:
source_rgba: np.ndarray
output_rgba: np.ndarray
inference: InferenceResult
analysis: ContinuousSourceAnalysis | TileGraphSourceAnalysis
analysis: PhaseFieldSourceAnalysis | TileGraphSourceAnalysis
solver: SolverArtifacts
cleanup: CleanupArtifacts
palette_result: PaletteResult | None