Skip to content

Conversation

@NoureldinYosri
Copy link
Contributor

@NoureldinYosri NoureldinYosri commented Feb 15, 2025

This is the final PR in the series #1554, #1533, and #1516. These PRs implemented the GF($2^n$) multiplication construction from https://arxiv.org/abs/1910.02849v2 which has a toffoli complexity of $n^{\log_2{3}}$

Copy link
Collaborator

@tanujkhattar tanujkhattar left a comment

Choose a reason for hiding this comment

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

Left a round of comments, mainly around the API of the bloqs.

Comment on lines 271 to 272
galois_field: 'galois.FieldArrayMeta'
m_x: Poly = attrs.field(converter=lambda x: x if isinstance(x, Poly) else Poly.Degrees(x))
element_repr: Literal['int', 'poly', 'power'] = attrs.field(default='int', eq=False)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why this change? For users who just want a bloq that can multiply a constant to a GF register, the previous API of specifying a "const" and "galois_field" type was more intuitive. Needing to specify m_x and element_repr explicitly is more verbose. Why do we need this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed

degree: SymbolicInt
irreducible_poly: Optional['galois.Poly'] = attrs.field()
element_repr: Literal["int", "poly", "power"] = attrs.field(default='int')
element_repr: Literal["int", "poly", "power"] = attrs.field(default='int', eq=False)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please add a test to data_types_test.py with examples of which QGF types should be equal and which should be different.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, can you remind me again why we needed to add element_repr to the QGF class in the first place? ]

It looks like its a property of the GF class that can be easily modified by calling gf_type.repr(int). If this is used mainly as a tool for debugging and visualizing the field elements, then its better to not have it as part of the QGF class and simply change the property on the underlying QGF.galois_field type wherever needed.

https://mhostetter.github.io/galois/v0.3.5/api/galois.FieldArray.element_repr/

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed

sub-quadratic Toffoli gate count](https://arxiv.org/abs/1910.02849v2) Section 3.1
"""

m_x: Poly = attrs.field(converter=lambda x: x if isinstance(x, Poly) else Poly.Degrees(x))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please consider taking the galois field type GF everywhere instead of taking Poly type. It makes the API simpler. You could also consider taking the QGF type directly, which encoded all the necessary information about the underlying field and represents the type of the quantum register on which you wish to perform the operations.

The signature of all the bloqs would change to dtype: QGF and other parameters like k: SymbolicInt here and const: const above for multiplication by a constant and dtype: QGF and uncompute: bool for GF2Mul bloq below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

class _GF2MulImpl(Bloq):
"""Multiply two GF2 numbers (or binary polynomials) modulu m(x)."""

m_x: Poly = attrs.field(converter=lambda x: x if isinstance(x, Poly) else Poly.Degrees(x))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Change to dtype: QGF instead

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Comment on lines +773 to +775
Register('f', dtype=self.qgf),
Register('g', dtype=self.qgf),
Register('h', dtype=self.qgf),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Preferably change to x, y, result but it's also fine if you want to leave it as is since it's a private bloq.

Copy link
Contributor Author

@NoureldinYosri NoureldinYosri Mar 25, 2025

Choose a reason for hiding this comment

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

keeping for the private bloq but changed for the public bloq

Comment on lines 752 to 753
class _GF2MulImpl(Bloq):
"""Multiply two GF2 numbers (or binary polynomials) modulu m(x)."""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please add a more detailed docstring if possible. How is this bloq different from GF2Mul below ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Comment on lines 932 to 934
def build_composite_bloq(
self, bb: 'BloqBuilder', f: 'Soquet', g: 'Soquet', h: Optional['Soquet'] = None
) -> Dict[str, 'Soquet']:
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd personally prefer taking a **soqs: 'SoquetT' and simply popping the necessary registers and avoiding the need to use a cast and a dedicated early return based on the if self.uncompute condition.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

g = bb.join(g_arr, self.qgf)
h = bb.join(h_arr, self.qgf)
return {'f': f, 'g': g, 'h': h}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Please implement a build_call_graph to support symbolic cost analysis.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

build_call_graph is already implemented for the public bloq ... this is a private bloq that will never appear to users ... it's used by the public bloq in a add_from statement

@mpharrigan
Copy link
Collaborator

What's the status of this?

@NoureldinYosri
Copy link
Contributor Author

@tanujkhattar ptal, I addressed all of your comments

@mpharrigan I got distracted by other things .. this PR is ready for another reivew

@NoureldinYosri NoureldinYosri merged commit ed6170e into quantumlib:main Mar 31, 2025
8 checks passed
@mpharrigan
Copy link
Collaborator

how long do you expect test_gf2mulmod_classical_action_slow to take

@NoureldinYosri
Copy link
Contributor Author

@mpharrigan I'm almost sure that it wasn't that slow when I wrote it ... anyway #1611

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.

3 participants