Skip to content
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

Improve Conjugacy safety and flexibility by adding more validation #444

Merged
merged 32 commits into from
Jul 5, 2024

Conversation

nabriis
Copy link
Collaborator

@nabriis nabriis commented Jun 23, 2024

Closes #345
Closes #174

Best reviewed in "side-by-side" mode.

  • Added ConjugatePair base class to support easy implementation and testing of new conjugate pairs
  • ConjugateNew sampler uses this ConjugatePair class select and verify the conjugate relations
  • Updated the Gibbs Demo to show-case using wrong equations for conjugacy (now throws error)
  • Added many tests for conjugacy to test framework.
  • Fixed bug in "find_valid_samplers" that used wrong conjugate relation.

ToDo

@nabriis nabriis requested a review from amal-ghamdi June 26, 2024 20:47
@nabriis
Copy link
Collaborator Author

nabriis commented Jun 26, 2024

@amal-ghamdi I have now implemented the conjugacy safety framework which is very strongly based on what Jasper did. Could you do a technical review?

Also @jeverink, it would be great if you want to have a look. In particular I was wondering if you have a case that we use this _regression_test_linear method? Else I will remove it for now. I am not even sure the conjugate sampler supports a linear operator on the function.

@jeverink
Copy link
Collaborator

jeverink commented Jun 27, 2024

Thanks for the work @nabriis , here is my take on _regression_test_linear.:

In terms of conditioning (I believe) we should be able to handle I can quickly come up with:

  1. prec = lambda d : d
  2. prec = lambda d : 10*d
  3. prec = lambda d : 10dnp.eye(n) (or any other matrix)
    or
  4. cov = lambda d : 1.0/d
  5. cov = lambda d : 0.1/d
  6. cov = lambda d : (0.1/d)*np.eye(n) (or any other matrix)

The current version of this PR can only handle cases 1 and 4, by checking using _check_conjugate_paramter_is_scalar_identity for the prec or using _check_conjugate_parameter_is_scalar_reciprocal for cov.

If I recall correctly, replacing the identity check with a linearity check, i.e., _check_conjugate_paramter_is_scalar_identity with some improved version of _regression_test_linear, could allow for case 2 . This additional scaling of the parameters is something I do plan to use as part of #424.

I suspect that a final generalization to case 5 and cases 3 and 6 (if wanted) should not be too much additional work then.

(Please fix the paramter typo in the code)

@chaozg chaozg requested a review from jakobsj July 1, 2024 07:09
@jeverink
Copy link
Collaborator

jeverink commented Jul 1, 2024

Thanks for the work @nabriis , here is my take on _regression_test_linear.:

In terms of conditioning (I believe) we should be able to handle I can quickly come up with:

1. prec = lambda d : d

2. prec = lambda d : 10*d

3. prec = lambda d : 10_d_np.eye(n) (or any other matrix)
   or

4. cov = lambda d : 1.0/d

5. cov = lambda d : 0.1/d

6. cov = lambda d : (0.1/d)*np.eye(n) (or any other matrix)

The current version of this PR can only handle cases 1 and 4, by checking using _check_conjugate_paramter_is_scalar_identity for the prec or using _check_conjugate_parameter_is_scalar_reciprocal for cov.

If I recall correctly, replacing the identity check with a linearity check, i.e., _check_conjugate_paramter_is_scalar_identity with some improved version of _regression_test_linear, could allow for case 2 . This additional scaling of the parameters is something I do plan to use as part of #424.

I suspect that a final generalization to case 5 and cases 3 and 6 (if wanted) should not be too much additional work then.

(Please fix the paramter typo in the code)

@nabriis, I currently think that _regression_test_linear can be removed and that handling the cases 1 and 4 above can be enough for the current PR, as it does not break any current models (as far as I am aware) and the other extension can than be considered in future PR.

Copy link
Contributor

@amal-ghamdi amal-ghamdi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many thanks @nabriis for the reimplementation and @jeverink for the original implementation. This looks really great and improves conjugate prior consistency and robustness.

I added some comments for you, feel free to address them however it makes sense to you.

Great work!

cuqi/experimental/mcmc/_conjugate.py Outdated Show resolved Hide resolved
cuqi/experimental/mcmc/_conjugate.py Outdated Show resolved Hide resolved
cuqi/experimental/mcmc/_conjugate.py Show resolved Hide resolved
cuqi/experimental/mcmc/_conjugate.py Outdated Show resolved Hide resolved
cuqi/experimental/mcmc/_conjugate.py Outdated Show resolved Hide resolved
cuqi/experimental/mcmc/_conjugate.py Outdated Show resolved Hide resolved
cuqi/experimental/mcmc/_conjugate.py Outdated Show resolved Hide resolved
cuqi/experimental/mcmc/_conjugate.py Outdated Show resolved Hide resolved
cuqi/experimental/mcmc/_conjugate_approx.py Outdated Show resolved Hide resolved
cuqi/experimental/mcmc/_conjugate_approx.py Outdated Show resolved Hide resolved
@nabriis
Copy link
Collaborator Author

