Pillar Nodes (Captured Nodes) — Hard Constraints Fulfilled by Architecture
A CapturedNode (also called a Pillar / PillarNode) models an absolute, non-negotiable constraint: its SLA (OpeningHours / time window) must be met.
This is a crucial point in JOpt:
A Pillar is a hard constraint that is fulfilled by the optimizer’s architecture, not by assigning an extremely high cost/penalty.
In other words:
- Soft constraints are typically enforced by cost (penalty terms in the objective function).
- Hard constraints in JOpt are enforced by design: the algorithm is structured so that these constraints are not violated.
A Pillar is a prime example: normal nodes “flow around” the pillar appointment in the timeline.
Clickable links
Concept documentation
Example implementation
Why this is not “just a high penalty”
Many optimization engines approximate “must-not-violate” requirements by setting a huge penalty in the objective function.
That is not how pillars work in JOpt.
Pillar behavior in plain language
A pillar appointment acts like a fixed anchor in the route timeline:
- The optimizer treats the pillar time window as something that must be satisfied.
- The surrounding schedule is then adapted:
- normal nodes may be reordered,
- normal nodes may be shifted earlier/later,
- normal nodes may be assigned to other resources,
- or (in extreme cases) the optimizer may decide to drop a pillar rather than violate it.
This “nodes flow around the pillar” effect is a direct consequence of JOpt’s architecture for hard constraints, not cost tuning.
What exactly is “hard” about a pillar?
A pillar’s OpeningHours are treated as hard feasibility boundaries:
- arriving outside the pillar time window is not acceptable,
- waiting before the window is allowed (as with normal time windows),
- but the visit must be placed such that the SLA is matched.
This makes pillars suitable for:
- contractual appointment windows,
- compliance deadlines,
- “must happen at this time” commitments.
Conflict handling (what happens when things don’t fit)
The Special Features documentation describes how the optimizer resolves conflicts between a pillar and “normal” nodes. The practical hierarchy is:
- Reorder / shift normal nodes so the pillar SLA is met.
- Let normal nodes violate their constraints if your model allows it (soft constraints/cost-driven).
- Move work to other resources if available, to protect the pillar.
- Remove a pillar (rare / extreme) if there is no feasible schedule that keeps the pillar intact and no alternative resource exists.
That last point is a key differentiator: the system prefers cancellation/removal to violating a captured SLA.
Java implementation: pillar node types
The pillar concept appears as dedicated node classes implementing IPillarNode, such as:
PillarTimeWindowGeoNode— a geo-located pillar node (lat/long + strict opening hours)PillarEventNode— a non-geo pillar node (event-style pillar, strict opening hours)
A pillar can optionally be tied to a mandatory resource:
pillar.attachResource(resource);
When attached:
- the node is not only time-critical,
- it is also constrained to one specific resource.
This is particularly valuable for:
- skills/certifications,
- legal requirements,
- named-person commitments.
What PillarExample demonstrates
The example contains three pillar variants.
1) Geo pillar with mandatory resource
A “Plumbing” task in Cologne has a strict time window (June 5, 10:00–10:50, Europe/Berlin) and is attached to John.
2) Event pillar with mandatory resource
An “Important call” has a strict time window (June 6, 10:30–12:00) and is attached to Jack.
3) Geo pillar without mandatory resource
A “Maintenance job” in Stuttgart has a strict time window (June 4, 13:30–16:00) and 90 minutes duration.
No resource is attached, so the optimizer may select the best-fitting resource while still treating the SLA as hard.
The example also exports the result to:
./PillarExample.kml
How to run
Run the main(String[] args) method of PillarExample.
Behavior highlights:
- The run is started asynchronously (
startRunAsync()). - The example blocks with
get()to prevent premature termination. - The result is printed to stdout.
- A KML file is written for visual inspection.
Recommended modeling guidance
Use pillars when violations are unacceptable
Use pillars for truly contractual requirements:
- “must be serviced within this window”
- “must not be late”
- “must not be moved outside the SLA”
Do not use pillars to “nudge” the solver
If the time window is preferred but not mandatory, model it as a normal node and handle it via:
- soft constraint penalties,
- objective weighting,
- business rules.
That separation keeps your model honest:
- architecture for hard constraints,
- cost function for preferences and trade-offs.
Summary
- CapturedNode = PillarNode: strict SLA matching for OpeningHours (hard constraint).
- Pillars are enforced by optimizer architecture, not by high penalty costs.
- Normal nodes “flow around” pillars; the solver rearranges the schedule to keep pillar SLAs intact.
- Pillars can optionally enforce a mandatory resource via
attachResource(...). - Extreme infeasibility may result in a pillar being removed rather than violated (per Special Features docs).
Load and Save Optimization Snapshots (JSON / JSON.BZ2) — JOpt TourOptimizer (Java)
This document consolidates and explains the load/save patterns demonstrated by the io_03 examples. It is written as a practical reference for building restartable, recoverable, and portable optimization runs.
Read Out an Optimization Result — IOptimizationResult in Practice
This document explains how to extract structured information from a JOpt TourOptimizer run result (IOptimizationResult) and turn it into something useful for: