Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 10:34 01 Aug 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Future Matrix Commands>

     Page 1 of 2    
Author Message
toml_12953
Guru

Joined: 13/02/2015
Location: United States
Posts: 442
Posted: 04:02am 16 Jul 2021
Copy link to clipboard 
Print this post

Are there any plans to add the matrix commands for inverting a square matrix and a function to return the determinant? How about MATH READ a() to read a matrix in from DATA statements? I know I can write these functions myself but they'd be a lot faster if built into the language.
 
jirsoft

Guru

Joined: 18/09/2020
Location: Czech Republic
Posts: 533
Posted: 07:55am 16 Jul 2021
Copy link to clipboard 
Print this post

  toml_12953 said  How about MATH READ a() to read a matrix in from DATA statements? I know I can write these functions myself but they'd be a lot faster if built into the language.

I think read matrix from DATA is one-time operation and you will no save too much...
Jiri
Napoleon Commander and SimplEd for CMM2 (GitHub),  CMM2.fun
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 7937
Posted: 08:20am 16 Jul 2021
Copy link to clipboard 
Print this post

I don't like long lists of DATA statements. I always feel "cheated" somehow, as that data is having to take up twice as much memory. It's usually of no real use on its own and has to be read into something. :(
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
toml_12953
Guru

Joined: 13/02/2015
Location: United States
Posts: 442
Posted: 09:35am 16 Jul 2021
Copy link to clipboard 
Print this post

  Mixtel90 said  I don't like long lists of DATA statements. I always feel "cheated" somehow, as that data is having to take up twice as much memory. It's usually of no real use on its own and has to be read into something. :(


Yeah but what are the alternatives? Either type all the data in each time the program is run using INPUT or use an editor to prepare a separate sequential file of data. We have hundreds of DATA statements in our programs so INPUT isn't feasible and the idea having two files that could get separated from each other or get out of sync isn't attractive either.
At least DATA keeps all the data right in the file itself.
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 7937
Posted: 10:04am 16 Jul 2021
Copy link to clipboard 
Print this post

No-one took me up on

RESTORE <variable> :)

which might have made DATA more useful by being able to select the start of data to be read anywhere by changing the value of a variable. It could be the start of a DATA block or by using
RESTORE <variable> : READ x
any individual data statement.

Actually, as I pointed out at the time, in theory all you really need is the address of the DATA pointer in MMBasic. Once you have that you can start by doing a scan of the data statements and PEEK it at recognizable points. Then you can POKE it with the DATA statement number that you want and you have RESTOREd to where you want to be. This was done on the old TRS-80.

You can also use a CSUB as a data store. PEEK its address + an offset and you have the data that you want. Ok when you want numbers, but strings have to be all the same length.
Edited 2021-07-16 20:09 by Mixtel90
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 4311
Posted: 10:21am 16 Jul 2021
Copy link to clipboard 
Print this post

  Mixtel90 said  No-one took me up on

RESTORE <variable> :)



Actually I told you how to do it, on the CMM2, the problem is at the time you were asking how to do it on the Picomite (which doesn't have the EXECUTE command).

EXECUTE "RESTORE " + v$


Best wishes,

Tom
MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
jirsoft

Guru

Joined: 18/09/2020
Location: Czech Republic
Posts: 533
Posted: 10:24am 16 Jul 2021
Copy link to clipboard 
Print this post

  Quote  You can also use a CSUB as a data store. PEEK its address + an offset and you have the data that you want. Ok when you want numbers, but strings have to be all the same length.
You can add information about length to the strings...
Jiri
Napoleon Commander and SimplEd for CMM2 (GitHub),  CMM2.fun
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 7937
Posted: 12:39pm 16 Jul 2021
Copy link to clipboard 
Print this post

EXECUTE is cheating, Tom. ;)

