19
$\begingroup$

Bug introduced in 12.0 or earlier and persisting through 12.2 or later


It seems we've discovered a bug! The following is a summary of the problem and possible workarounds. Scroll down to ORIGINAL POST to see the original statement of the issue.

If a List, TimeSeries, etc. of Around objects contains any identical elements, Accumulate produces propagated uncertainties that are too large. FoldList[Plus, 0, list] and FoldList[Plus]@list are valid alternatives that do not present this issue for Lists, but these do not work with TimeSeries! Finding something which does work with TimeSeries is still a work in progress.

If a List, TimeSeries, etc. of Around objects contains consecutive identical elements, Differences produces 0., which does not have an associated uncertainty. MovingMap[Subtract[#[[2]], #[[1]]] &, list, 1] and MovingMap[Subtract[#[[2]], #[[1]]] &, #, 1] &@list are valid alternatives which do not present this issue. And they work with TimeSeries!

Analysis of these and other functions can be found here.

For now, my best solution is to create a symbolic TimeSeries to manipulate with Accumulate, Differences, Ratios, etc., and then use ReplaceAll to insert the Around data in the final step. I'm not using AroundReplace because that function took over ten minutes to process a single TimeSeries! But, one must be careful when using ReplaceAll in lieu of AroundReplace. According to the documentation,

[ReplaceAll and AroundReplace] coincide if each replaced variable appears once in the original expression.

One must therefore perform calculations in a manner that ensures this is the case.

------------------------------------ORIGINAL POST------------------------------------

I am working with several TimeSeries containing Around objects. I find that the propagated uncertainties for numerical values are larger than I expect them to be. In contrast, the propagated uncertainties for symbolic values are exactly what I expect them to be.

This is also true for lists of Around objects, so I will use List to demonstrate. Note that the original data values are all integers greater than or equal to zero (0 ≤ n[i] ∈ ℤ) and their original uncertainties equal their square roots (δn[i] = √n[i])

First, generate a list of symbolic data:

symbolicData = Table[Around[n[i], Sqrt[n[i]]], {i, 10}]

enter image description here

Then, Accumulate these data:

symbolicTotals = Accumulate@symbolicData

enter image description here

The uncertainty of the last value is the square root of that value:

{symbolicTotals[[-1]]["Uncertainty"], Sqrt@symbolicTotals[[-1]]["Value"]}

enter image description here

Given my understanding of error propagation, this is correct.

Now, generate numerical data:

numericalData = Table[Around[#, Sqrt[#]] &@RandomInteger[10], {i, 10}]

enter image description here

Acculumate these data:

numericalTotals = Accumulate@numericalData

enter image description here

Compare the last value's uncertainty and square root:

{numericalTotals[[-1]]["Uncertainty"], Sqrt@numericalTotals[[-1]]["Value"]}

enter image description here

The uncertainty is larger than the square root. This happens for any long list of numbers.

Why? And how can I fix it? (Assuming there's an actual problem here, and not simply a lack of knowledge on my end.)

My guess is that this discrepancy is a consequence of the fact that

When Around is used in computations, uncertainties are by default propagated using a first-order series approximation, assuming no correlations.

What exactly is being approximated here, and if Around always does this, why doesn't it affect symbolic values?

I understand that AroundReplace allows for higher-order approximations, but it starts with a symbolic expression and substitutes numerical values. I'm starting with numerical values. Is my only option to generate TimeSeries objects with symbolic values, do all my computations, and then AroundReplace the symbols with the original numerical data?

Is there a better way?

------------------------------------UPDATE------------------------------------

@JulienKluge, @SjoerdSmit, and @JimB have suggested and demonstrated that this is a bug in Accumulate. I've done my own investigation, and I agree. Accumulate produces incorrectly propagated uncertainty whenever the same Around object appears multiple times in whatever is being accumulated. This error seems to increase with the number of duplicates.

Accumulate is not the only function with an issue. When the same Around object appears consecutively in a list, Differences produces a zero with no uncertainty!

enter image description here (If you'd like a copy of the notebook in which I performed this investigation, click here.)

I've encountered the problem with Differences before, but I'm only now recognizing it as a serious issue. I suppose bugs like this are why Around is still an experimental function...

In light of everything, I think I will try doing all my calculations on symbolic TimeSeries objects and finishing them off with AroundReplace. Hopefully, that will circumvent the Accumulate and Differences issues as well as some other minor problems I've encountered. If that doesn't work, I'll compute the uncertainty bands myself...

Wish me luck!

------------------------------------UPDATE------------------------------------

AroundReplace took over ten minutes to replace the values of a symbolic TimeSeries with Around objects. No other functions such as Accumulate had yet been used. So, I won't be using AroundReplace. ReplaceAll was much faster, but the documentation suggests it might introduce its own problems when working with Around.

Following the advice of @SjoerdSmit, I am going to try using FoldList[Plus]@list and MovingMap[Subtract[#[[2]], #[[1]]] &, #, 1] &@list as alternatives to Accumulate and Differences, respectively.

I'll report back if there are any major changes.

$\endgroup$
4
  • 1
    $\begingroup$ Somehow the "SUMMARY" does not appear to be a question at all, but an answer. It would be nice if the question were clearly posed as a question, and if you have an answer, please post it as an answer. $\endgroup$
    – Michael E2
    Mar 15, 2021 at 2:30
  • $\begingroup$ My apologies. I'm a relatively new active participant here, and I'm still learning the etiquette. The original question lead to the discovery of a bug, and so I modified the original post to alert other users of this fact. I will try to make that more clear. Thanks! $\endgroup$ Mar 16, 2021 at 14:44
  • 1
    $\begingroup$ Update: the bug was fixed in version 12.3 $\endgroup$ May 24, 2021 at 20:09
  • $\begingroup$ Excellent! I'll update Mathematica and this post to reflect that. $\endgroup$ May 25, 2021 at 18:40

3 Answers 3

14
$\begingroup$

Yes, this seems to be a bug. Compare, for example:

list1 = {Around[1., 2.], Around[1., 2.0001]};
Plus @@ list1
Fold[Plus, 0, list1]
Last @ Accumulate[list1]

Around[2., 2.8284978363081703`]

with

list2 = {Around[1., 2.], Around[1., 2.]};
Plus @@ list2
Fold[Plus, 0, list2]
Last @ Accumulate[list2]

Around[2., 2.8284271247461903`]

Around[2., 4.] (* result from Accumulate*)

I reported the issue. In the mean while you can use:

FoldList[Plus, 0, list2]

to get a correctly accumulated list.

$\endgroup$
7
  • $\begingroup$ For the workaround and for reporting the bug, I'm accepting this answer! Even though I've other problems with Around objects, and might have to resort to AroundReplace after all... $\endgroup$ Feb 24, 2021 at 2:17
  • 1
    $\begingroup$ @AaronEiben It might be worth trying alternative methods as well. Like I said, FolList[Plus, 0, list] is a valid alternative for Accumulate and such alternatives exist for Differences as well. For example, #2 - #1 & @@@ Partition[Range[5], 2, 1]. $\endgroup$ Feb 24, 2021 at 9:55
  • $\begingroup$ Agreed. AroundReplace took over ten minutes to replace the values in a symbolic TimeSeries--one that had not yet been operated upon! ReplaceAll was a thousand times faster, but the documentation suggests it will introduce its own problems with Around objects if not used carefully. So, I'm testing FoldList[Plus] as an alternative to Accumulate and MovingMap[Subtract[#[[2]], #[[1]]] &, #, 1]& as an alternative to Differences. These seem to work so far, and I'll update the original post as I learn more. Thanks again for your help! $\endgroup$ Feb 24, 2021 at 13:22
  • $\begingroup$ It turns out FoldList doesn't play nicely with TimeSeries. For example, if test = TimeSeries[val /@ Range[0, 9]] then FoldList[Plus, 0, test] produces an error. Any other suggestions? $\endgroup$ Feb 24, 2021 at 16:52
  • $\begingroup$ @AaronEiben Hmmm, not really. You can pull the timeseries apart with Normal; then fold the values (keeping the timestamps apart); and then put it all back together. That's the best I've got right now. $\endgroup$ Feb 24, 2021 at 23:17
13
$\begingroup$

Okay, wow. This stumped me for a bit.

But I found the answer. It seems to be a bug. An innocent looking one.

The fact you tried Integers instead of Reals triggered it. (I tried to use Reals first and failed to reproduce)

What happens is the following. Whenever Accumulate sees two equal values, it multiplies them by two instead of adding them. Which makes sense for reals

Accumulate[{a, b}]
Accumulate[{a, a}]

{a, a + b}

{a, 2a}

But not for Around's. The multiplication by two yields a different error propagation in the standard linear Gaussian approach

Accumulate[{a,b}]/.{a->Around[v,d],b->Around[v,d]}
Accumulate[{a,a}]/.{a->Around[v,d]}

{v±d,2 v±Sqrt[2] Sqrt[d^2]}

{v±d,2 v±2 d}

Judging from the comments, seems to be a bug. Someone/You should file it with Wolfram.

12.1.0 for Microsoft Windows (64-bit) (March 14, 2020)

$\endgroup$
7
  • 1
    $\begingroup$ No, I think this is correct. Adding two different numbers with uncorrelated errors is different from adding the same number with the same error to itself. In the first case, the errors partially cancel because they're uncorrelated, which gives a smaller error overall. That's why AroundReplace exists along with ReplaceAll. Compare, e.g., AroundReplace[a + Sqrt[a], a -> Around[2., 0.3]] with ReplaceAll[a + Sqrt[a], a -> Around[2., 0.3]]. In the second case, the two terms are assumed to be uncorrelated. $\endgroup$ Feb 22, 2021 at 22:39
  • $\begingroup$ Ahh darng...yes I think you are correct. This gotcha hit me already multiple times since I started using Around. Thanks. $\endgroup$ Feb 22, 2021 at 22:43
  • 1
    $\begingroup$ No wait, wouldn't that mean, that Accumulate implicitly assumes the values to be the same and thus dependent? $\endgroup$ Feb 22, 2021 at 22:52
  • 4
    $\begingroup$ @SjoerdSmit. I agree with Julien Kluge in that it's an Accumulate bug rather than an issue with Around. Consider a non-integer common value with the same uncertainty: Accumulate[{Around[4.5, 4], Around[4.5, 4]}][[2]] gives Around[9., 8.] when it should give Around[4.5 + 4.5, Sqrt[4^2 + 4^2]] which is Around[9., 5.656854249492381]. But if the uncertainties are different, then it gives the expected answer: Accumulate[{Around[4.5, 4], Around[4.5, 6]}][[2]] results in Around[9., 7.211102550927978] which is what Around[4.5 + 4.5, Sqrt[4^2 + 6^2]] produces. $\endgroup$
    – JimB
    Feb 23, 2021 at 0:46
  • 2
    $\begingroup$ Ah, yes. I see now. This is definitely confusing. It seems like you can obtain the right behaviour with Accumulate[{Around[a, b], Around[a, b2]}][[2]] /. b2 -> b. You can also see that Accumulate[{Around[1, 2.], Around[1, 2.0]}][[2]] is different from Accumulate[{Around[1, 2.], Around[1, 2.0001]}][[2]]. That's definitely a bug. I'll file it today. $\endgroup$ Feb 23, 2021 at 7:44
2
$\begingroup$

I don't have enough reputation yet to comment but I will note that Accumulate can be particularly tricky with TimeSeries objects. This is well documented elsewhere but, in short, Accumulate applied to a TimeSeries object will interpolate "missing" values if your TimeSeries is not, by default, what Mathematica considers to be "Regularly Sampled". There are good reasons "under the hood" why this is the default behaviour but it's a trap for users who are inexperienced with the quirks of TimeSeries

To get around this, you can specify that your TimeSeries object is regularly sampled when you create it.

For the purpose of this example, assume you have some data ready to be created as a timeseries assigned to xyz:

newTimeseries = TimeSeries[xyz,TemporalRegularity->True]

When you now run Accumulate on this newTimeSeries object, you should get values as expected...but you may break other functionality by forcing the TemporalRegularity to True if it actually isn't.

$\endgroup$
4
  • 1
    $\begingroup$ Hopefully my upvote boosts your reputation. The data I'm using is, in principle, regularly sampled with no missing values. I run it through TimeSeriesResample and set missing values to 0 before doing any computations. But I'll try your suggestion and see if anything changes. Thanks! $\endgroup$ Mar 16, 2021 at 15:09
  • 1
    $\begingroup$ Thank you, much appreciated. One thing I will note is that even regular timeseries -- like a default financial timeseries -- is not regularly sampled. Try using RegularlySampledQ on your timeseries to check. If it is false, try the fix i suggested in the answer and see what you get. Good luck and thanks again! $\endgroup$
    – R110
    Mar 16, 2021 at 20:54
  • 1
    $\begingroup$ See also first answer here: mathematica.stackexchange.com/questions/170738/… $\endgroup$
    – R110
    Mar 16, 2021 at 21:08
  • 1
    $\begingroup$ I used RegularlySampledQ before changing anything and found that, indeed, my TimeSeries are all regularly sampled. So it still seems this is an issue with Around. I've marked it as a bug and it's been reported to Wolfram Research, so hopefully, it gets fixed soon. $\endgroup$ Mar 16, 2021 at 23:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.