Solvers for placing points along chains
Project description
chainsolvers
chainsolvers is a Python library for solving point placement along chains problems — for example, distributing activities along activity chains to feasible locations. It provides pluggable solver routines, together with configurable scorers and selectors, to flexibly evaluate and select candidate solutions.
Quickstart
Use the two-step runner: setup(...) -> RunnerContext and solve(ctx=..., plans_df=...).
import chainsolvers as cs
import pandas as pd
import numpy as np
import logging
logging.basicConfig(level=logging.INFO)
# 1) Candidate locations
# Provide exactly one of: locations_df, locations_dict, or locations_tuple (these are just different ways of representing the same thing)
# df is probably the easiest coming from a csv, geopackage or similar, tuple is the internal format
locations_df = pd.DataFrame([
# minimal columns: id, act_type, x, y
# optional: name, potentials (plural, one per possible activity type at this location, set to 0 if not specified)
{"activities": "work; business; leisure", "id": "1", "x": 15.0, "y": 13.0, "name": "Business Factory"},
{"activities": "leisure", "id": "2", "x": 10.0, "y": 10.0, "potentials": 100000.0, "name": "Central Park"},
{"activities": "education; sports", "id": "3", "x": 10.0, "y": 10.0, "potentials": "5000.0; 60", "name": "Big School"},
])
locations_dict = {
"work": {
"1": {"coordinates": [15.0, 13.0], "name": "Business Factory"},
},
"business": {
"1": {"coordinates": [15.0, 13.0], "name": "Business Factory"},
},
"leisure": {
"1": {"coordinates": [15.0, 13.0], "name": "Business Factory"},
"2": {"coordinates": [10.0, 10.0], "potential": 100000.0, "name": "Central Park"}, # potential, singular
},
"education": {
"3": {"coordinates": [10.0, 10.0], "potential": 5000.0, "name": "Big School"},
},
"sports": {
"3": {"coordinates": [10.0, 10.0], "potential": 60.0, "name": "Big School"},
},
}
locations_tuple = (
{
"work": np.array(["1"], dtype=object),
"business": np.array(["1"], dtype=object),
"leisure": np.array(["1", "2"], dtype=object),
"education": np.array(["3"], dtype=object),
"sports": np.array(["3"], dtype=object),
},
{
"work": np.array([[15.0, 13.0]], dtype=float),
"business": np.array([[15.0, 13.0]], dtype=float),
"leisure": np.array([[15.0, 13.0], [10.0, 10.0]], dtype=float),
"education": np.array([[10.0, 10.0]], dtype=float),
"sports": np.array([[10.0, 10.0]], dtype=float),
},
{
"work": np.array([0], dtype=float),
"business": np.array([0], dtype=float),
"leisure": np.array([0, 100000.0], dtype=float),
"education": np.array([5000.0], dtype=float),
"sports": np.array([60.0], dtype=float),
},
)
# 2) Create a runner context
ctx = cs.setup(
locations_df=locations_df, # or locations_dict= or locations_tuple=...
# --- optional parameters ---
# solver="carla", # defaults to "carla"
# parameters={ # parameters for the solver (uses default values if not specified)
# "number_of_branches": 50,
# "candidates_complex_case": 100,
# "candidates_two_leg_case": 40,
# "anchor_strategy": "lower_middle", # {'lower_middle','upper_middle','start','end'}
# "selection_strategy_complex_case": "top_n_spatial_downsample",
# "selection_strategy_two_leg_case": "top_n",
# "max_iterations_complex_case": 100,
# },
# rng_seed=42, # or pass a numpy Generator
# scorer=CustomScorer(), # uses default scorer if not specified
# selector=CustomSelector() # uses default selector if not specified
# progress=tqdm, # for progress bars, use your own if you want, no progress bars shown if not specified
# visualizer=CustomVisualizer(),
)
# 3) Input plans. Minimum required columns:
# unique_person_id, unique_leg_id, to_act_type, distance_meters, from_x, from_y, to_x, to_y
plans_df = pd.DataFrame([
{"unique_person_id": "p1", "unique_leg_id": "p1-1", "to_act_type": "work", "distance_meters": 5000,
"from_x": 10.0, "from_y": 10.0, "to_x": float("nan"), "to_y": float("nan")},
{"unique_person_id": "p1", "unique_leg_id": "p1-2", "to_act_type": "home", "distance_meters": 4900,
"from_x": float("nan"), "from_y": float("nan"), "to_x": 300.0, "to_y": 350.4},
])
# 4) Solve
result_df, result_plans, valid = cs.solve(ctx=ctx, plans_df=plans_df)
print(valid)
print(result_df)
print(result_plans)
Returns
A tuple of three elements (in order):
result_df:pandas.DataFrame(always returned). Placed plans in same df format as input plans.result_plans:SegmentedPlans(frozendict[str, tuple[Segment, ...]]) orNone. Results in the internalSegmentedPlans(may be useful, else just ignore).valid:bool. Whether the output validation succeeded.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file chainsolvers-0.1.0.tar.gz.
File metadata
- Download URL: chainsolvers-0.1.0.tar.gz
- Upload date:
- Size: 32.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c69621ff4efb3b7fac31a3edab97fb685548644403394e10b8d14cc807520ea7
|
|
| MD5 |
dc2df1706379d8d75d2501d2fd1723bb
|
|
| BLAKE2b-256 |
07bb02114566837b76fe4a4fa277fa1598148b7a7d365aab0762b5c60f0516b1
|
File details
Details for the file chainsolvers-0.1.0-py3-none-any.whl.
File metadata
- Download URL: chainsolvers-0.1.0-py3-none-any.whl
- Upload date:
- Size: 34.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e9e9b3283d4c9d0385db6126db1f66dbfc785467b0261f4786da12fced4bd7e2
|
|
| MD5 |
48fdd942c1ac11322d41b50b63467c89
|
|
| BLAKE2b-256 |
4a7947de9b29e83fc63920f800bab1b4002aa8b4ca11e6e9701e5e3d566f2ceb
|