Skip to content

Add comprehensive test suite for Feed-Forward Neural Network wavefunction (David’s implementation)#164

Open
q-pratz-chem wants to merge 4 commits intomainfrom
115-test-rbm-wfn-class-has-low-test-coverage
Open

Add comprehensive test suite for Feed-Forward Neural Network wavefunction (David’s implementation)#164
q-pratz-chem wants to merge 4 commits intomainfrom
115-test-rbm-wfn-class-has-low-test-coverage

Conversation

@q-pratz-chem
Copy link
Collaborator

This PR introduces a new test file covering the Feed-Forward Neural Network (FFNN) wavefunction implemented by David.

  • The test suite achieves 100% code coverage for this module.
  • The addition is primarily for bookkeeping and archival purposes—the implementation is retained in the main branch for reference.
  • Note: The physical or numerical performance of this wavefunction has not yet been validated. If future work aims to verify or improve the model’s functionality, such efforts should be conducted in a separate development branch.

@q-pratz-chem q-pratz-chem linked an issue Nov 10, 2025 that may be closed by this pull request
@kzsigmond kzsigmond self-requested a review November 17, 2025 14:40
@kzsigmond kzsigmond added the test unit tests, integration tests, etc. label Nov 17, 2025
@kzsigmond kzsigmond added this to the v2.0.0 milestone Nov 17, 2025
Copy link
Contributor

@kzsigmond kzsigmond 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 writing the tests for RBM! Could you please go over the comments?

Comment on lines +145 to +148
@pytest.mark.xfail(reason="pspace=None not supported yet")
def test_normalize_none():
rbm = RestrictedBoltzmannMachine(nelec=2, nspin=4, nbath=2)
rbm.normalize(pspace=None)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the development of pspace=None on a roadmap? If the code isn't working for pspace=None, I would prefer to have a value error if pspace is None.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

At the moment, I'm not developing additional features on top of David’s original implementation. To preserve the original design until we have a clearer roadmap for future development, I have intentionally avoided modifying this behavior.

That said, if you feel that explicitly raising an error for pspace=None would improve clarity and safety, I can certainly make that change for now.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd prefer if you would raise an error with a message like: "This feature is not yet implemented". You can keep the code as is in there, I just don't want someone to think that pspace=None is supposed to work, when it doesn't.

Comment on lines +160 to +167
def test_assign_params_flat_and_influences_overlap():
rbm = RestrictedBoltzmannMachine(nelec=2, nspin=4, nbath=2, orders=(1,))
flat = np.zeros(rbm.nparams); flat[0] = 0.2
rbm.assign_params(flat)
olp0 = rbm.get_overlap(0b0)
olp1 = rbm.get_overlap(0b1)
assert olp0 == pytest.approx(1.0)
assert not np.isclose(olp1, 1.0)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why should the overlap be 1.0 with an SD that has 0 electrons and a wfn that has 2? Shouldn't it be 0?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The test is correct in its place.

The overlap is one in the case of zero electrons because overlap = Π_j σ( w_j · m ) * output_scale, where σ(x) = 1 + exp(x) and output_scale = 0.5.

If the correct physical behavior is expected, then there is a need to enforce:

  • get_overlap(sd)=0 when popcount(sd) != nelec
  • or incorporate antisymmetry.

Copy link
Contributor

Choose a reason for hiding this comment

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

Got it! Do you see any potential issues with the "incorrect" physical behavior that could come up when we are calculating the overlap? I think this could potentially happen in two scenarios:

  1. The user defined p-space contains SDs with different number of electrons. No idea why we would do that, but someone could in theory try it.
  2. There is some kind of bug in the code elsewhere that changes the number of electrons in the p-space/s-space, which could go unnoticed for RBM.

It might be worth opening up a separate issue on GitHub, where we can address this down the line.

