A+B:-findall(X,(append(X,Y,A),append(Y,X,A)),[_|Z]),length(Z,B).
Try it online!
Defines a predicate +/2
that takes a string (in the form of a list of character codes) as its first argument (A
) and sets its second argument (B
) to the order of the highest order symmetric rotation.
Explanation
This program uses the fact that the set of symmetric rotations on a string are a cyclic group and so the order of the set of symmetric rotations is equal to the order of the highest order symmetric rotation. Thus the program is able to calculate the desired result by finding the total number of symmetric rotations on the input string.
Code Explanation
The majority of the heavy lifting is done by a call to the findall/3
predicate. The findall/3
predicate finds all the different possible values for the first argument (X
in this case) such that the expression given as the second argument is true ((append(X,Y,A),append(Y,X,A))
, more on that later). Finally it stores each of these possible values of X
as a list in the final argument ([_|Z]
).
The expression passed into findall/3
as the second arugment, (append(X,Y,A),append(Y,X,A))
uses the append/3
predicate to specify that X
concatenated with some yet undefined Y
must be equal to A
, the input string, and that the same Y
concatenated with X
must also be equal to A
. This means that X
must be some prefix of A
such that if it is removed from the front of A
and added to the back then the resulting string is the same as A
. The set of X
s with this property almost has a one-to-one correspondence with the symmetric rotations of A
. There is always exactly one case of double counting which is caused by the fact that both the empty string and A
are prefixes of A
that correspond to the 0-rotation of A
. Since the 0
-rotation of A
is always symmetric the length of the resulting list of X
s from findall/3
will be one greater than the number of symmetric rotations on A
.
To solve the double counting problem, I use pattern matching on the third argument of the findall/3
predicate. In Prolog lists are represented as pairs of their head (the first element) and their tail (the rest). Thus [_|Z]
represents a list whose tail is equal is equal to Z
. This means that the length of Z
is one less than the number of prefixes found by the findall/3
predicate and thus equal to the number of symmetric rotations of A
. Finally, I use the length/2
predicate to set B
to the length of Z
.
Related. – Martin Ender – 2017-05-19T10:23:49.617
1
previously asked as a CMC: http://chat.stackexchange.com/transcript/message/37509699#37509699
– John Dvorak – 2017-05-19T10:30:14.597This is the same as finding the number of symmetric rotations smaller than the size of the string. As @0' points out they form a cyclic group so finding the highest order is the same as finding the size of the group. This would make the explanation of the task which is currently pretty unclear much clearer. – Post Rock Garf Hunter – 2018-03-10T17:54:33.477