Yep, I was looking for a way to select the different test programs for the PIO assembler (still ongoing). It's no use typing them in as you need them as sometimes things break and you have to check again on another. It's a load of hassle. RESTORE <label> is the best I can manage but it's a bit messy if you want to put a little menu system together (one of my original ideas that got abandoned because I lost interest in it!). No point in writing the assembler on the CMM2 really. It would test run, but development is very easy on the Pico when you can store stuff in flash. Also handy when I can take the PicoMite with me and work on it while I'm looking after my mum three days a week.

True, Jiri. :)
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
William Leue
Guru

Joined: 03/07/2020
Location: United States
Posts: 405
Posted: 04:20pm 16 Jul 2021
Copy link to clipboard 
Print this post

Note that I posted a matrix inversion program some time back. It also includes a determinant. There are several reasons why my BASIC program is not a good substitute for a robust, C-language version in the firmware, however; including speed and the poor numerical stability of the Gaussian Elimination method I use.

-Bill
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10310
Posted: 04:34pm 16 Jul 2021
Copy link to clipboard 
Print this post

  Quote  is not a good substitute for a robust, C-language version in the firmware


Point me at some C source and I might include it. NB this must include proper handling of matrices where inversion is impossible
Edited 2021-07-17 02:40 by matherp
 
William Leue
Guru

Joined: 03/07/2020
Location: United States
Posts: 405
Posted: 04:37pm 16 Jul 2021
Copy link to clipboard 
Print this post

There are a ton of them on the web. Take a look at

www.sanfoundry.com/c-program-find-inverse-matrix/

-Bill
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10310
Posted: 04:43pm 16 Jul 2021
Copy link to clipboard 
Print this post

  Quote  There are a ton of them on the web.


If you want it then you are going to have to do the spade work to qualify the algorithms, prove they work and that they handle edge cases properly. Anyone can google but that doesn't prove anything
 
William Leue
Guru

Joined: 03/07/2020
Location: United States
Posts: 405
Posted: 08:41pm 16 Jul 2021
Copy link to clipboard 
Print this post

  Quote  If you want it then you are going to have to do the spade work to qualify the algorithms, prove they work and that they handle edge cases properly. Anyone can google but that doesn't prove anything



Of course, Peter, but you didn't ask for that in your previous post. I am not an expert in numerical methods, so I will defer to someone else better qualified.

-Bill
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 4311
Posted: 10:31pm 16 Jul 2021
Copy link to clipboard 
Print this post

I got down my copy of "Numerical Recipes in C - The Art of Scientific Computing" (the FORTRAN version is I believe the definitive work on the subject) and had a look at matrix inversion ... either they never intended this book to be read of I am not the intellect I was 25 years ago - they also don't at brief glance discuss the edge cases. No help from me I'm afraid.

Best wishes,

Tom
Edited 2021-07-17 08:32 by thwill
MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
toml_12953
Guru

Joined: 13/02/2015
Location: United States
Posts: 442
Posted: 12:07pm 18 Jul 2021
Copy link to clipboard 
Print this post

  matherp said  
  Quote  is not a good substitute for a robust, C-language version in the firmware


Point me at some C source and I might include it. NB this must include proper handling of matrices where inversion is impossible


Here's a robust version:

#include<stdio.h>
#include<math.h>
#include<conio.h>

float determinant(float[25][25],float);
void cofactor(float[25][25],float);
void transpose(float[25][25],float[25][25],float);

int main()
{
   float matrix[25][25],size,d;
   int i,j;

   printf("\n\n  1 - Size of Matrix : ");
   scanf("%f",&size);
   printf("\n  2 - Enter the elements of the Matrix : \n");
   for (i=0;i<size;i++)>
   {
       for (j=0;j<size;j++)>
       {
            printf("\n\t[ %d , %d ] = ",i,j);
            scanf("%f",&matrix[i][j]);
       }
       printf("\n");
   }
   d=determinant(matrix,size);
   printf("\n\n\tDeterminant of the Matrix = %6.2f",d);
   if (d==0)
   {
       printf("\n\tInverse does not exsist\n\n");
   }
   else
       cofactor(matrix,size);
   getch();
}

/*For calculating Determinant of the Matrix . this function is recursive*/
float determinant(float matrix[25][25],float size)
{
   float s=1,det=0,m_minor[25][25];
   int i,j,m,n,c;
   if (size==1)
   {
       return (matrix[0][0]);
   }
   else
   {
       det=0;
       for (c=0;c<size;c++)>
       {
           m=0;
           n=0;
           for (i=0;i<size;i++)>
           {
               for (j=0;j<size;j++)>
               {
                   m_minor[i][j]=0;
                   if (i != 0 && j != c)
                   {
                      m_minor[m][n]=matrix[i][j];
                      if (n<(size-2))
                         n++;
                      else
                      {
                          n=0;
                          m++;
                      }
                   }
               }
           }
           det=det + s * (matrix[0][c] * determinant(m_minor,size-1));
           s=-1 * s;
       }
   }

   return (det);
}

/*calculate cofactor of matrix*/
void cofactor(float matrix[25][25],float size)
{
    float m_cofactor[25][25],matrix_cofactor[25][25];
    int p,q,m,n,i,j;
    for (q=0;q<size;q++)>
    {
        for (p=0;p<size;p++)>
        {
            m=0;
            n=0;
            for (i=0;i<size;i++)>
            {
                for (j=0;j<size;j++)>
                {
                    if (i != q && j != p)
                    {
                       m_cofactor[m][n]=matrix[i][j];
                       if (n<(size-2))
                          n++;
                       else
                       {
                           n=0;
                           m++;
                       }
                    }
                }
            }
            matrix_cofactor[q][p]=pow(-1,q + p) * determinant(m_cofactor,size-1);
        }
    }
    transpose(matrix,matrix_cofactor,size);
}

/*Finding transpose of cofactor of matrix*/
void transpose(float matrix[25][25],float matrix_cofactor[25][25],float size)
{
    int i,j;
    float m_transpose[25][25],m_inverse[25][25],d;

    for (i=0;i<size;i++)>
    {
        for (j=0;j<size;j++)>
        {
            m_transpose[i][j]=matrix_cofactor[j][i];
        }
    }
    d=determinant(matrix,size);
    for (i=0;i<size;i++)>
    {
        for (j=0;j<size;j++)>
        {
            m_inverse[i][j]=m_transpose[i][j] / d;
        }
    }
    printf("\n\n\tThe inverse of matrix is : \n\n");

    for (i=0;i<size;i++)>
    {
        for (j=0;j<size;j++)>
        {
            printf("\t%3.2f",m_inverse[i][j]);
        }
        printf("\n\n");
    }
}
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10310
Posted: 07:37am 19 Jul 2021
Copy link to clipboard 
Print this post

That code would need significant re-work. Using 25x25 arrays in functions will try and pull c3Kbytes off the stack at each level which will kill the stack on the CMM2 and any other MMBasic variant. Also, using an arbitrary size array is symptomatic of poor programming which doesn't inspire confidence in the rest
Edited 2021-07-19 17:46 by matherp
 
jirsoft

Guru

Joined: 18/09/2020
Location: Czech Republic
Posts: 533
Posted: 08:00am 19 Jul 2021
Copy link to clipboard 
Print this post

I don't remember matrix calculation exactly, but for example determinant is simple iterative operation and here is recursive...
Jiri
Napoleon Commander and SimplEd for CMM2 (GitHub),  CMM2.fun
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10310
Posted: 08:02am 19 Jul 2021
Copy link to clipboard 
Print this post

Note: I will also need test data and results if I am to include anything
 
toml_12953
Guru

Joined: 13/02/2015
Location: United States
Posts: 442
Posted: 01:29pm 19 Jul 2021
Copy link to clipboard 
Print this post

  matherp said  Note: I will also need test data and results if I am to include anything


Here is an even better version with some test data:

#include<stdio.h>
#include<math.h>
float determinant(float [][25], float);
void cofactor(float [][25], float);
void transpose(float [][25], float [][25], float);
int main()
{
 float a[25][25], k, d;
 int i, j;
 printf("Enter the order of the Matrix : ");
 scanf("%f", &k);
 printf("Enter the elements of %.0fX%.0f Matrix : \n", k, k);
 for (i = 0;i < k; i++)
   {
    for (j = 0;j < k; j++)
      {
       scanf("%f", &a[i][j]);
       }
   }
 d = determinant(a, k);

 if (d == 0)
  printf("\nInverse of Entered Matrix is not possible\n");
 else{
  printf("\nDeterminant of Matrix is %4f : ",d);
  cofactor(a, k);}
}

/*For calculating Determinant of the Matrix */
float determinant(float a[25][25], float k)
{
 float s = 1, det = 0, b[25][25];
 int i, j, m, n, c;
 if (k == 1)
   {
    return (a[0][0]);
   }
 else
   {
    det = 0;
    for (c = 0; c < k; c++)
      {
       m = 0;
       n = 0;
       for (i = 0;i < k; i++)
         {
           for (j = 0 ;j < k; j++)
             {
               b[i][j] = 0;
               if (i != 0 && j != c)
                {
                  b[m][n] = a[i][j];
                  if (n < (k - 2))
                   n++;
                  else
                   {
                    n = 0;
                    m++;
                    }
                  }
              }
            }
         det = det + s * (a[0][c] * determinant(b, k - 1));
         s = -1 * s;
         }
   }

   return (det);
}

void cofactor(float num[25][25], float f)
{
float b[25][25], fac[25][25];
int p, q, m, n, i, j;
for (q = 0;q < f; q++)
{
  for (p = 0;p < f; p++)
   {
    m = 0;
    n = 0;
    for (i = 0;i < f; i++)
    {
      for (j = 0;j < f; j++)
       {
         if (i != q && j != p)
         {
           b[m][n] = num[i][j];
           if (n < (f - 2))
            n++;
           else
            {
              n = 0;
              m++;
              }
           }
       }
     }
     fac[q][p] = pow(-1, q + p) * determinant(b, f - 1);
   }
 }
 transpose(num, fac, f);
}
/*Finding transpose of matrix*/
void transpose(float num[25][25], float fac[25][25], float r)
{
 int i, j;
 float b[25][25], inverse[25][25], d;

 for (i = 0;i < r; i++)
   {
    for (j = 0;j < r; j++)
      {
        b[i][j] = fac[j][i];
       }
   }
 d = determinant(num, r);
 for (i = 0;i < r; i++)
   {
    for (j = 0;j < r; j++)
      {
       inverse[i][j] = b[i][j] / d;
       }
   }
  printf("\n\n\nThe inverse of matrix is : \n");

  for (i = 0;i < r; i++)
   {
    for (j = 0;j < r; j++)
      {
        printf("\t%f", inverse[i][j]);
       }
   printf("\n");
    }
}


Test 1: 3 x 3
Enter the elements of 3X3 Matrix :
4 5 1 6 7 2 8 0 4

Determinant of Matrix is 16.000000 :


The inverse of matrix is :
       1.750000        -1.250000       0.187500
       -0.500000       0.500000        -0.125000
       -3.500000       2.500000        -0.125000

Test 2: 3 x 3
Enter the order of the Matrix : 3
Enter the elements of 3X3 Matrix :
0,0,1,1,0,0,0,1,0

Inverse of Entered Matrix is not possible

Test 3: 2 x 2
Enter the order of the Matrix : 2
Enter the elements of 2X2 Matrix :
1,1,1,1

Determinant of Matrix is 0.000000 :


The inverse of matrix is :
       1.000000        -0.000000
       -0.000000       inf   <<< I don't know how you'd want to handle that in BASIC.

