Skip to content

Sensor Placement Example

Download Notebook


Sensor Placement finds the optimal positioning of sensors on a network to maximize coverage while respecting cost and count constraints. Applications include environmental monitoring, security, and infrastructure inspection.

import getpass
import os

import numpy as np
from dotenv import load_dotenv
from luna_quantum.algorithms import SCIP

from luna_usecases.sensor_placement import (
    SensorPlacementCollection,
    SensorPlacementData,
    SensorPlacementFormulation,
    SensorPlacementInstance,
)

load_dotenv()
if "LUNA_API_KEY" not in os.environ:
    os.environ["LUNA_API_KEY"] = getpass.getpass("Enter your Luna API key: ")

Create Data

Define a 5-node network with placement costs and select 2 sensor locations using from_adjacency_matrix().

adj = np.array(
    [
        [0, 1, 1.5, 0, 0],
        [1, 0, 1, 1.5, 0],
        [1.5, 1, 0, 0, 1],
        [0, 1.5, 0, 0, 1],
        [0, 0, 1, 1, 0],
    ],
    dtype=float,
)
data = SensorPlacementData.from_adjacency_matrix(
    adjacency_matrix=adj,
    node_names=["A", "B", "C", "D", "E"],
    costs=[1.0, 2.0, 1.5, 3.0, 2.5],
    n_sensors=2,
)
print(data.to_string())
Sensor Placement Data:
  Nodes: 5
  Edges: 6
  Sensors to place: 2
  Costs: [1.  2.  1.5 3.  2.5]

Plot Data

Visualize the network graph with nodes and weighted edges.

data.plot()

<Axes: title={'center': 'Sensor Placement — 5 nodes, 6 edges, 2 sensors'}>
png

Create Formulation

Maximize coverage by selecting sensor locations within the allowed count.

formulation = SensorPlacementFormulation()
print(formulation.to_string(data))
Sensor Placement Formulation:
  Nodes: 5
  Edges: 6
  Sensors to place: 2

Decision Variables:
  x[i] in {0,1} for i = 0, ..., 4
  x[i] = 1 if a sensor is placed at node i
  Total: 5 binary variables

Objective:
  maximize sum_{{(i,j) edges}} w[i,j] * (x[i] + x[j] - x[i] * x[j]) - sum_i costs[i] * x[i]

Constraints:
  1. Exact sensor count (1 constraint):
     sum_i x[i] == 2

Create Instance

Combine data and formulation into a solvable instance.

instance = SensorPlacementInstance(data=data, formulation=formulation)
print(instance.to_string())
Data:Sensor Placement Data:
  Nodes: 5
  Edges: 6
  Sensors to place: 2
  Costs: [1.  2.  1.5 3.  2.5]
Formulation:Sensor Placement Formulation:
  Nodes: 5
  Edges: 6
  Sensors to place: 2

Decision Variables:
  x[i] in {0,1} for i = 0, ..., 4
  x[i] = 1 if a sensor is placed at node i
  Total: 5 binary variables

Objective:
  maximize sum_{{(i,j) edges}} w[i,j] * (x[i] + x[j] - x[i] * x[j]) - sum_i costs[i] * x[i]

Constraints:
  1. Exact sensor count (1 constraint):
     sum_i x[i] == 2

Formulate Model

Translate the instance into a mathematical optimization model.

model = instance.formulate()

Solve and Interpret

Solve the model with SCIP and interpret the raw result into a use-case-specific solution.

scip = SCIP()
job = scip.run(model)
sol = job.result()
uc_solution = instance.interpret(sol)
print(uc_solution.to_string())
/Users/maximilianjanetschek/PycharmProjects/luna-usecases/.venv/lib/python3.13/site-packages/rich/live.py:260:
UserWarning: install "ipywidgets" for Jupyter support
  warnings.warn('install "ipywidgets" for Jupyter support')






2026-05-29 11:35:52 INFO     Sleeping for 5.0 seconds. Waiting and checking a function in a loop.




Sensor Placement Solution:
  Sensor nodes: ['B', 'C']
  Coverage value: 6.0
  Total cost: 3.5
  Valid: True

Plot Solution

Visualize the optimal solution.

uc_solution.plot(data)

<Axes: title={'center': 'Sensor Placement — coverage: 6.00, cost: 3.50, valid: True'}>
png

Collections

Generate a benchmark collection of random instances for batch processing.

collection = SensorPlacementCollection.from_random(min_size=5, max_size=7, n_sensors=2, seed=42)
model = collection.instances[0].formulate()
print(model)

Model: sensor_placement<sensor_placement>
Maximize
  -2.2704291542953743 * x_0 * x_1 - 4.068156349659279 * x_0 * x_2
  - 1.0165342455067852 * x_0 * x_4 - 1.7415147268556663 * x_2 * x_3
  - 2.5005040519741306 * x_3 * x_4 + 4.405119749461439 * x_0
  + 1.2004291542953742 * x_1 + 4.969671076514945 * x_2 + 3.152018778829797 * x_3
  + 0.9070382974809159 * x_4
Subject To
  n_sensors: x_0 + x_1 + x_2 + x_3 + x_4 == 2
Binary
  x_0 x_1 x_2 x_3 x_4