/* MatProduct.c */

#include <stdio.h>

#define DataFile "GraphDataFile2.txt"
#define NN 200    /* maximum number entries = NN-1 */
#define INF 0XEFFFFF

int InputMat2(int*,int*);
void DisplayMat(int*);
int MatProd(int*,int*,int*);

/*
int InputMat2(int*,int*);

/*
int FileToMatA(int*,char*);

void EDITMatAB(int*,char*);
void MatABtoFile(int*,char*);
*/

void main(void)
{
 int K, C[NN], A[NN], B[NN];

/*
 A[] = {304, 3,1,1,4, 5,3,2,1, 6,2,9,5 ,INF},
     B[] = {402, 4,9, 6,8, 9,7, 7,6, INF};
/*
 B[] = {303, 1,2,3, 2,4,6, 1,2,3,INF}, A[] = {303, 1,-1,1, -3,2,-1, -2,1,0,INF};


 A[]={203, 12,73,55,  62,-88,45,INF},
 B[]={302, 89,14, 76,21, 91,-33,INF};
*/

 /*
 puts("Where is the data for the two matrices?");
 puts("If it will be typed in on the (K)eyboard, type K");
 puts("If it is already in the GraphData (F)ile, type F");
INX:
 CH=(char)getchar(); getchar();
 if ((CH=='K') || (CH=='k')) {InputMat2(A,B); goto NXT;}
 if ((CH=='F') || (CH=='f')) {if (FileToMatA(A,NAME)) goto NXT; else goto FIN;}
 puts("Error: enter either K or F");  goto INX;

NXT: 


EDT:
*/

 K=InputMat2(A,B);
 if (!K) goto FIN;
 printf("First matrix %dx%d:\n",A[0]/100,A[0]%100);  DisplayMat(A);
 printf("Second matrix %dx%d:\n",B[0]/100,B[0]%100) ; DisplayMat(B);

 K = MatProd(A,B,C);
 if (K)
  {printf("Product matrix %dx%d:\n",C[0]/100,C[0]%100); DisplayMat(C);}
   else puts("No product matrix");

 /*
 puts("\nChange data?");
 printf(" if YES then press Y key. Pressing any other letter key means NO  ");
 CH = (char)getchar(); getchar();
 if (CH=='y') CH='Y';
 if (CH=='Y') {EDITMatA(A,NAME);  goto EDT;}

 MatAtoFile(A,NAME); */

FIN:
 getchar();
}

/********************** MatProd C = Mat A x Mat B *************************/

int MatProd(int *A, int *B, int *C)
{
 int I,J,K,M1,N1,M2,N2,Sum,   *PP, *P, *Q, *R;  

 M1 = A[0]/100; N1 = A[0]%100;  M2 = B[0]/100; N2 = B[0]%100;

 if (N1 != M2)
  {
   puts("ERROR:");
   puts("First matrix not conformable to second matrix for multiplication");
   return 0;
  }

  PP= &A[1];    C[0] = 100*M1 + N2;  R = &C[1];

 for (I=1; I<=M1; I++)
 {
  for (J=1; J<=N2; J++)
   {
    P=PP; Q=&B[J]; Sum=0;
    for (K=1; K<=N1; K++)
     {
      Sum = Sum + *P**Q;  /*  printf("I=%d J=%d *P=%d *Q=%d\n",I,J,*P,*Q); */
      P++; Q = Q + N2;
     }
   *R = Sum;  R++;          /*    printf("I=%d J=%d Sum = %d\n\n",I,J,Sum); */
   } /* end J */

  PP = PP + N1;

 } /* end I */
 *R = INF;

 return C[0];
}

/*****************************************************************************/

int InputMat2(int *A, int *B)
{
 int I,J,K,M1,N1,M2,N2,   *P,*Q;

INX1:
 puts("Input size of the FIRST matrix (ROWSxCOLUMNS), 0x0 to abort:");
  scanf("%dx%d",&M1,&N1); getchar();
 if ((!M1) && (!N1)) {puts("Matrix input aborted."); return 0;}
 if ((M1<1) || (M1>12) || (N1<1) || (N1>12))
  {puts("ERROR: sizes must be natural numbers between 1 and 12"); goto INX1;}
INX2:
 puts("Input size of the SECOND matrix (ROWSxCOLUMNS), 0x0 to abort:");
  scanf("%dx%d",&M2,&N2); getchar();
  if (N1 != M2)
   {
    puts("Matrices not conformable for multiplication.");
    printf("Number of entries (%d) in rows in first matrix\n",N1);
    puts(" not equal to");
    printf("number of entries (%d) in columns of second matrix\n",M2);
    goto INX1;
   }
 if ((!M2) && (!N2)) {puts("Matrix input aborted."); return 0;}
 if ((M2<1) || (M2>12) || (N2<1) || (N2>12))
  {puts("ERROR: sizes must be natural numbers between 1 and 12"); goto INX2;}

 A[0] = M1*100 + N1;  B[0] = M2*100 + N2;

 puts("Input entries into the FIRST matrix. Press Enter key after each entry");

 P=A; P++;
 for (I=1; I<=M1; I++)
  {
   printf("Prepare to enter %d numbers in row %d\n",N1,I);
   for (J=1; J<=N1; J++)
    {
     if (J==1) puts("first number");
     if ((J>1) && (J<N1)) puts("next number");
     if (J==N1) puts("last number");
     scanf("%d",&K); getchar();
     *P=K; P++;
    }
  }

 *P=INF;

  puts("Input entries into the SECOND matrix. Press Enter key after each entry");

 Q=B; Q++;
 for (I=1; I<=M2; I++)
  {
   printf("Prepare to enter %d numbers in row %d\n",N2,I);
   for (J=1; J<=N2; J++)
    {
     if (J==1) puts("first number");
     if ((J>1) && (J<N2)) puts("next number");
     if (J==N2) puts("last number");
     scanf("%d",&K); getchar();
     *Q=K; Q++;
    }
  }

 *Q=INF;

 return M1*100 + N2;
}

/****************************************************************************/

int FileToMatA(int *A, char *NAME)
{
 FILE *F;   char TITLF[]=DataFile;
 char CH,*S,GrStr[NN];  int I,K,M,N=0,CNT,Sign,   *P;

  if ((F=fopen(TITLF,"r"))==NULL)
    {printf("Cannot find file %s\n",TITLF); return 0;}

     /************* list input-datas already in file ***********/

CH=(char)fgetc(F);

LP2:
 while ((!feof(F)) && (CH != '[')) CH=(char)fgetc(F);     /* find next [ */

 K=0;
 if (!feof(F))
  {
   N++; printf("%d  ",N);
   while (CH != ']') {putchar(CH); CH=(char)fgetc(F);}
   puts("]\n");
   goto LP2;
  }

 INX:
  puts("Input number before the selected data-input (zero to abort):");
  scanf("%d",&K); getchar();
  if (!K) {fclose(F); return 0;}
  if ((K<0) || (K>N)) {printf("Number must be between 1 and %d\n",N); goto INX;}

  rewind(F);

  CH = (char)fgetc(F);
  for (I=1; I<K; I++)
   {
    while (CH != ']') CH = (char)fgetc(F);
   CH = (char)fgetc(F);
  }

  while (CH != '[') CH = (char)fgetc(F);
  S=GrStr;    *S=CH;         /* CH =  [ */
  S++;

  CH = (char)fgetc(F); if ((CH=='m') || (CH=='M')) {*S='M'; S++;}
  else
   {
    puts("Input-array in file not marked 'M' (after '[') for Matrix data");
   return 0;
  }

    /**** Copy character array in file to GrStr ********/

  CH = (char)fgetc(F);
  while (CH!=']') {*S=CH; S++; CH = (char)fgetc(F);}
  *S = CH;
  fclose(F);
  S++; *S='\0';

  puts("Input-data from file is:");
  puts(GrStr);   /* getchar();   /* check data file */

           /*********GrStr to A ******************/

  S=GrStr;

     /* *S='"';  get name */
 I=0; S++;
 while (*S!='"') {NAME[I]=*S; S++; I++;} NAME[I]='\0';

 /* Get Size of matrix */
 while ((*S<'0') || (*S>'9')) S++;
 K=0; while ((*S>='0') && (*S<='9')) {K = 10*K + *S-48; S++;}
 M=K;
 while ((*S<'0') || (*S>'9')) S++;
 K=0; while ((*S>='0') && (*S<='9')) {K = 10*K + *S-48; S++;}
 N=K;

 P=A; *P=100*M + N; P++;

 CNT=M*N;       /* CNT = total number of entries */

 while (CNT)
  {
   while ((*S<'0') || (*S>'9')) S++;
   S--; if (*S=='-') Sign=-1; else Sign=1; S++;
   K=0; while ((*S>='0') && (*S<='9')) {K = 10*K + *S-48; S++;}
   if (Sign==1)*P=K; else *P=-K;  P++;
   CNT--;
  }
 *P=INF;
 return A[0];
}


