Sensor Positioning (SP) API Reference
Data
Data model for the Sensor Positioning (SP) use case.
SppData
Bases: UcData
Materialized coverage representation for Sensor Positioning.
This variant assumes coverage was precomputed (e.g., from geometry)
and stored as a boolean matrix: targets x positions. Fixed-on/off sets
(fixed_on, fixed_off) capture degree-1/dominated preprocessing decisions.
Attributes:
-
name(Literal['sensor_position_problem']) –Identifier.
-
position_ids(list[str]) –Identifiers for candidate sensor placements.
-
target_ids(list[str]) –Identifiers for targets/street points to cover.
-
coverage(NumPyArray) –Boolean matrix shape (n_targets, n_positions): coverage[t, p] is True if position p covers target t.
-
position_costs(NumPyArray) –Length n_positions; cost of activating each position (default 1).
-
min_coverage(list[int]) –Required coverage per target (broadcasted from int if needed).
-
budget(float | None) –Optional cost budget (<= constraint).
-
max_positions(int | None) –Optional cardinality cap.
-
incompatibilities(list[tuple[int, int]]) –Pairwise exclusions between positions.
-
must_select(list[int]) –Positions that must be activated.
-
forbidden(list[int]) –Positions that must stay deactivated.
-
fixed_on(list[int]) –Positions forced to 1 from preprocessing (e.g., degree-1 reductions).
-
fixed_off(list[int]) –Positions forced to 0 from preprocessing (e.g., dominated reductions).
-
uncoverable_targets(list[int] | None) –Target indices that cannot be covered by any candidate sensor.
-
cost_weight(float) –Weight on cost term (default 1.0).
-
proximity_penalty_weight(float) –Optional weight for future pairwise penalties (not used yet).
-
dropped_dominated_positions(NumPyArray | None) –Display-only geometry for dominated dropped lidars.
-
dropped_degree1_positions(NumPyArray | None) –Display-only geometry for degree-1 dropped lidars.
-
dropped_target_positions(NumPyArray | None) –Display-only geometry for targets removed by degree-1 reductions.
-
walls(list[WallLike] | None) –Optional wall geometry as tuples in this order:
(endpoint_a[x, y], endpoint_b[x, y], wall_height, sensor_density, lidar_height, wall_offset, direction_mode, pitch). -
group_ids(list[str | None]) –Optional mutual-exclusion groups (variants) per position; same group means at most one.
-
lidar_params(list[dict] | None) –Per-position coverage overrides (max_radius, half_horizontal_angle, max_vert_angle, min_vert_angle).
-
position_metadata(list[dict] | None) –Display metadata per position (labels, source, groupId, coverage params, variantOf, cost).
to_string() -> str
Summarize core counts and reduction metadata.
to_problem_dict(*, include_metadata: bool = True, include_coverage: bool = False) -> dict[str, Any]
Convert the instance to the enriched problem dictionary format.
save_to_json(path: str | Path, *, include_metadata: bool = True, include_coverage: bool = False) -> Path
Persist the problem dictionary to JSON on disk.
with_coverage(coverage: np.ndarray) -> SppData
Return a new instance with updated coverage while retaining metadata.
plot(*, ax: Axes | None = None, show_walls: bool = True, show_targets: bool = True, show_uncoverable_targets: bool = False, show_dropped_dominated_sensors: bool = True, show_dropped_degree1_sensors: bool = True, show_dropped_targets: bool = True, show_candidate_sensors: bool = True, show_coverage_rays: bool = False, show_sensor_headings: bool = True) -> Axes
Plot the SP problem structure on the provided axes.
Parameters:
-
ax(Axes | None, default:None) –Matplotlib axes to draw on. If
None, a new axes is created. -
show_walls(bool, default:True) –Draw walls and wall polygon.
-
show_targets(bool, default:True) –Draw target points.
-
show_uncoverable_targets(bool, default:False) –Highlight uncoverable targets.
-
show_dropped_dominated_sensors(bool, default:True) –Draw dominated dropped sensors.
-
show_dropped_degree1_sensors(bool, default:True) –Draw degree-1 dropped sensors.
-
show_dropped_targets(bool, default:True) –Draw dropped targets.
-
show_candidate_sensors(bool, default:True) –Draw candidate sensors.
-
show_coverage_rays(bool, default:False) –Draw all coverage rays.
-
show_sensor_headings(bool, default:True) –Draw sensor heading arrows.
Returns:
-
Axes–The axes with the plot.
Raises:
-
InvalidProblemStructureError–If required geometry is missing (
lidar_positionsortarget_positions).
generate_random(n_positions: int = 10, n_targets: int = 20, density: float = 0.2, seed: int | None = None) -> SppData
staticmethod
Create a random SP instance with guaranteed coverable targets.
Formulation
Formulation for the Sensor Positioning (SP) use case.
SppFormulation
Bases: UcFormulation[SppData, SppSolution]
Min-cost set-cover style formulation using materialized coverage.
to_string(data: SppData) -> str
staticmethod
Return a text summary of the formulated model inputs.
formulate(data: SppData) -> Model
staticmethod
Build the mixed-integer model for the SP instance.
interpret(solution: Solution, data: SppData) -> SppSolution
staticmethod
Map solver output back into an SpSolution with coverage metrics.
Solution
Solution model for the Sensor Positioning use case.
SppSolution
Bases: UcSolution
Selected positions and coverage metrics.
to_string() -> str
Return a formatted summary of the solution.
print() -> str
Return the string representation (alias for to_string).
plot(data: SppData | None = None, *, ax: Axes | None = None, show_walls: bool = True, show_targets: bool = True, show_uncoverable_targets: bool = False, show_dropped_dominated_sensors: bool = True, show_dropped_degree1_sensors: bool = True, show_dropped_targets: bool = True, show_candidate_sensors: bool = True, show_selected_sensors: bool = True, show_covered_targets: bool = True, show_uncovered_targets: bool = True, show_coverage_rays_all: bool = False, show_coverage_rays_selected: bool = False, show_sensor_headings: bool = True) -> Axes
Plot the SP solution structure on the provided axes.
Parameters:
-
data(SppData | None, default:None) –Problem data used for geometry and coverage information.
-
ax(Axes | None, default:None) –Matplotlib axes to draw on. If
None, a new axes is created. -
show_walls(bool, default:True) –Draw walls and wall polygon.
-
show_targets(bool, default:True) –Draw target points.
-
show_uncoverable_targets(bool, default:False) –Highlight uncoverable targets.
-
show_dropped_dominated_sensors(bool, default:True) –Draw dominated dropped sensors.
-
show_dropped_degree1_sensors(bool, default:True) –Draw degree-1 dropped sensors.
-
show_dropped_targets(bool, default:True) –Draw dropped targets.
-
show_candidate_sensors(bool, default:True) –Draw non-selected candidate sensors.
-
show_selected_sensors(bool, default:True) –Draw selected sensors.
-
show_covered_targets(bool, default:True) –Draw covered targets.
-
show_uncovered_targets(bool, default:True) –Draw uncovered targets.
-
show_coverage_rays_all(bool, default:False) –Draw all target-to-candidate coverage rays.
-
show_coverage_rays_selected(bool, default:False) –Draw target-to-selected coverage rays.
-
show_sensor_headings(bool, default:True) –Draw sensor heading arrows.
Returns:
-
Axes–The axes with the plot.
Raises:
-
ValueError–If
datais not provided. -
InvalidProblemStructureError–If required geometry is missing on
data. -
DataShapeMismatchError–If
data.coverageshape is inconsistent with geometry.
Instance
Instance model for Sp use case.
SppInstance
Bases: UcInstance[SppData, SppFormulation, SppSolution]
Instance combining data and formulation for Sp.
Collection
Collection of Sp instances.
SppCollection
Bases: UcInstanceCollection[SppInstance]
Lightweight SP collection utilities.
from_random(n_positions: int, n_targets: int, density: float = 0.2, num_instances: int = 1, seed: int | None = None) -> SppCollection
classmethod
Generate a collection of random SP instances.
from_json_file(path: str, *, max_vert_angle: float = 30, min_vert_angle: float = -80, max_radius: float = 2.5, half_horizontal_angle: float = 180, lidar_wall_offset: float = 0.2, min_coverage: int = 1, budget: float | None = None, max_positions: int | None = None, sensor_reduction: Literal['none', 'drop', 'fix'] = 'none', auto_variants: bool = False, auto_variant_specs: list[str] | None = None, auto_variant_group_mode: Literal['by-label', 'per-base-label'] = 'per-base-label', auto_variant_base_group: bool = True, auto_variant_cost_mult: float = 1.0, save_enriched_path: str | Path | None = None, include_metadata: bool = True, include_coverage: bool = True) -> SppCollection
classmethod
Load collection from JSON file.
Args: path: Path to JSON file. max_vert_angle: Maximum vertical viewing angle (degrees). min_vert_angle: Minimum vertical viewing angle (degrees). max_radius: Maximum sensor range. half_horizontal_angle: Half of horizontal field of view (degrees). lidar_wall_offset: Distance from wall endpoints when generating lidars. min_coverage: Required minimum coverage per target. budget: Optional total cost budget. max_positions: Optional cap on selected positions. sensor_reduction: "none" (default), "drop" to remove redundant sensors, "fix" to keep them but mark as fixed on/off.
Returns:
-
SpCollection with one instance from the JSON file.–
from_json_obj(problem_dict: dict[str, Any], *, max_vert_angle: float = 30, min_vert_angle: float = -80, max_radius: float = 2.5, half_horizontal_angle: float = 180, lidar_wall_offset: float = 0.2, min_coverage: int = 1, budget: float | None = None, max_positions: int | None = None, sensor_reduction: Literal['none', 'drop', 'fix'] = 'none', auto_variants: bool = False, auto_variant_specs: list[str] | None = None, auto_variant_group_mode: Literal['by-label', 'per-base-label'] = 'per-base-label', auto_variant_base_group: bool = True, auto_variant_cost_mult: float = 1.0, save_enriched_path: str | Path | None = None, include_metadata: bool = True, include_coverage: bool = True) -> SppCollection
classmethod
Load collection from an in-memory JSON object.
from_json_str(json_string: str, *, max_vert_angle: float = 30, min_vert_angle: float = -80, max_radius: float = 2.5, half_horizontal_angle: float = 180, lidar_wall_offset: float = 0.2, min_coverage: int = 1, budget: float | None = None, max_positions: int | None = None, sensor_reduction: Literal['none', 'drop', 'fix'] = 'none', auto_variants: bool = False, auto_variant_specs: list[str] | None = None, auto_variant_group_mode: Literal['by-label', 'per-base-label'] = 'per-base-label', auto_variant_base_group: bool = True, auto_variant_cost_mult: float = 1.0, save_enriched_path: str | Path | None = None, include_metadata: bool = True, include_coverage: bool = True) -> SppCollection
classmethod
Load collection from JSON string payload.
filter_infeasible(max_runtime: float = 3600, *, quiet: bool = True) -> list[bool]
Drop the instances of this collection that have no feasible solution.
Every instance is formulated and handed to SCIP, which stops as soon as
it finds the first feasible solution. An instance is removed from the
collection when SCIP proves the model infeasible, when no solution turns
up within max_runtime, or when formulating it fails altogether. This
keeps randomly generated instances from breaking a downstream pipeline.
Parameters:
-
max_runtime(float, default:3600) –SCIP time limit per instance in seconds. Must be positive. Defaults to 3600 seconds.
-
quiet(bool, default:True) –Suppress the SCIP solver output.
Returns:
-
list[bool]–Feasibility mask over the instances as they were before filtering, in that order:
Truewhere the instance was kept,Falsewhere it was removed.
Raises:
-
ValueError–If
max_runtimeis not positive.