Skip to content

CausalEstimand class for evaluating causal estimands #40

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

Merged
merged 26 commits into from
May 1, 2025

Conversation

willGraham01
Copy link
Collaborator

@willGraham01 willGraham01 commented Apr 29, 2025

Partially addresses #37 | Target is #39 since ParameterNodes are needed to get this functionality working, but @mscroggs feel free to hold off the merge until you're happy with the base (since this will need rebasing after any updates to that branch, anyway).

Introduces the CausalProblem class, designed to handle interactions between a Graph (.graph), the causal estimand of interest (.causal_estimand) and the constraints (currently not implemented). Handing of the constraints is not introduced in this pull request, since any comments about how the causal_estimand is being handled would apply to the constraints too, so figured it was best to settle on a design for one before writing the next.

Key Changes

Graph class

Had to introduce two methods related to ParameterNodes - mostly for fetching a tuple of all such nodes (note that this method uses graph.ordered_nodes since it is important that the parameter nodes a consistently given in the same order) and for the setting of the .value attributes of these nodes.

@mscroggs you might want to steal the corresponding changes & their tests and move them into the base PR (#39).

Node class

The sample method for ParameterNodes needs to have the same argument names as the super-class for the "up-the-graph" logic to work without an error, so have removed the _ prefixes and slapped on a # noqa for now, until we find a more elegant solution.

I also took the liberty of telling the linter that unused *args and **kwargs are OK. Since we're going to have a lot of inherited and overwritten methods that may not utilise all the arguments in the signature of the super-class.

CausalProblem

A CausalProblem can be initialised with just a label, and optionally providing a Graph that the instance will store. Said graph will define the relationships between the RVs that the problem considers, and can be set later via the .graph attribute if so desired. Very limited functionality (as in, essentially all you can do is set the .graph attribute) is available for a CausalProblem instance without a set .graph attribute.

Otherwise, the primary way a user is expected to interact with a CausalProblem is to provide the causal estimand function via the set_causal_estimand method. This takes some callable object (sigma) which is assumed to be a function of some RVs, with the RVs to be associated to Nodes in the .graph. At present, we also have to run a few "hacks" due to some design aspects we haven't got round to addressing:

  • set_causal_estimand allows one of the arguments to sigma to be a Graph object. This is because our current algorithms module only has methods that support calls via expectation(graph, node_name, ...) etc.
  • sigma (and the tests for this method) provides a static rng_key and sample_size, whereas in the long run we probably want these set instance-wise across the whole CausalProblem instance.

Once set, the .causal_estimand method can be called, which will evaluate the given sigma function using the associated Nodes in .graph. This method takes a jax.Array as input, which is assumed to be an array of the parameter values - the order of the values matches that of CausalProblem.graph.parameter_nodes (hence why it is important for this method to always return parameter nodes in the same order). It then calls .graph.set_parameters with the appropriate values extracted from the input array, before running sigma and returning the result. This gets around the issue identified in #37 regarding fixing a single realisation of a RV by accident.

.causal_estimand primarily exists to be sent into a solver / optimiser - I don't envision the user ever wanting to evaluate it manually, and they certainly should not need to evaluate it manually via a parameter vector. If a user does want to evaluate their causal estimand at a particular set of parameters, the recommended way is to run

# Inputs are sent directly to .graph.set_parameters(**)
causal_problem.set_parameter_values(**parameter_values)
# The .parameter_vector property returns the appropriate vector for the
# current parameter values.
# As such, since we just set the parameter values (using their names),
# we can now get the CP instance itself to build the vector, then evaluate
# the causal estimand at that vector.
causal_problem.causal_estimand(causal_problem.parameter_vector)

@willGraham01 willGraham01 force-pushed the wgraham/graph-is-pp-function branch from 65d8936 to a0c1df4 Compare April 30, 2025 13:24
@willGraham01 willGraham01 changed the base branch from main to mscroggs/parameter-node April 30, 2025 13:24
@willGraham01 willGraham01 changed the title Wgraham/graph is pp function CausalEstimand class for evaluating causal estimands Apr 30, 2025
@willGraham01 willGraham01 marked this pull request as ready for review April 30, 2025 13:48
@willGraham01 willGraham01 requested a review from mscroggs April 30, 2025 13:58
@mscroggs
Copy link
Collaborator

mscroggs commented May 1, 2025

The sample method for ParameterNodes needs to have the same argument names as the super-class for the "up-the-graph" logic to work without an error, so have removed the _ prefixes and slapped on a # noqa for now, until we find a more elegant solution.

I did this exact same change yesterday when I wrote a new test in #42. Yet to think of a more elegant way to do it

mscroggs added a commit that referenced this pull request May 1, 2025
* add parameter node

* Update src/causalprog/graph/node.py

* Update src/causalprog/graph/node.py

* Update src/causalprog/graph/node.py

* Update src/causalprog/graph/node.py

* ruff

* fix

* fix test

* need noqa here as they're somethimes used as kwargs

* Move parameter functions and test from #40

* typing

* docstring

* Update src/causalprog/graph/node.py

Co-authored-by: Will Graham <[email protected]>

* Update src/causalprog/graph/node.py

Co-authored-by: Will Graham <[email protected]>

* rufffff

* ruffffffff

---------

Co-authored-by: Will Graham <[email protected]>
Base automatically changed from mscroggs/parameter-node to main May 1, 2025 08:35
@willGraham01 willGraham01 merged commit 7bffe4f into main May 1, 2025
5 checks passed
@willGraham01 willGraham01 deleted the wgraham/graph-is-pp-function branch May 1, 2025 08:45
This was referenced May 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants