re possible other representations of time in matsim: we have thought about that multiple times. There seem to be several options:
(1) leave as is (as primitive type)
(2) change to Double (as object type)
(3) change to some class that extends Number (Double itself is final)
(4) change to some "Time" class that exists in the java library
It seems that you can do arithmetic computations only with (1), since there is no overloading of the +, -, *, / operators in Java.
With (2) (and maybe with (3)???) one would at least have autoboxing support. It seems that this addresses most if not all of the problems with arithmetics inside MATSim (I just tried) ... it seems to me that this was different several years back when I tried this before. So this might just be slow.
(a) make prototypical change to (2) and test for computational speed
(b) investigate if (3) supports autoboxing. If so, consider decision between (2) and (3)
(c) maybe investigate if a transitition to (4) might be possible without too much blood-shedding. If so, make prototypical change and investigate computational speed.
(d) decide and implement
Any other thoughts?
[Created via e-mail received from: "Nagel, Kai, Prof. Dr." <email@example.com>]
What is the problem with the current double? Why do you look at alternatives?
The only issue I’m currently aware of is the special treatment of “undefined time”, which could be solved differently if it would be an object type.
The current double type clearly offers the best performance, and a very good memory density. Using a Double or an even more complex type would require a lot more RAM to store the same information, and thus likely slow MATSim further down. Auto-Boxing/-Unboxing essentially means an additional memory access each time a time-value is accessed, and the memory access is already the bottleneck in MATSim. A potential change would thus, in my opinion, need to offer very compelling advantages to offset the performance disadvantage.
Exactly as you said, we would like to change the way “undefined time” is handled. We should find a solution which is “cheaper” than the cost of occasional debugging. Also there is a risk that sometimes the use of -Inf remains unnoticed.
I think I would try out (2.1) in places where we specifically use “undefined time” and see what the computational penalty is. Then we can decide what is “cheaper”.
The application of UNDEFINED_TIME is used in so many ways, so actually removing it requires applying smaller steps.
A few cases (maybe there are even more):
uninitialised value that should not be used, like in Activity.endTime (leads to bugs)
optional value, like in TransitRouteStop.arrivalOffset etc. (however the following check is not always performed, so again, may lead to bugs)
modelling time-invariant values, like
The first 2 cases are very similar. They are about producing time values. They could be modelled with using Double (or a proper “Time” class) internally.
The last case is different. It is about consuming time values. I do not think that using Double (even ignoring the computational penalty) is right. The problem is that computeTimeDependentValue(…, double time) provides a value for a given moment in time, whereas computeTimeIndependentValue(…) provides a fixed value (time-invariant cases) or an average/minimum/maximum/free-flow/??? value (time variant cases). We should not add extra responsibilities to computeTimeDependentValue(…, double time) by assuming that computeTimeDependentValue(…, UNDEFINED_TIME) is equivalent to computeTimeIndependentValue(…). It is maybe okay if that happens internally (i.e. implementation specific), but passing UNDEFINED_TIMEto computeTimeDependentValue(…, double time) at the level of interfaces is an overuse of the interface.
BTW. There are already comments in some places in code that also discourage the use of UNDEFINED_TIME to say “time is not relevant”. For instance:
I would like to first tackle the 3rd case since it is independent of the original issue (cases 1 and 2).
One thing: There is sometimes
My intuition is that we should not replace it by something like
We had Double.NaN for some time as undefined time, and for that the equality check "==" is wrong. Having a method here seems more flexible than "==".
After almost all calls of "compute-like" methods with UNDEFINED_TIME passed as time are removed ( ), now I will proceed to cases (1) and (2), i.e. time getters & setters.