Skip to content

Migrate MapFromFunc from Hecke->AbstractAlgebra#2443

Open
mjrodgers wants to merge 36 commits into
Nemocas:masterfrom
mjrodgers:MapFromFunc
Open

Migrate MapFromFunc from Hecke->AbstractAlgebra#2443
mjrodgers wants to merge 36 commits into
Nemocas:masterfrom
mjrodgers:MapFromFunc

Conversation

@mjrodgers

@mjrodgers mjrodgers commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

(Paired with thofma/Hecke.jl#2290)

As discussed in 6043, there is some motivation to move MapFromFunc from Hecke into AbstractAlgebra, at least partially so that it can be used in GAP.jl/NemoExt (we hope to migrate some of the iso_oscar_gap/iso_gap_oscar functionality to there.

To facilitate this, the following things have been moved:

  • the abstract type HeckeMap,
  • MapFromFunc
  • MapHeader
  • MapCache
    and some related/supporting functions.

We will also move some related tests, and rewrite some code using AbstractAlgebra.map_from_func (which creates a Generic.FunctionalMap) to use MapFromFunc instead.

@mjrodgers

Copy link
Copy Markdown
Contributor Author

Some weird things I am noticing with this:

To some extent, the abstract type HeckeMap and the concrete type MapFromFunc are replacements for the abstract type FunctionalMap and corresponding concrete type Generic.FunctionalMap, although the correspondence is not one-to-one.

The concrete Generic.FunctionalMap is very rarely used, I think only by the old map_from_func which we are in the process of deprecating in favor of MapFromFunc; but it seems like there are some (maybe minor?) limitations, one that I've come across is that if we compose two Generic.FunctionalMap the result still retains the knowledge that it is a functional map (Generic.FunctionalCompositeMap <: FunctionalMap) whereas if we compose two MapFromFuncs then we just get a Generic.CompositeMap.

Anyway, I don't know if this is a big deal at all, but I'm mainly wondering if it would be reasonable or useful to somehow merge the functionalities of HeckeMap and FunctionalMap, or if this would be really really really breaking.

@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.65979% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.13%. Comparing base (e440963) to head (c5bbbe1).
⚠️ Report is 14 commits behind head on master.

Files with missing lines Patch % Lines
src/MapTypes.jl 87.67% 9 Missing ⚠️
src/Map.jl 90.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2443      +/-   ##
==========================================
- Coverage   88.14%   88.13%   -0.02%     
==========================================
  Files         129      130       +1     
  Lines       33017    33113      +96     
==========================================
+ Hits        29104    29185      +81     
- Misses       3913     3928      +15     

☔ View full report in Codecov by Harness.
📢 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.

@thofma

thofma commented Jun 29, 2026

Copy link
Copy Markdown
Member

I think it is fine to get a CompositeMap.

Should we also move map_from_func here?

@mjrodgers

Copy link
Copy Markdown
Contributor Author

I think it is fine to get a CompositeMap.

Should we also move map_from_func here?

I think maybe we should replace the current AA map_from_func with the new version that we use in OSCAR (and my Hecke pull request implements it there, also) - this has a different argument order and return type so is breaking. So first I need to make a pull request to Nemo, that is one of the few places where this old version is being used. (I'll work on this soon).

@thofma

thofma commented Jun 30, 2026

Copy link
Copy Markdown
Member

I think we are breaking anyway, so let's try to do all the breaking stuff at once.

@mjrodgers

Copy link
Copy Markdown
Contributor Author

Sounds good, I'll get the modifications submitted to Nemo and then fix this up to move fully to the new map_from_func

@mjrodgers

Copy link
Copy Markdown
Contributor Author

Some things to consider:

  1. There is some documentation related to FunctionalMap (the generic type) in docs/src/functional_map.md which mentions that we can create a concrete Generic functional map using map_from_func; but now this method returns a MapFromFunc, which is not a subtype of FunctionalMap. I'm a little uncertain how to update this.
  2. There are now two implementations of MapCache (one is Generic.MapCache and the other is newly imported from Hecke), I'm not sure if this creates issues or not. They are slightly different in the number of parameters they take, and the Hecke one also can cache preimages.

The Hecke maps use a MapHeader which has a cache::MapCache field, so maybe 2. isn't a problem; HeckeMap uses the Hecke MapCache, and all other maps (if cached) use Generic.MapCache.

@mjrodgers

mjrodgers commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

I think it is fine to get a CompositeMap.

Should we also move map_from_func here?

I'm testing this with having HeckeMap <: FunctionalMap, there are some weird test failures resulting from composing two MapFromFuncs and getting a Generic.CompositeMap, which the generic image_fn method for functional maps doesn't apply to. Maybe this is a design decision that is overall bad for reasons I am overlooking, but I think it makes sense, the only requirement to be a FunctionalMap is to have an image_fn method which all HeckeMaps have.

EDIT: Having trouble getting this to work, I have Map(MapFromFunc) <: Map(FunctionalMap), but when I try to compose two MapFromFuncs julia uses the generic compose(f::Map, g::Map) instead of compose(f::Map(FunctionalMap){D, U}, g::Map(FunctionalMap){U, C}) like I want...

EDIT2: ooooooh since this code is in Generic this signature for compose only applies to the Generic.FunctionalMap type. Ok, I need to think about what to do here, is it a problem that Generic.CompositeMap does not support image_fn? (If not I can just remove the offending tests, I don't know.) If this is something we need, then I could either make a compose method for two MapFromFunc that either returns a FunctionalCompositeMap, or else replace with a new FromFuncCompositeMap (naming TBD) that would still be a HeckeMap.

Comment thread src/Map.jl
function map_from_func(image_fn::Function, domain, codomain)
return Generic.FunctionalMap(domain, codomain, image_fn)
map_from_func(D, C, image_fn) = MapFromFunc(D, C, image_fn)
map_from_func(D, C, image_fn, inverse_fn) = MapFromFunc(D, C, image_fn, inverse_fn)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How about we provide this for backwards compatibility:

Suggested change
map_from_func(D, C, image_fn, inverse_fn) = MapFromFunc(D, C, image_fn, inverse_fn)
@deprecated map_from_func(image_fn::Function, D, C) = MapFromFunc(D, C, image_fn)

(in the appropriate file)

Comment thread src/MapTypes.jl
#
###############################################################################

mutable struct MapCache{D, C, De, Ce}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It is unfortunate that we also have Generic.MapCache; the similar names may lead to confusion. I actually think the name Generic.MapCache is "wrong" by our modern convention (it should be something like Generic.CacheMap or Generic.CachedMap), but it probably isn't worth the bother to update it -- rather I'd consider ditching it in the not so distant future (but not as part of this PR).

Perhaps we can deprecate the method related to Generic.MapCache sooner, though (so enable_cache, or cached(::Map) etc.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since we are adding MapFromFunc here, I'd also be OK with calling this Generic.MapWithCache... as long as the name clearly conveys "this is a type of Map". (But of course I'd still rather prefer removing it ... ;-) )

Comment thread src/MapTypes.jl
old_im
old_pr

function MapCache(dom::D, cod::C, ::Type{De}, ::Type{Ce}, lim::Int=100) where {D, C, De, Ce}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In Hecke there are function allow_cache! and stop_cache! for all maps with a map header. We could also migrate them here.

Comment thread src/MapTypes.jl
Comment on lines +43 to +46
z = new{D, C}()
z.domain = domain
z.codomain = codomain
return z

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
z = new{D, C}()
z.domain = domain
z.codomain = codomain
return z
return new{D, C}(domain, codomain)

Comment thread src/MapTypes.jl
Comment on lines +50 to +54
z = new{D, C}()
z.domain = domain
z.codomain = codomain
z.image = image
return z

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
z = new{D, C}()
z.domain = domain
z.codomain = codomain
z.image = image
return z
return new{D, C}(domain, codomain, image)

Comment thread src/MapTypes.jl
Comment on lines +58 to +63
z = new{D, C}()
z.domain = domain
z.codomain = codomain
z.image = image
z.preimage = preimage
return z

@fingolfin fingolfin Jul 8, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
z = new{D, C}()
z.domain = domain
z.codomain = codomain
z.image = image
z.preimage = preimage
return z
return new{D, C}(domain, codomain, image, preimage)

Comment thread src/MapTypes.jl
Comment on lines +33 to +34
image
preimage

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
image
preimage
image # function (or other kind of object) used to actually compute images
preimage # function (or other kind of object) used to actually compute preimages

Comment thread src/AbstractTypes.jl

abstract type IdentityMap <: SetMap end

abstract type HeckeMap <: FunctionalMap end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
abstract type HeckeMap <: FunctionalMap end
abstract type HeckeMap <: SetMap end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How about we rename this to MapWithHeader or so?

@thofma opinion?

To make the transition on the Hecke side easier, the Hecke PR thofma/Hecke.jl#2290 could define an alias const HeckeMap = AbstractAlgbra.MapWithHeader ...?

Comment thread src/Map.jl
julia> g = map_from_func(ZZ, QQ, x -> QQ(x));

julia> h = compose(f, g)
Functional composite map

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should just delete FunctionalCompositeMap -- and eventually also Generic.FunctionalMap

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

To get rid of Generic.FunctionalMap we also need to change map_with_preimage_from_func etc. to call map_from_func

Comment thread src/AbstractTypes.jl

abstract type Map{D, C, S, T} <: SetElem end

abstract type SetMap end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
#
# The following types are only used as type parameters for `Map` subtypes
#
abstract type SetMap end

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants