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

Add terms kwarg to irreducible and primitive poly functions #463

Merged
merged 7 commits into from
Jan 22, 2023

Conversation

mhostetter
Copy link
Owner

@mhostetter mhostetter commented Jan 17, 2023

Implements #458.

Examples

In [1]: import galois

In [2]: galois.irreducible_poly(7, 3)
Out[2]: Poly(x^3 + 2, GF(7))

In [3]: galois.irreducible_poly(7, 3, terms=3)
Out[3]: Poly(x^3 + x + 1, GF(7))

In [4]: galois.primitive_poly(7, 3)
Out[4]: Poly(x^3 + 3x + 2, GF(7))

In [5]: galois.primitive_poly(7, 3, terms=4)
Out[5]: Poly(x^3 + x^2 + x + 2, GF(7))
In [1]: import galois

In [2]: list(galois.primitive_polys(3, 5))
Out[2]: 
[Poly(x^5 + 2x + 1, GF(3)),
 Poly(x^5 + 2x^2 + x + 1, GF(3)),       
 Poly(x^5 + x^3 + x + 1, GF(3)),        
 Poly(x^5 + x^3 + 2x^2 + 1, GF(3)),     
 Poly(x^5 + x^3 + 2x^2 + 2x + 1, GF(3)),
 Poly(x^5 + 2x^3 + x^2 + 1, GF(3)),     
 Poly(x^5 + 2x^3 + 2x^2 + x + 1, GF(3)),
 Poly(x^5 + x^4 + 2x + 1, GF(3)),
 Poly(x^5 + x^4 + x^2 + 1, GF(3)),
 Poly(x^5 + x^4 + x^2 + x + 1, GF(3)),
 Poly(x^5 + x^4 + x^3 + x + 1, GF(3)),
 Poly(x^5 + x^4 + x^3 + x^2 + 2x + 1, GF(3)),
 Poly(x^5 + x^4 + x^3 + 2x^2 + x + 1, GF(3)),
 Poly(x^5 + x^4 + 2x^3 + 1, GF(3)),
 Poly(x^5 + x^4 + 2x^3 + x^2 + x + 1, GF(3)),
 Poly(x^5 + x^4 + 2x^3 + 2x^2 + 1, GF(3)),
 Poly(x^5 + 2x^4 + 1, GF(3)),
 Poly(x^5 + 2x^4 + x + 1, GF(3)),
 Poly(x^5 + 2x^4 + 2x^2 + 2x + 1, GF(3)),
 Poly(x^5 + 2x^4 + x^3 + x^2 + x + 1, GF(3)),
 Poly(x^5 + 2x^4 + 2x^3 + 2x + 1, GF(3)),
 Poly(x^5 + 2x^4 + 2x^3 + x^2 + 1, GF(3))]

In [3]: list(galois.primitive_polys(3, 5, terms=4))
Out[3]: 
[Poly(x^5 + 2x^2 + x + 1, GF(3)),
 Poly(x^5 + x^3 + x + 1, GF(3)),
 Poly(x^5 + x^3 + 2x^2 + 1, GF(3)),
 Poly(x^5 + 2x^3 + x^2 + 1, GF(3)),
 Poly(x^5 + x^4 + 2x + 1, GF(3)),
 Poly(x^5 + x^4 + x^2 + 1, GF(3)),
 Poly(x^5 + x^4 + 2x^3 + 1, GF(3)),
 Poly(x^5 + 2x^4 + x + 1, GF(3))]

In [4]: list(galois.primitive_polys(3, 5, terms="min"))
Out[4]: [Poly(x^5 + 2x + 1, GF(3)), Poly(x^5 + 2x^4 + 1, GF(3))]

Examples related to #464

In [1]: import galois

In [2]: galois.primitive_poly(2, 18)
Out[2]: Poly(x^18 + x^5 + x^2 + x + 1, GF(2))

In [3]: galois.primitive_poly(2, 18, terms="min")
Out[3]: Poly(x^18 + x^7 + 1, GF(2))

In [4]: galois.primitive_poly(2, 32)
Out[4]: Poly(x^32 + x^7 + x^5 + x^3 + x^2 + x + 1, GF(2))

In [5]: galois.primitive_poly(2, 32, terms="min")
Out[5]: Poly(x^32 + x^7 + x^6 + x^2 + 1, GF(2))

In [6]: galois.primitive_poly(2, 33)
Out[6]: Poly(x^33 + x^6 + x^4 + x + 1, GF(2))

In [7]: galois.primitive_poly(2, 33, terms="min")
Out[7]: Poly(x^33 + x^13 + 1, GF(2))

In [8]: galois.primitive_poly(2, 34)
Out[8]: Poly(x^34 + x^7 + x^6 + x^5 + x^2 + x + 1, GF(2))

In [9]: galois.primitive_poly(2, 34, terms="min")
Out[9]: Poly(x^34 + x^8 + x^4 + x^3 + 1, GF(2))

@mhostetter mhostetter added the poly Related to polynomials label Jan 17, 2023
@codecov
Copy link

codecov bot commented Jan 17, 2023

Codecov Report

Base: 96.39% // Head: 96.40% // Increases project coverage by +0.01% 🎉

