GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
#include "typedef.h"1#include "gmp.h"2#include "longtools.h"3#include "matrix.h"4#include "bravais.h"56/***************************************************************************7@8@ --------------------------------------------------------------------------9@10@ FILE: row_spin.c11@12@ --------------------------------------------------------------------------13@14****************************************************************************/1516static void product_of_stairs(MP_INT *x,MP_INT **A,int rows,int cols)17{18int i,19j;2021mpz_set_si(x,1);2223for (i=0;i<rows;i++){24for (j=0;j<cols && (mpz_cmp_si(A[i]+j,0) ==0);j++);25mpz_mul(x,x,A[i]+j);26}2728mpz_abs(x,x);2930return;31}3233/*************************************************************************34@35@-------------------------------------------------------------------------36@37@ matrix_TYP *row_spin(matrix_TYP *x,matrix_TYP **G,int no,int option)38@39@ The function calculates a basis for the R module <x_i>_RG, where40@ x_i are the rows of x, G is assumed to be generated by the matrices G[i]41@ for 0 <= i <= no, and R is one of the rings Z or Q.42@ NOTE: this function will handle non integral matrices in G[i] as well.43@44@ matrix_TYP *x: see above. x is changed via kgv2rat and long_row_hnf.45@ matrix_TYP **G: see above. It is also changed by rat2kgv for each entry in G.46@ int no : will not be changed.47@ option : drives the behaviour of the function. in case48@ option % 2 == 0 it performs a Z-spinning algorithm,49@ option % 2 == 1 it performs a Q-spinning algorithm,50@ option % 4 == 0 perform a pair_red after spinning51@ the lattice. ONLY IN CONJUNCTION WITH52@ Z-spinning53@-------------------------------------------------------------------------54@55*************************************************************************/56matrix_TYP *row_spin(matrix_TYP *x,matrix_TYP **G,int no,int option)57{58int i,59j,60k,61l,62dim = x->cols,63rows = x->rows,64new_rows;6566matrix_TYP *res;6768long quot;6970MP_INT **A,71**Gram,72**TR,73*merk,74tmp,75prod,76denominator;7778/* check trivialities */79rat2kgv(x);80for (i=0;i<no;i++){81rat2kgv(G[i]);82if (G[i]->cols != dim || G[i]->rows!= dim){83fprintf(stderr,"error in row_spin:\n");84fprintf(stderr,"The %d-th given matrix is %dx%d,\n",85i,G[i]->rows,G[i]->cols);86exit(3);87}88}8990/* inserted tilman 22/07/97 */91long_row_hnf(x);9293/* prepare all the things */94if (x->rows>dim){95A = init_MP_mat(x->rows+1,dim);96}97else{98A = init_MP_mat(dim+1,dim);99}100for (i=0;i<rows;i++)101for (j=0;j<dim;j++)102mpz_set_si(A[i]+j,x->array.SZ[i][j]);103mpz_init(&tmp);104mpz_init_set_ui(&prod,0);105mpz_init_set_si(&denominator,x->kgv);106107for (i=0;i<rows;i++){108for (j=0;j<no;j++){109/* multiply the the i-th row in A with the j-th generator in G,110and stick it in the rows-th row */111for (k=0;k<dim;k++){112mpz_set_si(A[rows]+k,0);113for (l=0;l<dim;l++){114/* A[rows][k] += A[i][l] * G[j]->array.SZ[k][l] */115mpz_set_si(&tmp,G[j]->array.SZ[l][k]);116mpz_mul(&tmp,&tmp,A[i]+l);117mpz_add(A[rows]+k,A[rows]+k,&tmp);118}119}120121/* bare in mind what with the denominator happen */122if (G[j]->kgv != 1 && (option % 2 == 0)){123/* calculate the gcd of the rows-th row of A with G[j]->kgv */124mpz_set_si(&tmp,G[j]->kgv);125for (k=0;k<dim && mpz_cmp_si(&tmp,1)!=0;k++)126mpz_gcd(&tmp,&tmp,A[rows]+k);127128/* divide all entries in the rows-th row of A by this gcd */129if (mpz_cmp_si(&tmp,1) !=0)130for (k=0;k<dim;k++)131mpz_div(A[rows]+k,A[rows]+k,&tmp);132133/* now we have to destinguish two cases, the first (and134good) of which is that G[j]->kgv/tmp == 1, then the135denominator will not be changed. otherwise multiply136denominator by this quotient and multiply the rest of137A by it */138quot = abs(G[j]->kgv/mpz_get_si(&tmp));139if (quot != 1)140for (k=0;k<rows;k++)141for (l=0;l<dim;l++)142mpz_mul_ui(A[k]+l,A[k]+l,(unsigned long) quot);143144mpz_mul_ui(&denominator,&denominator,(unsigned long)quot);145}146147/* apply gauss */148new_rows = MP_row_gauss(A,rows+1,dim);149/* dump_MP_mat(A,new_rows,dim,"A vor"); */150151/* make manhattan as far as feassible */152MP_row_gauss_reverse(A,new_rows,dim,option % 2);153154/* dump_MP_mat(A,new_rows,dim,"A nach");155mpz_out_str(stdout,10,&denominator);156fprintf(stdout,"\n");157fflush(stdout); */158159/* for a Q-spin the dimension is sufficient to describe the space */160if ((option % 2 == 1) && new_rows != rows){161i = 0;162j = 0;163}164165/* for a Z-spin, compare the product of the elements of A166which are stair indices */167if (option == 0){168product_of_stairs(&tmp,A,new_rows,dim);169/* mpz_out_str(stdout,10,&prod);170fprintf(stdout,"\n");171mpz_out_str(stdout,10,&tmp);172fprintf(stdout,"\n");173fflush(stdout); */174if (mpz_cmp_si(&prod,0) == 0 ||175mpz_cmp(&prod,&tmp) != 0 ||176new_rows != rows){177i = 0;178j = 0;179}180mpz_set(&prod,&tmp);181}182183rows = new_rows;184}185}186187/* I like a good basis, so what's up with pair_red */188if (option % 2 == 0 || option % 4 == 0){189/* set the gram matrix */190Gram = init_MP_mat(rows,rows);191for (i=0;i<rows;i++){192for (j=0;j<rows;j++){193for (k=0;k<dim;k++){194/* Gram[i][j] += A[i][k]*A[j][k] */195mpz_mul(&tmp,A[i]+k,A[j]+k);196mpz_add(Gram[i]+j,Gram[i]+j,&tmp);197}198}199}200/* set the transformation matrix and do the pair_red */201TR = init_MP_mat(rows,rows);202for (i=0;i<rows;i++) mpz_set_si(TR[i]+i,1);203MP_pair_red(Gram,TR,rows);204205free_MP_mat(Gram,rows,rows);206Gram = init_MP_mat(rows,dim);207208/* multiply TR with A, stick it to Gram for a moment */209for (i=0;i<rows;i++){210for (j=0;j<dim;j++){211for (k=0;k<rows;k++){212/* Gram[i][j] += TR[i][k] * A[k][j] */213mpz_mul(&tmp,TR[i]+k,A[k]+j);214mpz_add(Gram[i]+j,Gram[i]+j,&tmp);215}216}217}218219/* stick it back to A, and swap the pointers only */220for (i=0;i<rows;i++){221merk = A[i];222A[i] = Gram[i];223Gram[i] = merk;224}225226/* we won't need TR and Gram anymore */227free_MP_mat(TR,rows,rows);228free_MP_mat(Gram,rows,dim);229}230231res = init_mat(rows,dim,"");232write_MP_mat_to_matrix(res,A);233234if (abs(denominator._mp_size>1)){235fprintf(stderr,"denominator in row_spin to large!\n");236fprintf(stderr,"(I thought this to be impossible)\n");237exit(3);238}239240if (option == 0){241res->kgv = mpz_get_si(&denominator);242}243else{244res->kgv = 1;245}246247Check_mat(res);248249/* clear space */250if (x->rows>dim){251free_MP_mat(A,x->rows+1,dim);252}253else{254free_MP_mat(A,dim+1,dim);255}256free(A);257mpz_clear(&tmp);258mpz_clear(&denominator);259260return res;261}262263/**********************************************************************264@ bravais_TYP *representation_on_lattice(matrix_TYP *x,bravais_TYP *G,265@ int option)266@267@268***********************************************************************/269bravais_TYP *representation_on_lattice(matrix_TYP *x,bravais_TYP *G,270int option)271{272273int i,274j;275276bravais_TYP *H;277278matrix_TYP *xtr,279*y,280*z,281**X;282283/* init H as far as possible in this stage */284H = init_bravais(G->dim);285H->gen = (matrix_TYP **) malloc(G->gen_no * sizeof(matrix_TYP *));286H->gen_no = G->gen_no;287288xtr = tr_pose(x);289290for (i=0;i<H->gen_no;i++){291/* map x by the first generator of H */292y = mat_mul(x,G->gen[i]);293z = tr_pose(y);294295/* firstly try to solve the GLS over a prime296p_lse_solve(); */297298/* if this goes wrong, to it the hard way and solve it via Z */299X = long_solve_mat(xtr,z);300301/* paranoia */302if (X[1] != NULL){303if (X[1]->cols!=0){304fprintf(stderr,"error in representation_on_lattice, X[1] wrong\n");305exit(3);306}307free_mat(X[1]);308}309310H->gen[i] = tr_pose(X[0]);311312free_mat(X[0]);313free(X);314free_mat(z);315free_mat(y);316317}318319/* clear up */320free_mat(xtr);321322return H;323}324325/****************************************************************************326@327@----------------------------------------------------------------------------328@329@ matrix_TYP *translation_lattice(matrix_TYP **G,int number,matrix_TYP *P)330@331@ Calculates a basis of the translation lattice of the space group332@ generated by the matrices given in G[i], 0<= i < number.333@ This lattice is returned via a matrix containing the columns of a basis334@ of the lattice (without the affine '1').335@336@ matrix_TYP **G : Generators for the spacegroup.337@ int number : see above338@ matrix_TYP *P : a matrix containing a presentation for the point group339@ to the space group. It has to be a presentation according340@ to the generators G[i], i.e { G[i] * T }/T fullfill341@ the relations given in P.342@343@----------------------------------------------------------------------------344@345*****************************************************************************/346matrix_TYP *translation_lattice(matrix_TYP **G,int number,matrix_TYP *P)347{348349int i,350j,351k,352lcm;353354matrix_TYP **Gtr,355**Ginv,356*B,357*X,358*Y;359360/* check all the trivialities to avoid trouble */361for (i=0;i<number;i++){362rat2kgv(G[i]);363if (G[i]->cols != G[0]->cols ||364G[i]->rows != G[0]->cols){365fprintf(stderr,"uncompatible dimensions in translation_lattice\n");366exit(3);367}368}369370/* init all the needed stuff */371Gtr = (matrix_TYP **) malloc(number * sizeof(matrix_TYP *));372for (i=0;i<number;i++) Gtr[i]=tr_pose(G[i]);373Ginv = (matrix_TYP **) calloc(number , sizeof(matrix_TYP *));374Y = init_mat(P->rows,G[0]->cols-1,"");375376for (i=0;i<P->rows;i++){377X = init_mat(G[0]->cols,G[0]->cols,"1");378for (j=0;j<P->cols;j++){379if (P->array.SZ[i][j] != 0){380if (abs(P->array.SZ[i][j]) > number){381fprintf(stderr,"translation_lattice: you asked for the %d-th"382,P->array.SZ[i][j]);383fprintf(stderr," generator,\n but gave only %d\n",number);384exit(3);385}386387/* the generator should be there */388if (P->array.SZ[i][j] > 0){389mat_muleq(X,G[P->array.SZ[i][j]-1]);390}391else if (P->array.SZ[i][j] < 0){392if (Ginv[-P->array.SZ[i][j]-1] == NULL)393Ginv[-P->array.SZ[i][j]-1] = mat_inv(G[-P->array.SZ[i][j]-1]);394mat_muleq(X,Ginv[-P->array.SZ[i][j]-1]);395}396Check_mat(X);397}398399}400401/* now we should have a trivial linear part in X, and the last402column of X gives a translation */403404/* check whether the linear part is indeed trivial */405rat2kgv(X);406for (j=0;j<X->cols-1;j++){407for (k=0;k<X->rows-1;k++){408if ((k==j && X->array.SZ[k][j] != X->kgv) ||409(k!=j && X->array.SZ[k][j] != 0)){410fprintf(stderr,"translation_lattice: the linear part is not\n");411fprintf(stderr,"trivial. exiting!\n");412exit(3);413}414}415}416417/* stick the resulting translation into Y */418lcm = X->kgv * Y->kgv/ GGT(X->kgv,Y->kgv);419if (lcm != Y->kgv)420for (j=0;j<i;j++)421for (k=0;k<Y->cols;k++)422Y->array.SZ[j][k] *= (lcm/Y->kgv);423424Y->kgv = lcm;425426for (j=0;j<X->rows-1;j++)427Y->array.SZ[i][j] = X->array.SZ[j][X->cols-1] * (lcm/X->kgv);428429free_mat(X);430}431432/* spin these (row) vector by Gtr */433for (i=0;i<number;i++) real_mat(Gtr[i],Gtr[i]->rows-1,Gtr[i]->cols-1);434X = row_spin(Y,Gtr,number,0);435436B = tr_pose(X);437438/* clear all the stuff */439for (i=0;i<number;i++) free_mat(Gtr[i]);440free(Gtr);441for (i=0;i<number;i++) if (Ginv[i] != NULL) free_mat(Ginv[i]);442free(Ginv);443free_mat(X);444free_mat(Y);445446return B;447448}449450451