-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
make CashFlow lazy, introduce notification pass through for observables #1750
Conversation
…ification pass through
addresses #1748 |
…t need the set of additional observables
…ore we need deepUpdate() instead of recalculate(), just as for rate helpers
@lballabio this is not finished, but before I continue I'd like your opinion on where this is going. The main work is to add the option to use immutable coupon pricers everywhere. This is the prerequisite (I think) to apply the observation graph compression (= register with observables of an observer instead the observer itself). And we should do this in a backwards compatible way, i.e. the default will remain a coupon pricer that can be changed / set with We can probably also use the new |
I like the On the other hand I'm not fully convinced by the immutable coupon pricers everywhere and the Looking from the results of this PR we would have a different behavior between coupon(...);
coupon.setPricer(pricer1);
...
coupon.setPricer(pricer2); // doesn't throws
... and coupon(..., pricer1);
...
coupon.setPricer(pricer2); // now throws
... For someone not aware of this PR and the related issue #1748 this is unexpected. If there is Also passing in a pricer via the constructor or via the setter shouldn't have an impact on the And in general I wouldn't tweak the In total, are these pitfalls worth the benefit solving the problem of changing the coupon pricer after assigning the cashflow to an instrument? Isn't it more of an academical problem which doesn't exist in real life? And if someone wants to do this there is still the possibility to register and unregister theses pricers to the instrument directly. So the tools are there to solve this problem. |
I think the potential compression of the observation graph is too good to ignore: For example, a single vanilla swap with say 40 coupons on each leg registers with 80 observables today. This PR brings that down to 3 observables (index, eval date, coupon pricer). I don't think it's realistic to do this kind of optimisation in user code even if someone would bother to try. And why should they if we can do this automatically and safely while building the observer graph. At the moment I don't see a good way to avoid the distinction between immutable and mutable pricers. Of course we should add a comment to the constructors along the lines "The coupon pricer can be passed to the constructor or set after construction with setPricer(). If passed to the constructor, the pricer is immutable, i.e. a subsequent call to setPricer() will throw an error. This is the recommended way, because it allows for an optimised representation of observability relations." The advantage of handling the optimisation in Maybe more important, it would be unsafe to register with the coupon observerables in Finally, they way it is implemented, it will work recursively. |
Hi @pcaspers, I'll have to do some more thinking about this—I like the idea of optimizing the graph but I'm not sure about the added complexity of the Also, I'm not sure that Are you at the point when you can run some timing experiment and see what's the effect of these changes? And maybe there are 2 PRs inside this one? One making cashflows lazy and another for graph optimization? |
Oh, I see you partially answered my questions while I was writing them :) |
A link would not allow the compression by default, which is correct since it might be relinkable? Actually we could enable it though otherwise, i.e. if it can't be relinked. Separate discussion probably, since it needs some modifications. I can split the PR into two. |
The graph optimization reduces the memory footprint: if we have 100k swaps with 80 cashflows each we avoid storing ~8m shared_ptr each in turn storing 16 byte on a 64 bit system, i.e. 128 MB in total. |
I'm not worried with |
You are right, I didn't think of this. My answer right now would be that if So in addition to the assumption that a pass-through observable must not change its observables after construction, we need to ensure that any observer registering with such an observable must not remove any of its observables. Except it wants to remove all of them. In case of But in general that can cause errors where they do not occur today, e.g. when client code tries to unregister a swap with one of its coupons. I don't see many use cases for that at the moment, but it's a breaking change anyway! |
I can look at some bigger use cases. If we think it's worthwhile maybe we can add a compile-time setting |
will open a new PR for the lazy cashflow part |
No description provided.