Closed georgematheos closed 1 year ago
@ztangent For equality, what do you think between the following possible semantics?
For checking equality w.r.t. particle weights:
a
and b
are equal if a.log_weights .+ a.lml_estimate == b.log_weights .+ b.lml_estimate
and all else is the samea
and b
are equal if a.log_weights == b.log_weights && a.lml_estimate == b.lml_estimate
and all else is the sameFor dealing with new_traces
:
A. Two PF states which are identical except their new_traces
field are equal.
B. PF states must have equivalent new_traces
fields to be equal.
The benefit of doing 1-A is that it would make it easier to do things like dictionary lookups based on equivalent PF states which might come from different paths through an inference algorithm. But it also seems like it could be confusing if, e.g., calling update_refs!
on two equivalent PF states can yield non-equivalent states.
What do you think?
Re A vs B -- since we expect in normal usage the new_traces
vector to have undef
values, errors can be thrown if we try to check the equality or two new_traces
arrays containing undef values. So I think we should potentially use semantics A.
Thanks for raising these questions! I think 1-A sounds like a fine way to go -- or at least, I currently can't think of edge cases where you'd want a stricter equality check. Re 1, I'd maybe check that this is still correct when custom priority weights are used when resampling, as in the second branch of this code:
Re A vs. B, I think not checking new_traces
is fine given that it's not supposed to be exposed as part of the interface.
@ztangent I've committed a change which implements 2-A. I'm heading out on vacation now, so I will only be able to respond sporadically for the coming month, but hopefully this is a viable change for now!
Re implementation 1 vs 2 -- I switched to implementation 2. (Also, I realize that my proposal for "1" gets the math slightly wrong, by the way. This isn't the reason for the switch, though.)
The reason I switched from 1 to 2 is I realized I do not understand what the semantics are supposed to be regarding how the values of log_ml_est
and log_weights
are set. I had thought that the log_ml_est
was just a performance optimization of some sort, and that in principle the ParticleFilterState data structure could be implemented where the log ML estimate was just obtained as logsumexp(log_weights) - n_particles
, without changing any semantics. But as I'm looking at the code now, I realize that there are a couple methods that do not seem to treat the separation between log_weights
and the log_ml_est
as a semantically irrelevant implementation detail. get_log_weights
can return different things, depending how much of the log ML estimate is factored into the weight vector and how much into log_ml_est
. Likewise, the code you linked above appears like it might care about the separation of log_weights
and log_ml_est
, though I would need to read more carefully to be sure.
You or @alex-lew may understand these semantics, and so know if there is a better implementation of equality for the ParticleFilterState. Or perhaps it is actually the case that the semantics should always that the separation of log_ml_est
and log_weights
is irrelevant, and there are a couple of interface methods that currently mistakenly return different things depending on this separation?
Anyway, if this is going to require longer discussion, perhaps we could commit this implementation of 2-A for now, and open an issue to discuss potentially changing equality semantics for particle filters.
Going with 2-A sounds good to me! Yes, on second thought, we probably shouldn't say two particle filters are equal if get_log_weights
returns different things. I've made one additional commit to ensure that the implementation of hash
is consistent with the semantics of ==
. But apart from that, I think we can merge this -- thanks for making these changes! :)
Looks great! It strikes me that we might also want to implement
Base.(:==)
(and alsoBase.hash
since that's required for every type that implements==
), so that we can check that copies are accurate? And to add a test case somewhere.