/* ********************************
"make_canonical.cpp"
標準形の計算に必要な関数−実現部
******************************** */
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
#include "braid.h"
#include "canonical.h"
#include "make_canonical.h"
#include "braid_table.h"
#define SIZE 2304
#define MAX_LEN 15
// Biを求める
void Bi_list(int num,Cell* B[][MAX_LEN]){
List Bi;
B[2][1]=Bi.Init(); // 初期値
int n,i,j;
for(n=3;n<=num;n++){
for(i=1;i<n-1;i++){ // B[n][i]=1...n-1B[n-1][i]
List L;
Cell* p=L.Init();
for(j=1;j<n;j++){
L.Insert(p,j);
p=L.Next(p);
}
List B_dec;
B_dec.Ref_init(B[n-1][i]);
L.Insert(p,B_dec);
B[n][i]=L.Init();
}
for(i=n-1;i<n;i++){ // B[n][i]=n...1n...2...21
List F(n);
fundamental(F);
Cell* p=F.Pre(F.Last());
F.Delete(p);
B[n][i]=F.Init();
}
}
}
// 逆元をBiで置き換え,基本ブレイドを左に集める
int make_positive(List& L){
// 消去できる逆元を消去
Cell* p=L.Pre(L.Last());
do{
if(L.Element(p)<0){
int i=L.Element(p)*(-1);
if(L.Element(L.Pre(p))==i){
Cell* q=L.Pre(p);
Cell* r=L.Next(p);
L.Delete(p);
L.Delete(q);
p=r;
}else if(L.Element(L.Next(p))==i){
Cell* q=L.Next(p);
Cell* r=L.Next(q);
L.Delete(p);
L.Delete(q);
p=r;
}else{
p=L.Pre(p);
}
}else{
p=L.Pre(p);
}
}while(p!=L.Init());
// 逆元を置き換える
Cell* Bi[L.Num()+1][MAX_LEN];
Bi_list(L.Num(),Bi);
p=L.Pre(L.Last());
while(p!=L.Init()){
if(L.Element(p)<0){
int i=L.Element(p)*(-1);
List A; A.Ref_init(Bi[L.Num()][i]);
L.Insert(p,A);
}
p=L.Pre(p);
}
// 基本ブレイドを左に集める
int u=0; // 基本ブレイドの数
p=L.Next(L.Init());
while(p!=L.Last()){
if(L.Element(p)<0){
collect_delta(L,p); u--;
p=L.Pre(p); L.Delete(L.Next(p));
}
p=L.Next(p);
}
return u;
}
// 冗長ブレイドを,前から見て最長の順列ブレイドとその他の部分に分ける
Cell* decomp(List& L,Cell* p,Cell* hl){
int i,j;
Cell* q;
// Lのpからhlまでを配列に格納
int B[MAX_LEN];
q=p; i=0;
while(q!=L.Next(hl)){
B[i]=L.Element(q);
q=L.Next(q); i++;
}
int len=i;
// 入力されたブレイドを探す
int index;
for(i=0;i<SIZE;i++){
for(j=0;j<len;j++){
if(B[j]!=R[len][i][j]) break;
}
if(j==len){ index=i; break; }
}
// Lを更新
q=p; j=0;
int crs=0;
Cell* hl_new;
while(q!=L.Next(hl)){
L.Set_element(q,M[len][index][j]);
crs++;
if(crs==N[len][index]) hl_new=q;
q=L.Next(q); j++;
}
return hl_new;
}
// 正ブレイドをleft-weightedに分解する
void decomp_head_tail(List& L,Canonical& C){
int i=1;
Cell* head_last=L.Init(); // headの最後
Cell* hl;
do{
hl=L.Pre(L.Last()); Cell* p=hl;;
List H(L.Num());
// headとtailに分解する
do{
H.Insert(H.Init(),L.Element(p));
int judge=judge_braid(H);
if(judge==1){ // 順列ブレイド
p=L.Pre(p);
}else if(judge==2){ // 基本ブレイド
// Δを左に集める
Cell* q=L.Next(hl);
int u=C.Delta(); u++; C.Set_delta(u);
collect_delta(L,p);
L.Delete(p,hl);
H.Clear();
// lastからやり直す
hl=L.Pre(L.Last());
p=hl;
/*
if(L.Pre(q)==head_last){
// lastからやり直す
hl=L.Pre(L.Last());
p=hl;
}else{
// 1つ前の順列ブレイドからやり直す
List T(L.Num());
while(q!=L.Last()){
T.Insert(T.Init(),L.Element(q));
if(judge_braid(T)==3) break;
q=L.Next(q);
}
hl=L.Pre(q);
p=hl;
}
*/
}else{ // 冗長ブレイド
hl=decomp(L,p,hl);
H.Clear();
p=hl;
}
}while(p!=head_last);
head_last=hl; // head確定 -> tailに対して処理を繰り返す
}while(head_last!=L.Pre(L.Last()));
C.Set_length(i-1);
C.Set_glist(L);
}
// canonical formを構成する
void make_canonical(List& L,Canonical& C){
Cell* p;
int u;
// 紐の本数>2のとき
if(L.Num()>2){
C.Set_num(L.Num());
// リストが空でないとき
if(L.Empty()!=true){
// 逆元を置き換える
u=C.Delta();
u+=make_positive(L);
C.Set_delta(u);
// リストが空でないとき,left-weightedに分割
if(L.Empty()!=true) decomp_head_tail(L,C);
}else{
puts("List is empty.");
}
}else{
puts("Number of strings is smaller than 3.");
}
}