Coverage data is based on head (32de045) compared to base (5e45744).
Patch coverage: 98.71% of modified lines in pull request are covered.

Additional details and impacted files
@@                Coverage Diff                @@
##           release/0.3.x     #463      +/-   ##
=================================================
+ Coverage          96.39%   96.40%   +0.01%     
=================================================
  Files                 43       43              
  Lines               5624     5701      +77     
=================================================
+ Hits                5421     5496      +75     
- Misses               203      205       +2     
Impacted Files Coverage Δ
src/galois/_polys/_poly.py 96.54% <97.22%> (+0.06%) ⬆️
src/galois/_polys/_irreducible.py 100.00% <100.00%> (ø)
src/galois/_polys/_primitive.py 100.00% <100.00%> (ø)

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

@mhostetter
Copy link
Owner Author

@iyanmv can you review this PR and see how you think it'll fit into our plans for #462 and #464?

I'm not 100% happy with it, but pretty happy.

Copy link
Contributor

@iyanmv iyanmv left a comment

Choose a reason for hiding this comment

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

Looks good to me! I will start testing things with the polynomials from the databases.

src/galois/_polys/_irreducible.py Outdated Show resolved Hide resolved
else:
if terms == "min":
terms = _minimum_terms(order, degree, "is_primitive")
poly = _random_search(order, degree, terms)
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe a future improvement for performance is not to use a random search when terms="min"? Or is this the best known algorithm?

Copy link
Owner Author

Choose a reason for hiding this comment

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

Good point.

I struggled a lot getting an efficient iteration through only the polynomials with t non-zero terms. I used combinations and permutations from itertools, but was never able to get the iteration order in precisely lexicographical order. So, instead, I created this recursive algorithm to iterate in lexicographical order.

But now that you mention this, I could resurrect my combinations and permutations code, add an extra shuffle, and iterate through that for the method="random" and fixed-term case. I'll work on that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Probably it's also a good idea to check how people using NTL find these polynomials?

Copy link
Owner Author

Choose a reason for hiding this comment

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

Yes, that could be helpful.

Comment on lines 133 to 141
try:
if method == "min":
poly = next(primitive_polys(order, degree, terms))
elif method == "max":
poly = next(primitive_polys(order, degree, terms, reverse=True))
else:
if terms == "min":
terms = _minimum_terms(order, degree, "is_primitive")
poly = _random_search(order, degree, terms)
Copy link
Contributor

Choose a reason for hiding this comment

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

What do you think about moving the if terms == "min" to the top? I would like to only include the code to search in the database in one place, but as it is, if a user writes, for example, primitive_poly(7, 129, terms="min"), it would still enter the first if method="min".

Copy link
Owner Author

Choose a reason for hiding this comment

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

I have a commit I'm about to push. Can you let me know your suggested change to my latest?

Copy link
Contributor

Choose a reason for hiding this comment

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

As an alternative, you could also change the default value of method to "random" when the user specifies terms="min". What do you think?

Copy link
Owner Author

Choose a reason for hiding this comment

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

This was the kind of thing I had in mind for the database lookup. What are your thoughts?

    try:
        if terms == "min" and method == "min":
            try:
                # Database lookup
                return poly
            except LookupError:
                pass

        if method == "min":
            return next(irreducible_polys(order, degree, terms))
        if method == "max":
            return next(irreducible_polys(order, degree, terms, reverse=True))

        # Random search
        if terms is None:
            return next(_random_search(order, degree, "is_irreducible"))
        if terms == "min":
            terms = _minimum_terms(order, degree, "is_irreducible")
        return next(_random_search_fixed_terms(order, degree, terms, "is_irreducible"))

Copy link
Contributor

Choose a reason for hiding this comment

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

That works too, yes!

Copy link
Owner Author

Choose a reason for hiding this comment

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

Actually, even better is this:

    if terms is "min" and method == "min":
        try:
            # Database lookup
            return poly
        except LookupError:
            pass

    try:
        if method == "min":
            return next(irreducible_polys(order, degree, terms))
        if method == "max":
            return next(irreducible_polys(order, degree, terms, reverse=True))

        # Random search
        if terms is None:
            return next(_random_search(order, degree, "is_irreducible"))
        if terms == "min":
            terms = _minimum_terms(order, degree, "is_irreducible")
        return next(_random_search_fixed_terms(order, degree, terms, "is_irreducible"))

    except StopIteration as e:
        terms_str = "any" if terms is None else str(terms)
        raise RuntimeError(
            f"No monic irreducible polynomial of degree {degree} over GF({order}) with {terms_str} terms exists."
        ) from e

@mhostetter
Copy link
Owner Author

@iyanmv I think this branch is good-to-go. If you agree, I'll merge into release/0.3.x and you can rebase your branches off of that. If you still have requested changes, that's cool too.

@iyanmv
Copy link
Contributor

iyanmv commented Jan 22, 2023

Sure, go ahead!

@mhostetter mhostetter merged commit 0c4386b into release/0.3.x Jan 22, 2023
@mhostetter mhostetter deleted the add-terms-kwarg branch January 22, 2023 20:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
poly Related to polynomials
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants