-
-
Notifications
You must be signed in to change notification settings - Fork 160
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
LRE Inference Functions #2447
LRE Inference Functions #2447
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #2447 +/- ##
==========================================
+ Coverage 98.70% 98.71% +0.01%
==========================================
Files 88 89 +1
Lines 4083 4133 +50
==========================================
+ Hits 4030 4080 +50
Misses 53 53 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks great. Nice work, @purva-thakre !
Added some comments, but many of them are quite minor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very cool stuff here.
I left some comments related to things Vincent raised. I think we can make some big simplifications with how we do monomials, but otherwise looking good.
a17ce99
to
c92a38a
Compare
16e247f
to
aef46ab
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice changes! I'm hopeful we can simplify things a bit more, but I might not have the full picture in my head to understand why certain things need to be that way.
@natestemen This is ready for a review with your suggestions. I removed 2 unit tests in 42fd2b1 because When I add the unit test to check if all the coeffs sum up to 1, the tests fail. But if I manually check this value in a jupyter notebook by using I figured this was a float addition issue. Rounding the values up to 2 decimal places before calculating the sum is also not working here. Edit: I think this is a bug in pytest. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice clean up! Getting closer!
I'm lacking some understanding as to how the functions added here fit together, but maybe that will come in the final PR? This is usually where I would rely on the PR description to add context for the reviewer.
assert ( | ||
expected_matrix - sample_matrix(test_circ, test_degree, 1) | ||
).all() <= 1e-3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert ( | |
expected_matrix - sample_matrix(test_circ, test_degree, 1) | |
).all() <= 1e-3 | |
assert np.allclose(expected_matrix, sample_matrix(test_circ, test_degree, 1), atol=1e-3) |
I don't think the test, as currently written, is testing what is intended. Calling .all
on a numpy array returns a boolean indicating whether all the values of the array are truthy. Currently things are passing because expected_matrix
is exactly equal to the output of sample_matrix
, meaning the array is all 0's. The .all
call then returns False
and False <= 1e-3
evaluates to True.
The right output, but incorrect path to get there.
Other tests need to be reworked to fix this as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching this!
Apparently, the two failures I noticed in #2447 (comment) were related to this.
Because the tests passed, I thought there was a float addition error. I will work on finding a way around the for
block where I was copying the array.
@pytest.mark.parametrize( | ||
"test_num_layers, test_degree", | ||
[(1, 1), (2, 2), (3, 2), (10, 4)], | ||
# Note need to add (100, 2) here. This makes the unit test very slow. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should either be removed, or we'll need to refactor _full_monomial_basis_term_exponents
to speed it up. If we need to speed it up, what are the largest values it should be performant at?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we'll need to refactor _full_monomial_basis_term_exponents to speed it up
TO DO: I was thinking of leaving this for the immediate future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. Let's finish the full implementation and then come back to it. Please add TODO
to the comment so it's a bit more discoverable.
…nstead of copying np array
for i in range(mat_row): | ||
if i == 0: # first row | ||
new_mat = np.concatenate( | ||
(repl_row, input_sample_matrix[1:]), axis=0 | ||
) | ||
elif i == mat_row - 1: # last row | ||
new_mat = np.concatenate( | ||
(input_sample_matrix[:i], repl_row), axis=0 | ||
) | ||
else: | ||
frst_sl = np.concatenate( | ||
(input_sample_matrix[:i], repl_row), axis=0 | ||
) | ||
sec_sl = input_sample_matrix[i + 1 :] | ||
new_mat = np.concatenate((frst_sl, sec_sl), axis=0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@natestemen @vprusso Does this sound like a better alternative to the previous version where I was copying the sample matrix?
Both of you pointed out memory issues with using .copy()
on a numpy array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems okay from my perspective!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed with @natestemen to revert back to using .copy()
on a numpy array because np.concatenate
might have the same memory issues as .copy()
.
The code is more readable with .copy()
. Will add this as a todo as discussed in #2447 (comment)
+ "the matrix is too large. Consider chunking your" | ||
+ " input circuit. " | ||
) | ||
assert det != 0.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to check whether it's close to 0.0 and add an appropriate debug message in case it is not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed this with @natestemen yesterday. We are coming back to think about edge cases like this once the general LRE implementation is complete.
I'll go ahead and create an issue to log all the todos I need to tackle in the immediate future.
|
||
coeff_list = [] | ||
mat_row, mat_cols = input_sample_matrix.shape | ||
assert mat_row == mat_cols |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar question here as to whether we want to provide more details to the end-user as to what the issue would have been here if this assert fails.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #2447 (comment)
Returns: | ||
List of the evaluated monomial basis terms using the scale factor | ||
vectors. | ||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add error handling?
if degree < 1:
raise ValueError("Degree must be a positive integer")
if fold_multiplier < 1:
raise ValueError("Fold multiplier must be a positive integer")
if num_chunks is not None and num_chunks < 1:
raise ValueError("Number of chunks must be a positive integer")
for i in range(mat_row): | ||
if i == 0: # first row | ||
new_mat = np.concatenate( | ||
(repl_row, input_sample_matrix[1:]), axis=0 | ||
) | ||
elif i == mat_row - 1: # last row | ||
new_mat = np.concatenate( | ||
(input_sample_matrix[:i], repl_row), axis=0 | ||
) | ||
else: | ||
frst_sl = np.concatenate( | ||
(input_sample_matrix[:i], repl_row), axis=0 | ||
) | ||
sec_sl = input_sample_matrix[i + 1 :] | ||
new_mat = np.concatenate((frst_sl, sec_sl), axis=0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems okay from my perspective!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved, but a few small cleanup things to do before merging!
Well done with this Purva!
We assume the terms in the monomial basis are arranged in a graded | ||
lexicographic order such that the terms with the highest total degree are | ||
considered to be the largest and the remaining terms are arranged in | ||
lexicographic order. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the ordering we are using here is some sort of anti-lexicographic ordering within each "grade". E.g. with grade = 1, in lexicographic ordering 10
comes after 01
since 0
comes before 1
. Maybe it's "graded reverse lexicographic ordering"?\
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
raded reverse lexicographic ordering
No, this would be a different order. See section I of https://pi.math.cornell.edu/~dmehrle/notes/old/alggeo/07MonomialOrdersandDivisionAlgorithm.pdf
In the graded lexicographic order, the highest total degree is the largest along with the requirements of the lexicographic order which considers the difference between the exponents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, so I think all the confusion boils down to a potential confusion in convention.
A tuple of exponents
If we are working in the second convention (which seems a bit strange to me1) then I think everything is correct. In my head, I was previously working with the former convention which means the graded lexicographic ordering on monomials with two terms and maximum degree two (
whereas the latter convention reads
The latter convention indeed yields what is currently implemented.
So the question is does
Footnotes
-
It's convention, though, not gospel, so 🤷🏻. ↩
# verify the matrix is square | ||
mat_row, mat_cols = sample_matrix.shape | ||
assert mat_row == mat_cols |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We typically use tests for this type of thing. Is there a reason we should have this assert
in the code here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am making my way through Dan Bader's 'Python Tricks: The Book' to help me write better code. He recommends using assertions like this.
Co-authored-by: nate stemen <[email protected]>
Co-authored-by: nate stemen <[email protected]>
Description
Fixes #2372
To Dos
License
Before opening the PR, please ensure you have completed the following where appropriate.