Skip to content

Add FroidurePin algorithm#36

Draft
jswent wants to merge 26 commits intomainfrom
add-froidure-pin
Draft

Add FroidurePin algorithm#36
jswent wants to merge 26 commits intomainfrom
add-froidure-pin

Conversation

@jswent
Copy link
Member

@jswent jswent commented Feb 8, 2026

Addresses #32. Opening for visibility, final PR will be rebased when #33 and #35 are merged.

  • add FroidurePinBase binding
  • add FroidurePin<E> template instantiations
  • add high-level FroidurePin julia API

@jswent jswent added this to the v0.0.1 milestone Feb 8, 2026
@jswent jswent added enhancement New feature or request bindings Related to C++ bindings code or C++ <-> Julia interaction algorithms labels Feb 8, 2026
@codecov-commenter
Copy link

codecov-commenter commented Feb 8, 2026

Codecov Report

❌ Patch coverage is 4.97238% with 172 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@2feb9d5). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/froidure-pin.jl 0.00% 138 Missing ⚠️
src/libsemigroups/runner.jl 0.00% 25 Missing ⚠️
src/libsemigroups/word-graph.jl 50.00% 9 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main      #36   +/-   ##
=======================================
  Coverage        ?   49.82%           
=======================================
  Files           ?       10           
  Lines           ?      570           
  Branches        ?        0           
=======================================
  Hits            ?      284           
  Misses          ?      286           
  Partials        ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

note that position, current_position conflicts with Julia Base.*, so we need to reference Semigroups.position, etc. directly
@testset "FroidurePin inherited FroidurePinBase methods" begin
LS = Semigroups.LibSemigroups

t1 = LS.Transf1(StdVector{UInt8}(UInt8[1, 0, 2]))
Copy link
Member

Choose a reason for hiding this comment

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

I think we shouldn't be testing the lower-level stuff, only its higher level equivalents (it is these after all that we want to be used and working). I.e. I think here you are testing the implementation, which might change even if the API doesn't.

Copy link
Member Author

Choose a reason for hiding this comment

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

oops didn't mean to commit these tests. I was going to work on porting test suite from C++/Python tomorrow which will replace this file

# ============================================================================

"""
length(S::FroidurePin) -> Int
Copy link
Member

Choose a reason for hiding this comment

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

This should be called size the name length conflicts with something else. Was there a reason to call it length?

Copy link
Member Author

Choose a reason for hiding this comment

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

Only because overloading Base.length is the standard convention for data structures, but I just looked at Python and saw that there is no overload for len - so I'm assuming you'd rather use size?

# Display
# ============================================================================

function Base.show(io::IO, S::FroidurePin{E}) where {E}
Copy link
Member

Choose a reason for hiding this comment

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

This shouldn't be necessary, use to_human_readable_repr from libsemigroups itself, to avoid code duplication.

Return the 1-based position of `x` in `S`, or `nothing` if not found.
Triggers full enumeration.
"""
function position(S::FroidurePin{E}, x::E) where {E}
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't seem to work as expected:

S = FroidurePin([Transf([1, 1, 2]), Transf([2, 1, 3]), Transf([2, 3, 1])])
julia> position(S, S[10])
ERROR: MethodError: no method matching position(::FroidurePin{Transf{UInt8}}, ::Transf{UInt8})
The function `position` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  position(::Base.JuliaSyntax.ParseState, ::Any...)
   @ Base /private/tmp/julia-20260101-8411-jav5tg/julia-1.12.3/base/JuliaSyntax/src/parser.jl:116
  position(::Base.JuliaSyntax.ParseStream)
   @ Base /private/tmp/julia-20260101-8411-jav5tg/julia-1.12.3/base/JuliaSyntax/src/parse_stream.jl:956
  position(::Base.Filesystem.File)
   @ Base filesystem.jl:348
  ...

Stacktrace:
 [1] top-level scope
   @ REPL[19]:1

not sure why

Copy link
Member Author

@jswent jswent Feb 10, 2026

Choose a reason for hiding this comment

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

Ah yeah I wasn't sure what to do about this so I just left it TBD; should've made a note.

So position is defined in Julia's Base (Base.position) which is designated for IO streams, exporting this function directly causes a conflict. We can overload Base.position so this functionality works, but I was going to do some research first and make sure there aren't any underlying problems since it was designed for separate purpose. I'm assuming this is fine and what I'll end up doing, but wanted to look at some similar packages first.

Right now you can use it by calling Semigroups.position. Or if you want to use it directly you can run:

import Semigroups: position
position(args)

in your repl.

_to_word_0based(word) = StdVector{CxxULong}(CxxULong[w - 1 for w in word])

# Check if C++ returned UNDEFINED and convert to nothing (with +1 shift)
_maybe_undefined(val::UInt32) = is_undefined(val, UInt32) ? nothing : Int(val) + 1
Copy link
Member

Choose a reason for hiding this comment

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

In the python bindings we generally returned UNDEFINED instead of the perhaps more canonical None, this was to make it more similar to the C++ bindings, and to simplify some of the code. If you want to use nothing here instead of UNDEFINED I don't object, just wanted to point out that it should be consistently used everywhere, and that this convention should be recorded somewhere in the CONTRIBUTING.md file.

Copy link
Member Author

Choose a reason for hiding this comment

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

We should discuss tmr and weigh pros/cons. My justification was to keep it as close to Julian convention as possible for easier integration into other libraries, but I'm not attached to it.

"""
FroidurePin(gens::AbstractVector{E}) where {E}

Construct a FroidurePin semigroup from a vector of generators.
Copy link
Member

Choose a reason for hiding this comment

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

I'd really prefer the doc to be copied/generated from the C++ doc rather than partially (and not completely accurately, sorry!) paraphrased here. This will increasingly become an issue the more stuff we add/change/etc.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sorry I should've made a note that the docs are not ready. I'm going to delete and rebuild this after #33 and #35 get merged and write up the full docstrings and update docs site.

Re: generating docs automatically, I looked at it briefly and it seemed it was going to be easier to just copy/paste/edit manually but we can discuss tmr if doing that programmatically would be better for LTS.

Copy link
Member

@james-d-mitchell james-d-mitchell left a comment

Choose a reason for hiding this comment

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

This generally looks amazing, there are one or two persistent issues though:

  • reimplementing things that already exist in libsemigroups in this instance show
  • it'd be good if we could start copying/generating the doc from libsemigroups itself.

@jswent
Copy link
Member Author

jswent commented Feb 10, 2026

@james-d-mitchell sounds good, will make these changes tmr. Does the WordGraph/Runner functionality look okay to you?

@jswent
Copy link
Member Author

jswent commented Feb 10, 2026

Todo list for final PR:

  • Change from Base.length -> size
  • Call to_human_readable_repr for Base.show
  • Overload Base.position
  • Port over test suite from C++/Python
  • Copy and edit docstrings from C++
  • Update docs site algorithms page

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

Labels

algorithms bindings Related to C++ bindings code or C++ <-> Julia interaction enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants