Skip to content

Commit 8ec20d0

Browse files
committed
core: stdcm: cache engineering allowance sequences
Signed-off-by: Eloi Charpentier <[email protected]>
1 parent 7006371 commit 8ec20d0

File tree

6 files changed

+48
-5
lines changed

6 files changed

+48
-5
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package fr.sncf.osrd.utils
2+
3+
import java.lang.ref.SoftReference
4+
import kotlin.properties.ReadOnlyProperty
5+
import kotlin.reflect.KProperty
6+
7+
/**
8+
* Usage: `val myValue by SoftLazy { computeValue() }`. The value is evaluated only when it's
9+
* actually accessed. It's then stored in a `SoftReference`, which may be cleared if the JVM needs
10+
* more RAM. Variables defined that way can then be used transparently, as if they were of type `T`.
11+
*/
12+
class SoftLazy<T>(
13+
private val computeValue: () -> T,
14+
) : ReadOnlyProperty<Any?, T> {
15+
var cache: SoftReference<T> = SoftReference(null)
16+
17+
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
18+
return cache.get() ?: computeValue().also { cache = SoftReference(it) }
19+
}
20+
}

core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/STDCMEdge.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ data class STDCMEdge(
7979
null,
8080
previousPlannedNodeRelativeTimeDiff,
8181
graph.remainingTimeEstimator.invoke(this, null, stepTracker),
82+
graph,
8283
)
8384
} else {
8485
// New edge on the same block, after a stop
@@ -103,6 +104,7 @@ data class STDCMEdge(
103104
nextStop.originalStep.plannedTimingData,
104105
previousPlannedNodeRelativeTimeDiff,
105106
graph.remainingTimeEstimator.invoke(this, locationOnEdge, stepTracker),
107+
graph,
106108
)
107109
}
108110
}

core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/STDCMNode.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ package fr.sncf.osrd.stdcm.graph
33
import fr.sncf.osrd.envelope_sim.TrainPhysicsIntegrator.areTimesEqual
44
import fr.sncf.osrd.sim_infra.api.Block
55
import fr.sncf.osrd.stdcm.PlannedTimingData
6+
import fr.sncf.osrd.stdcm.graph.engineering_allowance.generatePreviousSimulationSegments
67
import fr.sncf.osrd.stdcm.infra_exploration.InfraExplorerWithEnvelope
8+
import fr.sncf.osrd.utils.SoftLazy
9+
import fr.sncf.osrd.utils.cacheable
710
import fr.sncf.osrd.utils.units.Offset
811
import kotlin.math.min
912

@@ -27,6 +30,8 @@ data class STDCMNode(
2730
val previousPlannedNodeRelativeTimeDiff: Double?,
2831
// Estimation of the min time it takes to reach the end from this node
2932
var remainingTimeEstimation: Double,
33+
// Reference to the main graph. Only null in some unit tests, where we don't have a full graph
34+
val graph: STDCMGraph?,
3035
) : Comparable<STDCMNode> {
3136

3237
/**
@@ -183,4 +188,14 @@ data class STDCMNode(
183188
fun getRealTime(updatedTimeData: TimeData): Double {
184189
return timeData.getUpdatedEarliestReachableTime(updatedTimeData)
185190
}
191+
192+
val previousSimulationSegments by SoftLazy {
193+
generatePreviousSimulationSegments(previousEdge, graph).cacheable()
194+
}
195+
val allowanceOpportunities by SoftLazy {
196+
graph!!
197+
.allowanceManager
198+
.generateAllowanceOpportunities(previousSimulationSegments, speed)
199+
.cacheable()
200+
}
186201
}

core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/STDCMPathfinding.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ class STDCMPathfinding(
117117
ConstraintCombiner(initConstraints(fullInfra, listOf(rollingStock)).toMutableList())
118118

119119
assert(steps.last().stop) { "The last stop is supposed to be an actual stop" }
120-
starts = getStartNodes(listOf(constraints))
120+
starts = getStartNodes(graph, listOf(constraints))
121121
val path = findPathImpl()
122122
graph.stdcmSimulations.logWarnings()
123123
if (path == null) {
@@ -258,7 +258,10 @@ class STDCMPathfinding(
258258
}
259259

260260
/** Converts start locations into starting nodes. */
261-
private fun getStartNodes(constraints: List<PathfindingConstraint<Block>>): Set<STDCMNode> {
261+
private fun getStartNodes(
262+
graph: STDCMGraph,
263+
constraints: List<PathfindingConstraint<Block>>
264+
): Set<STDCMNode> {
262265
val res = HashSet<STDCMNode>()
263266
val firstStep = steps[0]
264267
assert(!firstStep.stop)
@@ -292,6 +295,7 @@ class STDCMPathfinding(
292295
firstStep.plannedTimingData,
293296
null,
294297
graph.bestPossibleTime,
298+
graph,
295299
)
296300
res.add(node)
297301
}

core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/engineering_allowance/EngineeringAllowanceManager.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,17 @@ class EngineeringAllowanceManager(
4141
assert(constDeceleration > 0.0)
4242

4343
val requiredAdditionalTime = expectedStartTime - prevNode.timeData.earliestReachableTime
44-
val segments = generatePreviousSimulationSegments(prevNode.previousEdge, graph).cacheable()
45-
val opportunities = generateAllowanceOpportunities(segments, prevNode.speed)
44+
45+
val opportunities = prevNode.allowanceOpportunities
46+
4647
val solution =
4748
opportunities
4849
.takeWhile { it.maxNextAllowanceValue >= requiredAdditionalTime }
4950
.firstOrNull { it.addedTime >= requiredAdditionalTime } ?: return null
5051

5152
// We still try to roughly guess the maximum length over which to add the time
5253
var distance = 0.meters
53-
for (segment in segments) {
54+
for (segment in prevNode.previousSimulationSegments) {
5455
if (segment.maxAddedDelay <= requiredAdditionalTime) break
5556
distance += segment.length
5657
}

core/src/test/kotlin/fr/sncf/osrd/stdcm/preprocessing/STDCMHeuristicTests.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ class STDCMHeuristicTests {
248248
null,
249249
null,
250250
0.0,
251+
null
251252
)
252253
val defaultEdge =
253254
STDCMEdge(

0 commit comments

Comments
 (0)