nabriis commented Jul 2, 2024

Thanks for the work @nabriis , here is my take on _regression_test_linear.:
In terms of conditioning (I believe) we should be able to handle I can quickly come up with:

1. prec = lambda d : d

2. prec = lambda d : 10*d

3. prec = lambda d : 10_d_np.eye(n) (or any other matrix)
   or

4. cov = lambda d : 1.0/d

5. cov = lambda d : 0.1/d

6. cov = lambda d : (0.1/d)*np.eye(n) (or any other matrix)

The current version of this PR can only handle cases 1 and 4, by checking using _check_conjugate_paramter_is_scalar_identity for the prec or using _check_conjugate_parameter_is_scalar_reciprocal for cov.
If I recall correctly, replacing the identity check with a linearity check, i.e., _check_conjugate_paramter_is_scalar_identity with some improved version of _regression_test_linear, could allow for case 2 . This additional scaling of the parameters is something I do plan to use as part of #424.
I suspect that a final generalization to case 5 and cases 3 and 6 (if wanted) should not be too much additional work then.
(Please fix the paramter typo in the code)

@nabriis, I currently think that _regression_test_linear can be removed and that handling the cases 1 and 4 above can be enough for the current PR, as it does not break any current models (as far as I am aware) and the other extension can than be considered in future PR.

Thanks for the input. I agree. I added #453

@nabriis nabriis requested a review from amal-ghamdi July 3, 2024 21:41
@nabriis
Copy link
Collaborator Author

nabriis commented Jul 3, 2024

Hi @amal-ghamdi and @jakobsj. As discussed this PR is now ready for you both :)

Copy link
Contributor

@amal-ghamdi amal-ghamdi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @nabriis for the updates!

Just one comment, I added issue #454, let me know what you think.

tests/zexperimental/test_mcmc.py Outdated Show resolved Hide resolved
Copy link
Contributor

@jakobsj jakobsj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much @nabriis and @jeverink for joint work for adding safety checks on the conjugate sampler. The solution with adding conjugate pair as a base class and specific concrete pair classes is very neat. I see also comprehensive tests are added, and a demonstration of the check in the demo, very nice.

My only request here, is for some general documentation to be added, as especially now with the introduction of the pair class, there are many concepts in play. Specifically, I think it should be explained somewhere:

  • what conjugacy is,
  • define what a conjugate pair is,
  • in ConjugatePair.sample() is is mentioned "sample from the conjugate distribution" which in singular is unclear when we need a pair of conjugate distributions, what is meant by "THE conjugate distribution"
  • "conjugate parameter"

I don't know where's the best place to put this, docstring of the ConjugatePair ABC perhaps since general, though may not be so visible there. Maybe in docstring of ConjugateNew sampler?

There is a comment in the docstring of ConjugateNew that the sampler does NOT check correctness, can this comment be removed now this PR adds check for correctness?

@nabriis
Copy link
Collaborator Author

nabriis commented Jul 5, 2024

Thank you very much @nabriis and @jeverink for joint work for adding safety checks on the conjugate sampler. The solution with adding conjugate pair as a base class and specific concrete pair classes is very neat. I see also comprehensive tests are added, and a demonstration of the check in the demo, very nice.

My only request here, is for some general documentation to be added, as especially now with the introduction of the pair class, there are many concepts in play. Specifically, I think it should be explained somewhere:

  • what conjugacy is,
  • define what a conjugate pair is,
  • in ConjugatePair.sample() is is mentioned "sample from the conjugate distribution" which in singular is unclear when we need a pair of conjugate distributions, what is meant by "THE conjugate distribution"
  • "conjugate parameter"

I don't know where's the best place to put this, docstring of the ConjugatePair ABC perhaps since general, though may not be so visible there. Maybe in docstring of ConjugateNew sampler?

There is a comment in the docstring of ConjugateNew that the sampler does NOT check correctness, can this comment be removed now this PR adds check for correctness?

I updated the description now. Hope it helps. I think we could write a good tutorial later on conjugacy, but perhaps this is sufficient for this PR.

@nabriis nabriis requested a review from jakobsj July 5, 2024 07:22
Co-authored-by: Jakob Sauer Jørgensen <jakobsj@users.noreply.github.com>
Copy link
Contributor

@jakobsj jakobsj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding a bit of documentation. Agree this will suffices to clarify the different concepts and connections for now and have added an issue for a tutorial as suggested: #458

@nabriis nabriis merged commit c77d3de into main Jul 5, 2024
6 checks passed
@nabriis nabriis deleted the feature_345_174_conjugacy_safety_and_flexibility branch July 5, 2024 07:58
This pull request was closed.
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.

Making conjugacy consistent Check parameter is correct for conjugacy sampling
4 participants