# PositionIndex of isomorphic value

The following example is a simplified version of a problem I am working on:

equivalent[x_, y_] := Mod[x, 7] == Mod[y, 7]


Given a list, say {3, 7, 5} and an integer 21. I need to determine the position of 21 in the list. If I use PositionIndex (which is what I want to use) then the result is

Missing["KeyAbsent", 21]


I need the result to be {2}, i.e. the position of 7 in the list (where 7 is identified with 21 through the equivalence relation).

Is there a way to define PositionIndex up to isomorphism? I.e. so that it returns positions of elements A that are equivalent to list elements B in the list by returning the position of B (for the element A)?

ETA: the result should not depend on the actual value of 7.

So in case the list is {3,14,5} and the element is 21, the result should still be {2}. In the application I cannot assume anything about the integers contained in the list (or the element of which the position in the list needs to be determined). The position should be {2} in case the given element is equivalent to the list element in second position.

• equivalent[x_, y_] := Mod[x - y, 7] == 0; equivclass[x_] := Mod[x, 7, 1]; Position[{3, 7, 5}, equivclass[21]] Commented Jun 9, 2023 at 15:10
• If I understood correctly: Mod[x,7,1] plays on the fact that we know 7 is the first representative. Can it be done so it works for any representative? For instance {3, 21, 5} for the element 14 should yield {2} as well, i.e. it should work for any two equivalent elements (where we cannot assume we know anything specific about the list elements) Commented Jun 9, 2023 at 15:20
• Like this? Position[equivclass/@{3, 21, 5}, equivclass[21]] Commented Jun 9, 2023 at 15:24
• Oh I see! Very cool. Would that blow up matters computation wise? Does not seem to. Much appreciated! I assume that it works for associations too? I will test it on PositionIndex. Yes works perfect, thanks! Commented Jun 9, 2023 at 15:28
• So Mod[x,7] should suffice now as definition of equivclass[x_]. It seems to work fine. Commented Jun 9, 2023 at 15:31

You said you wanted to use PositionIndex, and you show a sample result of Missing["KeyAbsent", 21], so I'm assuming that you're wanting to turn the list into an association that can be queried with a given target key but matching based on an equivalence using Mod for some other integer. Let's say our target modulus is 7 and our target key is 21. We could proceed like this:

posIdx = PositionIndex[{3, 7, 5, 14}];
KeySelect[posIdx, Divisible[21 - #, 7] &]


<|7 -> {2}, 14 -> {4}|>

This maintains the original values, but if that's not useful, then just take the values:

Values[KeySelect[posIdx, Divisible[21 - #, 7] &]]


{{2}, {4}}

You could also have applied the Mod to the list before applying PositionIndex. In either case, we would need to be careful about repeated values. But if you don't actually need to use PositionIndex, then we can get that same result more directly:

Position[{3, 7, 5, 14}, _?(Divisible[21 - #, 7] &)]


Either of these can easily be bundled into a function. I'm confused by why you need PositionIndex, so I'll demonstrate with the second strategy since it's simpler.

PositionByEquivalence[mod_, target_, list_] := Position[list, _?(Divisible[target - #, mod] &)]


With all the arguments explicit like this, now you can use it with any modulus and any target value.

PositionByEquivalence[7, 21, {3, 7, 5, 14}]


{{2}, {4}}

PositionByEquivalence[10, 15, {3, 7, 5, 14}]


{{3}}

equivalent[x_, y_] := Mod[x, 7] == Mod[y, 7]

Position[{3,7,5},x_/;equivalent[x,21],1]

(*  {{2}}  *)


Using SelectPositions by Taliesin Beynon

SelectPositions = ResourceFunction["SelectIndices"];

SelectPositions[Divisible[21 - #, 7] &] @ {3, 7, 5, 14}


{2, 4}

If needed:

List /@ %


{{2}, {4}}