Comment on lines +170 to +177
def test_assign_params_invalid_length():
rbm = RestrictedBoltzmannMachine(nelec=2, nspin=4, nbath=2)
original = rbm.params.copy()
longer = np.zeros(rbm.nparams + 1)
rbm.assign_params(longer) # should not crash
# Parameters should still have expected shape and size
assert rbm.params.shape == original.shape
assert np.isfinite(rbm.params).all()
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a specific reason why we can assign parameters that are too long and then get truncated?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There is no conceptual reason this wavefunction should accept parameter arrays that are longer than required. The current behavior, silently truncating extra entries, is simply a consequence of how David originally wrote the slicing logic inside assign_params.

If stricter behavior is preferred, an explicit length check is required in place, so that assigning too-long arrays raises a ValueError instead of being silently truncated.

Copy link
Contributor

Choose a reason for hiding this comment

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

I am fine with the current behavior if there is some kind of warning statement notifying the user that the provided parameters got truncated.

@q-pratz-chem
Copy link
Collaborator Author

Thanks for writing the tests for RBM! Could you please go over the comments?

Thanks for the review. I have updated the tests considering the comments and have already pushed the changes.

Comment on lines +145 to +148
@pytest.mark.xfail(reason="pspace=None not supported yet")
def test_normalize_none():
rbm = RestrictedBoltzmannMachine(nelec=2, nspin=4, nbath=2)
rbm.normalize(pspace=None)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd prefer if you would raise an error with a message like: "This feature is not yet implemented". You can keep the code as is in there, I just don't want someone to think that pspace=None is supposed to work, when it doesn't.

Comment on lines +160 to +167
def test_assign_params_flat_and_influences_overlap():
rbm = RestrictedBoltzmannMachine(nelec=2, nspin=4, nbath=2, orders=(1,))
flat = np.zeros(rbm.nparams); flat[0] = 0.2
rbm.assign_params(flat)
olp0 = rbm.get_overlap(0b0)
olp1 = rbm.get_overlap(0b1)
assert olp0 == pytest.approx(1.0)
assert not np.isclose(olp1, 1.0)
Copy link
Contributor

Choose a reason for hiding this comment

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

Got it! Do you see any potential issues with the "incorrect" physical behavior that could come up when we are calculating the overlap? I think this could potentially happen in two scenarios:

  1. The user defined p-space contains SDs with different number of electrons. No idea why we would do that, but someone could in theory try it.
  2. There is some kind of bug in the code elsewhere that changes the number of electrons in the p-space/s-space, which could go unnoticed for RBM.

It might be worth opening up a separate issue on GitHub, where we can address this down the line.

Comment on lines +170 to +177
def test_assign_params_invalid_length():
rbm = RestrictedBoltzmannMachine(nelec=2, nspin=4, nbath=2)
original = rbm.params.copy()
longer = np.zeros(rbm.nparams + 1)
rbm.assign_params(longer) # should not crash
# Parameters should still have expected shape and size
assert rbm.params.shape == original.shape
assert np.isfinite(rbm.params).all()
Copy link
Contributor

Choose a reason for hiding this comment

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

I am fine with the current behavior if there is some kind of warning statement notifying the user that the provided parameters got truncated.

vec_derivs = rbm.get_overlaps(sds, deriv=deriv_index)
numeric_grad = finite_diff_grad(rbm, sds[0])

assert np.isclose(vec_derivs[0], numeric_grad[deriv_index],
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
assert np.isclose(vec_derivs[0], numeric_grad[deriv_index],
assert np.isclose(vec_derivs[deriv_index], numeric_grad[deriv_index],

Not having deriv_index hardcoded for vec_derivs could prevent future issues, if someone decides to change deriv_index to something else.

Comment on lines +75 to +84
## Derivatives w.r.t multiple params
#for deriv_index in [0, rbm.nparams - 1]:
# derivs = rbm.get_overlaps(sds, deriv=deriv_index)
# assert derivs.shape == (len(sds),)
# sd = sds[0]
# eps = 1e-6
# base_flat = rbm.params.copy()
# numeric = finite_diff_grad(rbm, sd)[deriv_index]
# rbm.assign_params(base_flat)
# assert np.isclose(derivs[0], numeric, rtol=1e-3, atol=1e-6)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you want to keep the old code for future reference?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test unit tests, integration tests, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Test: RBM wfn class has low test coverage

2 participants