A+B:-findall(X,(append(X,Y,A),append(Y,X,A)),[_|Z]),length(Z,B).
Experimente online!
Define um predicado +/2
que pega uma string (na forma de uma lista de códigos de caracteres) como seu primeiro argumento ( A
) e define seu segundo argumento ( B
) na ordem da rotação simétrica da ordem mais alta.
Explicação
Este programa usa o fato de que o conjunto de rotações simétricas em uma sequência é um grupo cíclico e, portanto, a ordem do conjunto de rotações simétricas é igual à ordem da rotação simétrica de ordem mais alta. Assim, o programa é capaz de calcular o resultado desejado, localizando o número total de rotações simétricas na sequência de entrada.
Código Explicação
A maior parte do trabalho pesado é feita por uma chamada ao findall/3
predicado. O findall/3
predicado encontra todos os diferentes valores possíveis para o primeiro argumento ( X
neste caso), de modo que a expressão fornecida como segundo argumento seja verdadeira ( (append(X,Y,A),append(Y,X,A))
, mais sobre isso posteriormente). Finalmente, ele armazena cada um desses valores possíveis X
como uma lista no argumento final ( [_|Z]
).
A expressão transmitida findall/3
como a segunda versão, (append(X,Y,A),append(Y,X,A))
usa o append/3
predicado para especificar que X
concatenado com alguns ainda não definidos Y
deve ser igual a A
, a sequência de entrada e que o mesmo Y
concatenado X
também deve ser igual a A
. Isso significa que X
deve haver algum prefixo para A
que, se for removido da frente A
e adicionado à parte traseira, a sequência resultante seja a mesma que A
. O conjunto de X
s com essa propriedade tem quase uma correspondência individual com as rotações simétricas de A
. Sempre há exatamente um caso de contagem dupla causado pelo fato de que a cadeia vazia e A
os prefixos deA
que correspondem à rotação 0 de A
. Como a 0
rotação de A
é sempre simétrica, o comprimento da lista resultante de X
s findall/3
será um maior que o número de rotações simétricas ativadas A
.
Para resolver o problema da contagem dupla, utilizo a correspondência de padrões no terceiro argumento do findall/3
predicado. No Prolog, as listas são representadas como pares de cabeça (o primeiro elemento) e cauda (o resto). Assim, [_|Z]
representa uma lista cuja cauda é igual é igual a Z
. Isso significa que o comprimento de Z
é um menor que o número de prefixos encontrados pelo findall/3
predicado e, portanto, igual ao número de rotações simétricas de A
. Finalmente, eu uso o length/2
predicado para definir B
o comprimento de Z
.