/*****************************************************************************/
/*
void KBToMatA(int *A, char *NAME)
{
 int I,J,K,M,N,    *P;    char CH,Buf[100];

 puts("Enter name of matrix (less than 10 letters)"); gets(Buf);
 for (I=0; I<10; I++) NAME[I]=Buf[I];   NAME[10]='\0';

INX:
 puts("Enter size of matrix separated by a comma (0,0 termimates input)  ");
 scanf("%d,%d",&M,&N); getchar();
 if ((M>12) || (N>12)) {puts("No size larger than 12"); goto INX;}
 A[0] = 100*M + N;

 P=A; P++;
 for (I=1; I<=M; I++)
  {
   printf("Prepare to enter %d numbers in row %d\n",N,I);
   for (J=1; J<=N; J++)
    {
     if (J==1) puts("first number");
     if ((J>1) && (J<N)) puts("next number");
     if (J==N) puts("last number");
     scanf("%d",&K); getchar();
     *P=K; P++;
    }
  }

 *P=INF;
 return;
}
*/
/*************************** Print A as a Matrix *****************************/

void DisplayMat(int *P)
 {
  int I,J,K,M,N,Max=0,T;    char S1[] = "%1d%2d%3d%4d%5d%6d%7d%8d%9d",S2[3];

  M=*P/100;  N=*P%100;  P++;
  for (I=1; I<=M; I++)
   {
    for (J=1; J<=N; J++)
     {
      if (*P>=0) K=*P; else K=-*P;
      if (K>Max) Max=K;
    }
  }

 T=1; K=1;
 while (T<=Max) {T=T*10; K++;} 
 for (I=0; I<3; I++) S2[I] = S1[3*K+I];  S2[3]='\0';


 for (I=1; I<=M; I++)
   {
    for (J=1; J<=N; J++) {printf(S2,*P); P++;}
    puts("");
  }

 return;
}

/********************** editing adjacency arrays ***************************/
/*
void EDITMatA(int *A, char *NAME)
{

 return;
}
*/
/***************************************************************************/
/*
void MatAtoFile(int *A, char *NAME)
{
 FILE *G;   char TITLG[]=DataFile;
 char *S,GrStr[NN], DigChar[]="0123456789";


 return;
}
*/
/**************************************************************************/

int DET(int *A)
   /*  NN has been defined globally so that NN-1 is the maximum length of
         any permutation (to prevent rollover of counters).
       Receive integer N, 2<=N<NN, and a pointer A to an array of length NN+1;
       The first permutation is odd; after that the odd-even alternate */
{
 int CNT,H,I,J,K,N,PROD,COPY;    int ODD=1,SUM=0;
 int R[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0},
     D[]={1,1,1,1,1,1,1,1,1,1,1,1,1,1},
  PERM[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13};

 N=A[0]%100;

 if (N<2 || N>NN)
  {printf("Input %d  not between limits  2 and %d\n",N,NN); return 0;}
 CNT=1; for (I=1; I<=N; I++) CNT*=I;   /* CNT = N! */

 while (CNT)
  {              /* form a sum of products of N! terms from matrix A */
   K=0; I=N;
  INDEX:      /* but first, construct a new PERMutation from the old one */
     R[I] = J = R[I] + D[I];
     if (J==I) {D[I]=-1; goto LOOP;}
     if (J) goto TRANSPOSE;
     D[I]=1; K++;
  LOOP:
     if (I>2) {I--; goto INDEX;}
     J=1;
  TRANSPOSE:
     J+=K; COPY=PERM[J]; PERM[J]=PERM[J+1]; PERM[J+1]=COPY;
     /* note: odd and even permutations alternate during the generation */

   /* Using permutation PERM form a product PROD of entries from the matrix A */
     PROD=1;
     for (H=1; H<=N; H++) PROD*= A[(H-1)*N + PERM[H]];   /* row H */
    /* PROD = A[1,PERM[I]]* **** * A[N,PERM[N]] */

/*If permutation even, PROD is added to SUM; if odd then -PROD is added */
     if(ODD) SUM-=PROD; else SUM+=PROD;
     ODD=1-ODD;
     CNT--;
  } /* end of while CNT */   
 return SUM;
}


