How to resolve the algorithm Cycles of a permutation step by step in the Julia programming language
How to resolve the algorithm Cycles of a permutation step by step in the Julia programming language
Table of Contents
Problem Statement
On the event of their marriage, Alf and Betty are gifted a magnificent and weighty set of twenty-six wrought iron letters, from A to Z, by their good friends Anna and Graham. Alf and Betty have, in their home, a shelf sturdy enough to display their gift, but it is only large enough to hold fifteen of the letters at one time. They decide to select fifteen of the letters and rearrange them every day, as part of their daily workout, and to select a different set of letters from time to time, when they grow bored of the current set. To pass the time during their honeymoon, Alf and Betty select their first set of letters and find seven arrangements, one for each day of the week, that they think Anna and Graham would approve of. They are:
They decide to write down instructions for how to rearrange Monday's arrangement of letters into Tuesday's arrangement, Tuesday's to Wednesday's and so on, ending with Sunday's to Monday's.
However, rather than use the letters, they number the positions on the shelf from 1 to 15, and use those position numbers in their instructions. They decide to call these instructions "permutations".
So, for example, to move from the Wednesday arrangement to the Thursday arrangement, i.e.
they would write the permutation as:
(i.e. The D that is in position 1 on Thursday stayed in position 1, the I that is in position 2 on Thursday came from position 4, the T in position 3 came from position 7, and so on.)
They decide to call this "two-line notation", because it takes two lines to write it down. They notice that the first line is always going to be the same, so it can be omitted, and simplify it to a "one-line notation" that would look like this:
As a subtle nuance, they figure out that when the letters at the right hand end don't move, they can safely leave them off the notation. For example, Mon and Tue both end with T, so for Mon->Tue the one-line notation would be fourteen numbers long rather than fifteen.
Then they notice that the letter at position 9 moves to position 12, the letter at position 12 moves to position 13, and the letter at position 13 moves to position 9, forming the cycle 9->12->13->9->12->13-> etc., which they decide to write as (9 12 13). They call this a 3-cycle, because if they applied the cycle to the letters in those positions three times, they would end up back in their original positions.
They also notice that the letters in positions 1 and 6 do not move, so they decide to not write down any of the 1-cycles (not just the ones at the end as with the one-line notation.) They also decide that they will always write cycles starting with the smallest number in the cycle, and that when they write down the cycles in a permutation, the will be sorted by the first number in the permutation, smallest first.
The permutation Wed->Thur has a 10-cycle starting at position 2, a 3-cycle starting at position 9 and two 1-cycles (at positions 1 and 6), so they write down:
They decide to call this "cycle notation". (By pure coincidence all the names they have chosen are the same as those used by mathematicians working in the field of abstract algebra. The abstract algebra term for converting from one-line notation to cycle notation is "decomposition". Alf and Betty probably wouldn't have thought of that. 1-cycles, 2-cycles, 3-cycles et cetera are collectively called k-cycles. 2-cycles are also called transpositions. One more piece of terminology: two or more cycles are disjoint if they have no elements in common. The cycles of a permutation written in cycle notation are disjoint.)
Alf and Betty notice that they can perform the first k-cycle as a series of transpositions, swapping the letters in positions 14 and 4, then the letters in positions 5 and 14, then 15 and 5, then 10 and 15 and so on, ending with swapping the letters in positions 4 and 2.
Then it occurs to them that it would be more efficient if one of them took the letter in position 8 and held it while the other moved the letter in position 7 and moved it to position 8, then moved 3 to 7, 11 to 3 and so on. Finally the one who had been holding the letter from position 8 could put it in position 2.
Computer programmers would call this an "in-place" solution. The one and two-line notations lend themselves to a not-in-place solution, i.e., having a second shelf that they could conveniently move they letters to while rearranging them.
If they accidentally did the Wed->Thu permutation on the wrong day of the week they would end up with a jumble of letters that they would need to undo using a Thu->Wed permutation. Mathematicians would call this the inverse of Wed->Thu.
They could do this in two-line notation by swapping the top and bottom lines and calculating the one-line notation result.
(To perform the calculation: The 1 in the top line has a 1 below it, so 1 goes in the first position in the result. The 2 in the second line has an 4 above it, so write 2 in the fourth position in the result. Th 3 in the second line has a seven above it, so write 3 in the seventh position in the result and so on.)
Or they could use cycle notation. To invert a cycle, reverse the order of the numbers in it. To maintain the convention that cycles start with the smallest number in the cycle, move the first number in the cycle to the end before reversing. So (9 13 12) -> (13 12 9) -> (9 12 13). Do this for every cycle.
If Alf and Betty went to visit Anna and Graham on a Wednesday and came home on a Friday, they'd need to figure out the permutation Wed->Fri from the permutations Wed->Thu and Thu->Fri. Mathematicians call this either composition or multiplication, and if A is the notation for Wed->Thu and B is the notation for Thu->Fri, they would write it as BA or B∙A. It may seem backwards, but that's they way mathematicians roll.
Note that B∙A will NOT give the same result as A∙B – unlike regular multiplication of numbers, this sort of multiplication is generally not commutative. (There is an exception to this rule; when two or more cycles are disjoint they can be performed in any order.)
The cycle notation for Thu->Fri is
and the multiplication Thu->Fri∙Wed->Thu gives the result
The order of a permutation is the number of times it needs to be applied for the items being rearranged to return to their starting position, and the signature of a permutation is 1 if an even number of transpositions would be required to do the permutation, and -1 if it required an odd number of permutations.
The order of a permutation is the least common multiple of its cycles' lengths, and the signature is 1 if a permutation has an even number of cycles with an even number of elements, and -1 otherwise.
For a summary of the mathematics discussed here, and a demonstration of the manual method for multiplying permutations in cycle notation, I suggest the Socratica YouTube video Cycle Notation of Permutations - Abstract Algebra.
(Other suitable videos are also available, including the first three parts of this YouTube playlist by Dr Angela Berardinelli.)
Wolfram Alpha is useful resource for testing code. If you enter one-line notation wrapped in parentheses and scroll down a little way when it has finished computing, you will find, amongst other things, the cycle decomposition and the inverse permutation. If you enter cycle notation preceded by the word "permutation" it will give the result of multiplying the cycles in all the notations mentioned above as well as the order and signature of the result.
Notes:
Alf and Betty chose to represent one-line notation as space delimited numbers without enclosing parentheses, brackets or braces. This representation is not mandated. If it is more convenient to, for example, use comma delimitation and enclosing braces, then do so. Similar considerations apply to their choice of representations for cycles and the cycles of a permutation. State which representations your solution uses.
Their choice of orderings for cycle notation (i.e. smallest number first for cycles, cycles sorted in ascending order by first number) is not mandated. If your solution uses a different ordering, describe it.
Similarly, right-to-left evaluation of cycle multiplication as composition of functions is not mandated. Show how Thu->Fri∙Wed->Thu would be written in your solution.
Alf and Betty's system is one-based. If a zero-based system is more appropriate, then use that, but provide the means (e.g. one or more functions, procedures, subroutines, methods, or words, et cetera) to allow conversion to and from zero-based and one-based representations so that user I/O can be one-based. State if this is the case in your solution.
Their choice of orderings for cycle notation (i.e. smallest number first for cycles, cycles sorted in ascending order by first number) is not mandated. If your solution uses a different ordering, describe it.
Their choice of omitting trailing 1-cycles in one-line notation and all 1-cycles in cycle-notation is not mandated. Include 1-cycles in either notation if you prefer.
Other names exist for some of the terms used in this task. For example, the signature is also known as the sign or parity. Use whichever terms you are comfortable with, but make it clear what they mean.
Data validation is not required for this task. You can assume that all arguments and user inputs are valid. If you do include sanity checks, they should not be to the detriment of the legibility of your code.
If the required functionality is available as part of your language or in a library well known to the language's user base, state this and consider writing equivalent code for bonus points.
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Cycles of a permutation step by step in the Julia programming language
The provided Julia code defines a Perm
struct and various functions for working with permutations. Here's a detailed explanation:
-
Perm
Struct:- Represents a permutation as a one-line form. It stores a
Vector{Int}
a
, wherea[i]
indicates the position ofi
in the permutation. - The constructor
Perm(arr)
takes a vector of integers and checks if it's a permutation of the range1:length(arr)
.
- Represents a permutation as a one-line form. It stores a
-
Creating a
Perm
from Cycle Vectors:- The function
Perm(cycles; addsingles=true)
constructs aPerm
from a vector of cycle vectors. - Cycles are represented as vectors of integers.
- If
addsingles
is true, single elements not included in any cycle are added as singleton cycles.
- The function
-
Length of a
Perm
:- The function
length(p::Perm)
returns the length of the permutation, which is the length of thea
vector.
- The function
-
Permutation Signage:
- The function
sign(p::Perm)
calculates the permutation signage. A permutation with even cycle lengths has a signage of 1, and a permutation with odd cycle lengths has a signage of -1.
- The function
-
Permutation Order:
- The function
order(p::Perm)
calculates the order of the permutation, which is the least common multiple (LCM) of the lengths of its cycles.
- The function
-
Perm Composition (Multiplication):
- The multiplication operator
Base.:*
is defined for twoPerm
objects. It composes the two permutations by applying the first permutation followed by the second.
- The multiplication operator
-
Inverse of a
Perm
:- The
inv
function computes the inverse of aPerm
. For each elementi
in the original permutation, the inverse permutation hasa[i]
as its inverse mapping.
- The
-
Getting Permutation Cycles:
- The
permcycles
function extracts the cycles of aPerm
as a vector of integer vectors. - By default, it only includes cycles with more than one element, but setting
includesingles
to true also includes singleton cycles.
- The
-
Printing a
Perm
:- The
print
function forPerm
prints the permutation in cycle notation or optionally in a one-line format. - The
oneline
option prints the permutation as a sequence of numbers in their permuted order, surrounded by square brackets. - The
printsinglecycles
option includes singleton cycles in the cycle notation output. - The
AlfBetty
option assumes the permutation is applied to the letters 'H', 'A', 'N', 'D', 'Y', 'C', 'O', 'I', 'L', 'S', 'E', 'R', 'U', 'P', 'T', and rearranges the letters according to the permutation.
- The
-
Creating a
Perm
from Strings:
- The
Perm(s::AbstractString)
constructor creates aPerm
by finding the unique letters in the strings
and assigning them positions based on their first occurrence in the sorted string. Perm(s1::AbstractString, s2::AbstractString)
creates aPerm
by finding the mapping between the two stringss1
ands2
, effectively permuting the characters ofs1
to matchs2
.
- Permuting a String using a
Perm
:
- The
permutestring(s::AbstractString, p::Perm)
function applies the permutationp
to the strings
and returns the permuted string.
testAlfBettyPerms
Function:
- This function demonstrates the use of
Perm
for a specific scenario involving the names of the days of the week. - It defines day names and strings and creates
Perm
objects representing permutations between them. - It shows how to apply these permutations to rearrange the letters and calculates the permutations' signatures and orders.
Overall, this code provides a comprehensive set of tools for working with permutations in Julia, including creation, manipulation, and visualization. The Perm
struct and its associated functions offer a convenient and versatile way to represent and operate on permutations.
Source code in the julia programming language
""" A Perm is a permutation in one-line form. `a` is a shuffled gapless 1-based range of Int. """
struct Perm
a::Vector{Int}
function Perm(arr::Vector{Int})
if sort(arr) != collect(1:length(arr))
error("$arr must be permutation of 1-based integer range")
end
return new(arr)
end
end
""" Create a Perm from its cycle vectors """
function Perm(cycles::Vector{Vector{Int}}; addsingles = true)
elements = reduce(vcat, cycles)
if addsingles
for elem in filter(x -> !(x in elements), 1:maximum(elements))
push!(cycles, [elem])
push!(elements, elem)
end
end
a = collect(1:length(elements))
sort!(elements) != a && error("Invalid cycles <$cycles> for creating a Perm")
for c in cycles
len = length(c)
for i in 1:len
j, n = c[i], c[mod1(i + 1, len)]
a[j] = n
end
end
return Perm(a)
end
""" length of Perm """
Base.length(p::Perm) = length(p.a)
""" permutation signage for the Perm """
Base.sign(p::Perm) = iseven(sum(c -> iseven(length(c)), permcycles(p))) ? 1 : -1
""" order of permutation for Perm """
order(p::Perm) = lcm(map(length, permcycles(p)))
""" Composition of Perm permutations with the * operator """
function Base.:*(p1:: Perm, p2::Perm)
len = length(p1)
len != length(p2) && error("Permutations must be of same length")
return Perm([p1.a[p2.a[i]] for i in 1:len])
end
""" inverse of a Perm """
function Base.inv(p::Perm)
a = zeros(Int, length(p))
for i in 1:length(p)
j = p.a[i]
a[j] = i
end
return Perm(a)
end
""" Get cycles of a Perm permutation as a vector of integer vectors, optionally with singles """
function permcycles(p::Perm; includesingles = false)
pdict, cycles = Dict(enumerate(p.a)), Vector{Int}[]
for i in 1:length(p.a)
if (j = pop!(pdict, i, 0)) != 0
c = [i]
while i != j
push!(c, j)
j = pop!(pdict, j)
end
push!(cycles, c)
end
end
return includesingles ? cycles : filter(c -> length(c) > 1, cycles)
end
""" Perm prints in cycle or optionally oneline format """
function Base.print(io::IO, p::Perm; oneline = false, printsinglecycles = false, AlfBetty = false)
if length(p) == 0
print(io, "()")
end
if oneline
width = length(string(maximum(p.a))) + 1
print(io, "[ " * prod(map(n -> "$n ", p.a)) * "]")
else
cycles = permcycles(AlfBetty ? inv(p) : p, includesingles = printsinglecycles)
print(io, prod(c -> "(" * string(c)[begin+1:end-1] * ") ", cycles))
end
end
""" Create a Perm from a string with only one of each of its letters """
Perm(s::AbstractString) = Perm([findfirst(==(c), String(sort(unique(collect(s))))) for c in s])
""" Create a Perm from two strings permuting first string to the second one """
Perm(s1::AbstractString, s2::AbstractString) = Perm([findfirst(==(c), s1) for c in s2])
""" Create a permuted string from another string using a Perm """
permutestring(s::AbstractString, p::Perm) = String([s[i] for i in p.a])
function testAlfBettyPerms()
days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
daystrings = ["HANDYCOILSERUPT", "SPOILUNDERYACHT", "DRAINSTYLEPOUCH",
"DITCHSYRUPALONE", "SOAPYTHIRDUNCLE", "SHINEPARTYCLOUD", "RADIOLUNCHTYPES"]
dayperms = [Perm(daystrings[mod1(i - 1, 7)], daystrings[i]) for i in 1:length(days)]
print("On Thursdays Alf and Betty should rearrange\ntheir letters using these cycles: ")
print(stdout, dayperms[4], AlfBetty = true)
println("\n\nSo that $(daystrings[3]) becomes $(daystrings[4])")
print("\nor they could use the one-line notation: ")
print(stdout, dayperms[4]; oneline = true)
print("\n\n\nTo revert to the Wednesday arrangement they\nshould use these cycles: ")
print(stdout, inv(dayperms[4]), AlfBetty = true)
print("\n\nor with the one-line notation: " )
print(stdout, inv(dayperms[4]); oneline = true)
println("\n\nSo that $(daystrings[4]) becomes $(daystrings[3])")
println("\n\nStarting with the Sunday arrangement and applying each of the daily")
println("permutations consecutively, the arrangements will be:\n")
println(" "^6, daystrings[7], "\n")
for i in 1:length(days)
i == 7 && println()
println(days[i], ": ", permutestring(daystrings[mod1(i - 1, 7)], dayperms[i]))
end
Base.println("\n\nTo go from Wednesday to Friday in a single step they should use these cycles: ")
print(stdout, Perm(daystrings[3], daystrings[5]), AlfBetty = true)
println("\n\nSo that $(daystrings[3]) becomes $(daystrings[5])")
println("\n\nThese are the signatures of the permutations:\n\n Mon Tue Wed Thu Fri Sat Sun")
for i in 1:length(days)
j = i == 1 ? length(days) : i - 1
print(lpad(sign(Perm(daystrings[mod1(i - 1, 7)], daystrings[i])), 4))
end
println("\n\nThese are the orders of the permutations:\n\n Mon Tue Wed Thu Fri Sat Sun")
for i in 1:7
print(lpad(order(dayperms[i]), 4))
end
println("\n\nApplying the Friday cycle to a string 10 times:\n")
pFri, str = dayperms[5], "STOREDAILYPUNCH"
println(" $str\n")
for i in 1:10
str = permutestring(str, pFri)
println(lpad(i, 2), " ", str, i == 9 ? "\n" : "")
end
end
testAlfBettyPerms()
You may also check:How to resolve the algorithm Hello world/Graphical step by step in the Commodore BASIC programming language
You may also check:How to resolve the algorithm Partition an integer x into n primes step by step in the D programming language
You may also check:How to resolve the algorithm Loops/Nested step by step in the R programming language
You may also check:How to resolve the algorithm Knapsack problem/Unbounded step by step in the Modula-3 programming language
You may also check:How to resolve the algorithm Convert decimal number to rational step by step in the TI SR-56 programming language