Void & Cluster Algorithm#
The select_sessions function implements a Void & Cluster sampling algorithm to select capture times that maximize diversity.
Overview#
For captures that depend on lighting, weather, or location conditions, you want to sample times that provide good coverage of the parameter space. The algorithm works on a coverage "energy" field:
- Energy: Convert pairwise distances into coverage energy — candidates close to existing captures (or to slots already selected) have high energy
- Void: Pick the candidate with the lowest energy (the largest gap in coverage) and add it to the selection
- Cluster: Find the selected point with the highest energy — the tightest cluster. If it is the point just added, the set is stable; otherwise release it so a later iteration can re-place it in a better void
Each selection raises the energy around it, pushing later selections into the remaining gaps, and the cluster step lets late selections evict early picks that became crowded.
Basic Usage#
from datetime import timedelta
import capturegraph as cg
import capturegraph.scheduling as cgsh
# 1. Generate candidate time slots
potential = cg.Array()
potential.date = cgsh.forecast.times(span=timedelta(hours=24))
potential.location = location
# 2. Add derived attributes
potential.solar_angle = cgsh.forecast.solar_position(location, potential.date)
# 3. Define distance function
distance_fn = cgsh.distance.combine(
solar_angle=cgsh.distance.solar(sigma_deg=2.0),
)
# 4. Select diverse sessions
selected = cgsh.select_sessions(
potential,
existing_sessions,
distance_fn,
energy_fn=cgsh.energy.gaussian(sigma=1.0),
selections=10,
)
Parameters#
| Parameter | Type | Default | Description |
|---|---|---|---|
potential_sessions |
cg.Array |
— | Candidates to select from |
previous_sessions |
cg.Array |
— | Already-captured sessions |
distance_fn |
Callable |
— | Distance function between sessions |
energy_fn |
Callable |
gaussian(sigma=1) |
Distance-to-energy conversion |
energy_mode |
str |
"sum" |
How to combine energies ("sum" or "max") |
selections |
int |
10 |
Number of sessions to select |
Forecast Utilities#
Generate candidate sessions using the forecast submodule:
from datetime import timedelta
import capturegraph.scheduling as cgsh
# Time slots for the next 24 hours
times = cgsh.forecast.times(span=timedelta(hours=24))
# Specific times of day
times = cgsh.forecast.times_of_day(hours=[8, 12, 17])
# Solar positions
solar = cgsh.forecast.solar_position(location, times)
# Weather forecasts (from Open-Meteo, free API)
weather = cgsh.forecast.hourly_weather(location, days=3)
nearest = cgsh.forecast.nearest_weather(weather, times)
# Location grids from polygon vertices (a cg.Array of cg.Location)
points = cgsh.forecast.locations_area(bounds, resolution_meters=5.0)
outline = cgsh.forecast.locations_perimeter(bounds, resolution_meters=5.0)
Energy Functions#
Convert distances to coverage energy:
import capturegraph.scheduling as cgsh
# Gaussian falloff (default)
energy = cgsh.energy.gaussian(sigma=1.0)
# Regularized inverse distance: 1 / (d + 1/max_energy)
energy = cgsh.energy.inverse(max_energy=10**6)
Note
Both gaussian and
inverse are factories —
call them to obtain the function you pass as energy_fn. Passing
cgsh.energy.inverse without parentheses raises an AttributeError
inside select_sessions.
See Also#
- Reservations — Handing each user a distinct capture time
- Distance Functions — Defining distance metrics