Test 4: 1 x 1
Enter the order of the Matrix : 1
Enter the elements of 1X1 Matrix :
5

Determinant of Matrix is 5.000000 :


The inverse of matrix is :
       0.000000

Test 5: 4 x 4
Enter the order of the Matrix : 4
Enter the elements of 4X4 Matrix :
7 9 2 5 0 0 1 1 3 4 -99 .5 12 16 8 -1

Determinant of Matrix is 407.000000 :


The inverse of matrix is :
       4.000000        -22.012285      -0.316953       -2.170762
       -3.000000       16.567568       0.243243        1.689189
       0.000000        0.007371        -0.009828       0.002457
       -0.000000       0.992629        0.009828        -0.002457

What other types of examples would you like to see?
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10310
Posted: 01:47pm 19 Jul 2021
Copy link to clipboard 
Print this post

See the latest PicoMite post.

Your code is still horrid with pre-allocated arrays.

Here is how I do it.

static MMFLOAT* alloc1df (int n)
{
//    int i;
   MMFLOAT* array;
   if ((array = (MMFLOAT*) GetMemory(n * sizeof(MMFLOAT))) == NULL) {
       error("Unable to allocate memory for 1D float array...\n");
       exit(0);
   }

//    for (i = 0; i < n; i++) {
//        array[i] = 0.0;
//    }

   return array;
}

static MMFLOAT** alloc2df (int m, int n)
{
   int i;
   MMFLOAT** array;
   if ((array = (MMFLOAT **) GetMemory(m * sizeof(MMFLOAT*))) == NULL) {
       error("Unable to allocate memory for 2D float array...\n");
       exit(0);
   }

   for (i = 0; i < m; i++) {
       array[i] = alloc1df(n);
   }

   return array;
}

static void dealloc2df (MMFLOAT** array, int m, int n)
{
   int i;
   for (i = 0; i < m; i++) {
       FreeMemorySafe((void *)&array[i]);
   }

   FreeMemorySafe((void *)&array);
}

