Skip to content

Python bindings: getCube/setCube declare different shared_ptr spellings, so in-memory cube reuse raises TypeError (regression in 1.8.16.0) #351

Description

@dazivo

Summary

In the Python bindings, OREApp::getCube() and InputParameters::setCube() are declared with different spellings of the same type, so the cube returned by the getter cannot be passed to the setter:

TypeError: in method 'InputParameters_setCube', argument 2 of type
           'QuantLib::ext::shared_ptr< ore::analytics::NPVCube > const &'

setMarketCube/getMarketCube are affected identically. This is a regression between v1.8.15.0 and v1.8.16.0, and it disables in-memory cube reuse from Python — running the XVA analytic postprocess-only on a previously simulated cube.

Root cause

The C++ is self-consistent — both sides use QuantLib::ext::shared_ptr:

  • OREAnalytics/orea/app/oreapp.hpp:78QuantLib::ext::shared_ptr<NPVCube> getCube(std::string cubeName);
  • OREAnalytics/orea/app/inputparameters.hpp:674void setCube(const QuantLib::ext::shared_ptr<NPVCube>& cube)

The SWIG interface qualifies only the setters:

ORE-SWIG/OREAnalytics-SWIG/SWIG/orea_app.i

355:    void setCube(const QuantLib::ext::shared_ptr<ore::analytics::NPVCube>& file);              // qualified
356:    void setMarketCube(const QuantLib::ext::shared_ptr<ore::analytics::AggregationScenarioData>& file);
...
554:    ext::shared_ptr<ore::analytics::NPVCube> getCube(std::string cubeName);                    // NOT qualified
557:    ext::shared_ptr<ore::analytics::AggregationScenarioData> getMarketCube(std::string cubeName);

SWIG keys its type table on the literal spelling, so ext::shared_ptr<...> and QuantLib::ext::shared_ptr<...> are registered as two distinct types. The mismatch is visible in the proxy objects themselves:

returned by getCube : <ORE.NPVCube; proxy of <Swig Object of type 'ext::shared_ptr< ore::analytics::NPVCube > *'>>
expected by setCube : QuantLib::ext::shared_ptr< ore::analytics::NPVCube > const &

In v1.8.15.0 both sides read ext::shared_ptr<NPVCube> (lines 345/383) — consistent, and it works. The setters were qualified to match the C++ somewhere in v1.8.15.0..v1.8.16.0 (the change enters on the merge 85c8f7494, feature/QPR-13887) and the getters were not updated with them.

Suggested fix: add the QuantLib:: prefix to the two getter declarations at orea_app.i:554 and :557, so they match the setters and the C++.

Reproducer

Any run that produces a cube, then handing that cube back:

import ORE

app = ORE.OREApp(params, logfile, log_mask, True)
app.run(market_data, fixings)          # analytics: NPV + EXPOSURE + XVA

cube = app.getCube(next(iter(app.getCubeNames())))
market_cube = app.getMarketCube(next(iter(app.getMarketCubeNames())))

p = ORE.InputParameters()
p.setCube(cube)                        # TypeError
p.setMarketCube(market_cube)           # TypeError

Both calls raise on 1.8.16.0 and both succeed on 1.8.15.0.

Impact

The intended workflow is unreachable from Python. Reuse requires both cubes — XvaAnalyticImpl hard-requires the market cube ("XVA without EXPOSURE requires a market cube as input", xvaanalytic.cpp) — and there is no substitute for either:

  • The market cube cannot be supplied as a file instead, because AggregationScenarioData is not serialisable through the binding (the SWIG wrapper types the qualifier argument of has/get as an opaque bare string, so qualified entries are unreachable).
  • It cannot be obtained from the engine either: OREApp::run(loader) ends at // Leave any report writing to the calling aplication and writes no cubes; only the file-loader path, OREApp::analytics(), calls saveCube/saveAggregationScenarioData.

So a Python caller using the InputParameters setter path cannot reuse a cube at all on 1.8.16.0, and must re-simulate. For a Monte-Carlo exposure cube this is the difference between seconds and a full simulation.

Noting in passing that inputparameters.hpp:670 carries // TODO: API for setting NPV and market cubes directly above these two setters, so this area may already be known to be unfinished.

Environment

  • open-source-risk-engine 1.8.16.0 (PyPI wheel, cp312-cp312-macosx_14_0_arm64), Python 3.12.13, macOS 15 arm64
  • Compared against 1.8.16.0 and 1.8.15.0 wheels on the same machine; the C++ / .i line references are from tags v1.8.16.0 and v1.8.15.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions