Skip to content

Commit

Permalink
Add group actions
Browse files Browse the repository at this point in the history
  • Loading branch information
APJansen committed Jun 18, 2023
1 parent 421e7f9 commit db7cc17
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/GroupsOnGrids.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ include("wallpaper_groups.jl")

include("signals.jl")

include("action.jl")

end
150 changes: 150 additions & 0 deletions src/action.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@

"""
Represents the action of all elements of a group.
# Fields
- `group`: The group that is acting.
- `new_group_axis`: The position of the new group axis.
"""
abstract type GroupAction end

"""
Apply a group action to a grid.
# Arguments
- `ga`: The group action to apply.
- `x`: The grid to act on.
- `axes`: The meaning of the axes of the grid.
# Returns
The grid after the group action has been applied.
"""
function act_on_grid(ga::GroupAction, x::AbstractArray, axes::AxesInfo) end

function (ga::GroupAction)(x::AbstractArray, axes::AxesInfo)
x, axes = lift(x, axes, ga.new_group_axis)
x = act_on_grid(ga, x, axes)
# TODO: acting on group
x
end

#########
# P1
#########
struct P1_action <: GroupAction
group::Group
new_group_axis::Int
end

function P1_action(new_group_axis::Int)
P1_action(P1(), new_group_axis)
end

function act_on_grid(ga::P1_action, x::AbstractArray, axes::AxesInfo)
x
end

#########
# P2
#########
struct P2_action <: GroupAction
group::Group
new_group_axis::Int
end

function P2_action(new_group_axis::Int)
P2_action(P2(), new_group_axis)
end

function act_on_grid(ga::P2_action, x::AbstractArray, axes::AxesInfo)
x_rotated = reverse(x, dims = (axes.width, axes.height))
x = cat(x, x_rotated, dims = ga.new_group_axis)
x
end

#########
# P2MM
#########
struct P2MM_action <: GroupAction
group::Group
new_group_axis::Int
end

function P2MM_action(new_group_axis::Int)
P2MM_action(P2MM(), new_group_axis)
end

function act_on_grid(ga::P2MM_action, x::AbstractArray, axes::AxesInfo)
x = cat(x, reverse(x, dims = axes.height), dims = ga.new_group_axis)
x = cat(x, reverse(x, dims = axes.width), dims = ga.new_group_axis)

x
end

#########
# P4
#########
struct P4_action <: GroupAction
group::Group
new_group_axis::Int
end

function P4_action(new_group_axis::Int)
P4_action(P4(), new_group_axis)
end

function swap_axes(x::AbstractArray, axis1, axis2)
axes = collect(1:ndims(x))
axes[axis1], axes[axis2] = axes[axis2], axes[axis1]
x = permutedims(x, axes)
x
end

function act_on_grid(ga::P4_action, x::AbstractArray, axes::AxesInfo)
x = cat(x, reverse(x, dims = (axes.width, axes.height)), dims = ga.new_group_axis)
x = cat(
x,
reverse(swap_axes(x, axes.width, axes.height), dims = axes.height),
dims = ga.new_group_axis,
)

# put the elements in the right order
order = [1, 3, 2, 4]
indices = ntuple(a -> a == ga.new_group_axis ? order : :, ndims(x))
x = x[indices...]

x
end

#########
# P4M
#########
struct P4M_action <: GroupAction
group::Group
new_group_axis::Int
end

function P4M_action(new_group_axis::Int)
P4M_action(P4M(), new_group_axis)
end

function act_on_grid(ga::P4M_action, x::AbstractArray, axes::AxesInfo)
x = cat(x, reverse(x, dims = axes.width), dims = ga.new_group_axis)
x = cat(x, reverse(x, dims = axes.height), dims = ga.new_group_axis)
x = cat(x, swap_axes(x, axes.width, axes.height), dims = ga.new_group_axis)

# put the elements in the right order
order = [1, 6, 4, 7, 2, 5, 3, 8]
indices = ntuple(a -> a == ga.new_group_axis ? order : :, ndims(x))
x = x[indices...]

x
end

WallpaperActions = [
P1_action,
P2_action,
P2MM_action,
P4_action,
P4M_action,
]
2 changes: 1 addition & 1 deletion src/api.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export Group
export Group, GroupAction
export AxesInfo
export lift
18 changes: 18 additions & 0 deletions test/actiontests.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
function test_action_composition(action::GroupAction, x::AbstractArray, axes::AxesInfo)
group = action.group
g_x = action(x, axes)

# This is when acting two times, first with the element at axis 1, then at axis 2
h_on_g_x = action(g_x, axes)

# Now first compose the group elements, then act once
# flattened list of compositions
h_compose_g = reshape(group.composition, :)
indices = ntuple(a -> a == ndims(g_x) ? h_compose_g : :, ndims(g_x))
h_g_on_x = g_x[indices...]
h_g_on_x = reshape(h_g_on_x, size(g_x)..., group.order)

# Check if the two are equal
print(h_on_g_x .=== h_g_on_x)
@test all(h_on_g_x .=== h_g_on_x)
end
13 changes: 12 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ using Test

include("grouptests.jl")
include("axestests.jl")

include("actiontests.jl")

@testset "GroupsOnGrids.jl" begin
groups = GroupsOnGrids.WallpaperGroups
Expand Down Expand Up @@ -33,4 +33,15 @@ include("axestests.jl")
test_lift()
end

@testset "Testing whether action respects composition..." begin
x = rand(1, 5, 5, 2)
axes = AxesInfo(2, 3, nothing, nothing)
for action in GroupsOnGrids.WallpaperActions
action = action(5)
@testset "... for group action $(action)" begin
test_action_composition(action, x, axes)
end
end
end

end

0 comments on commit db7cc17

Please sign in to comment.