/*Finding transpose of cofactor of matrix*/
void transpose(MMFLOAT **matrix,MMFLOAT **matrix_cofactor,MMFLOAT **newmatrix, int size)
{
   int i,j;
   MMFLOAT d;
MMFLOAT **m_transpose=alloc2df(size,size);

   for (i=0;i<size;i++)
   {
       for (j=0;j<size;j++)
       {
           m_transpose[i][j]=matrix_cofactor[j][i];
       }
   }
   d=determinant(matrix,size);
   for (i=0;i<size;i++)
   {
       for (j=0;j<size;j++)
       {
           newmatrix[i][j]=m_transpose[i][j] / d;
       }
   }

dealloc2df(m_transpose,size,size);
}
/*calculate cofactor of matrix*/
void cofactor(MMFLOAT **matrix,MMFLOAT **newmatrix,int size)
{
MMFLOAT **m_cofactor=alloc2df(size,size);
MMFLOAT **matrix_cofactor=alloc2df(size,size);
   int p,q,m,n,i,j;
   for (q=0;q<size;q++)
   {
       for (p=0;p<size;p++)
       {
           m=0;
           n=0;
           for (i=0;i<size;i++)
           {
               for (j=0;j<size;j++)
               {
                   if (i != q && j != p)
                   {
                      m_cofactor[m][n]=matrix[i][j];
                      if (n<(size-2))
                         n++;
                      else
                      {
                          n=0;
                          m++;
                      }
                   }
               }
           }
           matrix_cofactor[q][p]=pow(-1,q + p) * determinant(m_cofactor,size-1);
       }
   }
   transpose(matrix, matrix_cofactor, newmatrix, size);
dealloc2df(m_cofactor,size,size);
dealloc2df(matrix_cofactor,size,size);

}
/*For calculating Determinant of the Matrix . this function is recursive*/
MMFLOAT determinant(MMFLOAT **matrix,int size)
{
  MMFLOAT s=1,det=0;
  MMFLOAT **m_minor=alloc2df(size,size);
  int i,j,m,n,c;
  if (size==1)
  {
      return (matrix[0][0]);
  }
  else
  {
      det=0;
      for (c=0;c<size;c++)
      {
          m=0;
          n=0;
          for (i=0;i<size;i++)
          {
              for (j=0;j<size;j++)
              {
                  m_minor[i][j]=0;
                  if (i != 0 && j != c)
                  {
                     m_minor[m][n]=matrix[i][j];
                     if (n<(size-2))
                        n++;
                     else
                     {
                         n=0;
                         m++;
                     }
                  }
              }
          }
          det=det + s * (matrix[0][c] * determinant(m_minor,size-1));
          s=-1 * s;
      }
  }
  dealloc2df(m_minor,size,size);
  return (det);
}
tp = checkstring(cmdline, "M_INVERSE");
if(tp){
void *ptr1 = NULL;
void *ptr2 = NULL;
int i, j, n, numcols=0, numrows=0;
MMFLOAT *a1float=NULL, *a2float=NULL,det;
getargs(&tp, 3,",");
if(!(argc == 3)) error("Argument count");
ptr1 = findvar(argv[0], V_FIND | V_EMPTY_OK | V_NOFIND_ERR);
if(vartbl[VarIndex].type & T_NBR) {
if(vartbl[VarIndex].dims[2] != 0) error("Invalid variable");
if(vartbl[VarIndex].dims[1] <= 0) { // Not an array
error("Argument 1 must be a numerical 2D array");
}
if(vartbl[VarIndex].dims[0] <= 0) { // Not an array
error("Argument 1 must be a numerical 2D array");
}
numcols=vartbl[VarIndex].dims[0] - OptionBase;
numrows=vartbl[VarIndex].dims[1] - OptionBase;
a1float = (MMFLOAT *)ptr1;
if((uint32_t)ptr1!=(uint32_t)vartbl[VarIndex].val.s)error("Syntax");
} else error("Argument 1 must be a numerical 2D array");
ptr2 = findvar(argv[2], V_FIND | V_EMPTY_OK | V_NOFIND_ERR);
if(vartbl[VarIndex].type & T_NBR) {
if(vartbl[VarIndex].dims[2] != 0) error("Invalid variable");
if(vartbl[VarIndex].dims[1] <= 0) { // Not an array
error("Argument 2 must be a numerical 2D array");
}
if(vartbl[VarIndex].dims[0] <= 0) { // Not an array
error("Argument 2 must be a numerical 2D array");
}
if(numcols!=vartbl[VarIndex].dims[0] - OptionBase)error("array size mismatch");
if(numrows!=vartbl[VarIndex].dims[1] - OptionBase)error("array size mismatch");
a2float = (MMFLOAT *)ptr2;
if((uint32_t)ptr2!=(uint32_t)vartbl[VarIndex].val.s)error("Syntax");
} else error("Argument 2 must be a numerical 2D array");
if(numcols!=numrows)error("Array must be square");
n=numrows+1;
MMFLOAT **matrix=alloc2df(n,n);
for(i=0;i<n;i++){ //load the matrix
for(j=0;j<n;j++){
matrix[j][i]=*a1float++;
}
}
det=determinant(matrix,n);
if(det==0.0){
dealloc2df(matrix,numcols,numrows);
error("Determinant of array is zero");
}
MMFLOAT **matrix1=alloc2df(n,n);
cofactor(matrix, matrix1, n);
for(i=0;i<n;i++){ //load the matrix
for(j=0;j<n;j++){
*a2float++=matrix1[j][i];
}
}
dealloc2df(matrix,numcols,numrows);
dealloc2df(matrix1,numcols,numrows);

return;
}


Edited 2021-07-20 01:46 by matherp
 
     Page 1 of 2    
Print this page
The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025