1 /* nl-matrix.c --- matrix functions for newLISP
3 Copyright (C) 2008 Lutz Mueller
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 /* Since version 8.9.9 all matrix operations work on lists and
21 arrays. Previously only lists where supported.
30 double * * multiply(double ** A
, double ** B
, int m
, int n
, int k
, int l
);
31 double * * invert(double * * A
, int n
, int * err
);
32 int ludcmp(double * * a
, int n
, int * indx
, double * d
);
33 void lubksb(double * * a
, int n
, int * indx
, double * b
);
34 double * * getMatrix(CELL
* params
, int * type
, int * n
, int * m
, int * err
, int evalFlag
);
35 double * * makeMatrix(CELL
* number
, int n
, int m
);
36 int getDimensions(CELL
* mat
, int * n
, int * m
);
37 double * * data2matrix(CELL
* list
, int n
, int m
);
38 CELL
* matrix2data(double * * matrix
, int type
, int n
, int m
);
39 double * * allocateMatrix(int rows
, int cols
);
40 void freeMatrix(double * * m
, int rows
);
42 /* since version 7.4.8 'transpose' tramspose any matrix not only
43 matrices containing numbers.
46 CELL
* p_matTranspose(CELL
* params
)
57 A
= evaluateExpression(params
);
59 if(A
->type
== CELL_ARRAY
)
60 return(arrayTranspose(A
));
62 if(A
->type
!= CELL_EXPRESSION
)
63 return(errorProcExt(ERR_NOT_MATRIX
, params
));
65 if(getDimensions(A
, &n
, &m
) == FALSE
)
66 return(errorProcExt(ERR_NOT_MATRIX
, params
));
69 return(errorProcExt(ERR_WRONG_DIMENSIONS
, params
));
71 Brows
= allocMemory(sizeof(CELL
*) * m
);
72 for(j
= 0; j
< m
; j
++)
74 Brows
[j
] = getCell(CELL_EXPRESSION
);
75 if(j
> 0) Brows
[j
-1]->next
= Brows
[j
];
78 B
= getCell(CELL_EXPRESSION
);
79 B
->contents
= (UINT
)Brows
[0];
81 for(i
= 0; i
< n
; i
++)
84 rowA
= (CELL
*)A
->contents
;
88 if(rowA
->type
!= CELL_EXPRESSION
)
93 for(j
= 0; j
< m
; j
++)
98 cell
= (CELL
*)rowA
->contents
;
101 new = copyCell(cell
);
104 new = copyCell(conCell
);
107 Brows
[j
]->contents
= (UINT
)new;
109 Brows
[j
]->next
= new;
121 CELL
* p_matMultiply(CELL
* params
)
126 int typeX
, typeY
, typeM
;
131 if((X
= getMatrix(params
, &typeX
, &n
, &m
, &err
, TRUE
)) == NULL
)
132 return(errorProcExt(err
, params
));
134 if((Y
= getMatrix(params
->next
, &typeY
, &k
, &l
, &err
, TRUE
)) == NULL
)
137 return(errorProcExt(err
, params
->next
));
140 typeM
= (typeX
== CELL_ARRAY
|| typeY
== CELL_ARRAY
) ? CELL_ARRAY
: CELL_EXPRESSION
;
143 err
= ERR_WRONG_DIMENSIONS
;
144 else if((M
= multiply(X
, Y
, n
, m
, k
, l
)) == NULL
)
145 err
= ERR_NOT_ENOUGH_MEMORY
;
150 if(err
) return(errorProc(err
));
152 C
= matrix2data(M
, typeM
, n
, l
);
158 CELL
* p_matInvert(CELL
* params
)
166 if((A
= getMatrix(params
, &typeA
, &n
, &m
, &err
, TRUE
)) == NULL
)
167 return(errorProcExt(err
, params
));
172 return(errorProcExt(ERR_WRONG_DIMENSIONS
, params
));
175 if( (Y
= invert(A
, n
, &err
)) == NULL
)
178 if(err
) return(errorProc(err
));
182 dataY
= matrix2data(Y
, typeA
, n
, n
);
191 CELL
* p_determinant(CELL
* params
)
195 int typeM
, n
, m
, i
, err
;
198 if( (M
= getMatrix(params
, &typeM
, &m
, &n
, &err
, TRUE
)) == NULL
)
199 return(errorProcExt(err
, params
));
204 return(errorProcExt(ERR_WRONG_DIMENSIONS
, params
));
207 indx
= (int *)calloc((n
+ 1), sizeof(int));
209 if(ludcmp(M
, n
, indx
, &d
) == FALSE
)
212 for(i
= 1; i
<= n
; i
++)
215 return(stuffFloat(&d
));
219 CELL
* p_matScalar(CELL
* params
)
225 int typeA
, typeB
, typeC
= 0;
227 int n
, m
, k
, l
, err
= 0;
231 param
= evaluateExpression(param
);
232 if(param
->type
== CELL_SYMBOL
)
233 type
= *((SYMBOL
*)param
->contents
)->name
;
234 else if(param
->type
== CELL_PRIMITIVE
)
235 type
= *(char *)param
->aux
;
237 return(errorProcExt(ERR_ILLEGAL_TYPE
, params
));
239 params
= params
->next
;
241 if( (A
= getMatrix(params
, &typeA
, &n
, &m
, &err
, TRUE
)) == NULL
)
242 return(errorProcExt(err
, params
));
243 result
= evaluateExpression(params
->next
);
244 if(isNumber(result
->type
))
247 if((B
= makeMatrix(result
, k
, l
)) == NULL
)
249 err
= ERR_NOT_ENOUGH_MEMORY
;
252 typeB
= CELL_EXPRESSION
;
254 else if( (B
= getMatrix(result
, &typeB
, &k
, &l
, &err
, FALSE
)) == NULL
)
257 return(errorProc(err
));
260 typeC
= (typeA
== CELL_ARRAY
|| typeB
== CELL_ARRAY
) ? CELL_ARRAY
: CELL_EXPRESSION
;
263 err
= ERR_WRONG_DIMENSIONS
;
264 else if((M
= allocateMatrix(n
, m
)) == NULL
)
265 err
= ERR_NOT_ENOUGH_MEMORY
;
268 for(k
= 1; k
<= n
; k
++)
269 for(l
= 1; l
<= m
; l
++)
273 case '+': M
[k
][l
] = A
[k
][l
] + B
[k
][l
]; break;
274 case '-': M
[k
][l
] = A
[k
][l
] - B
[k
][l
]; break;
275 case '*': M
[k
][l
] = A
[k
][l
] * B
[k
][l
]; break;
279 return(errorProc(ERR_MATH
));
281 M
[k
][l
] = A
[k
][l
] / B
[k
][l
];
285 return(errorProcExt(ERR_ILLEGAL_TYPE
, params
));
293 if(err
) return (errorProc(err
));
295 result
= matrix2data(M
, typeC
, n
, m
);
302 /* ------------------- C = A*B, A and B unchanged --------------------- */
304 double * * multiply(double ** A
, double ** B
, int n
, int m
, int k
, int l
)
310 if((C
= allocateMatrix(n
, l
)) == NULL
)
315 errorProc(ERR_WRONG_DIMENSIONS
);
319 for(i
= 1; i
<= n
; i
++)
321 for(j
= 1; j
<= l
; j
++)
324 for(s
= 1; s
<= m
; s
++)
325 sum
+= A
[i
][s
] * B
[s
][j
];
335 /* ----- return inverse of A in Y, A will contain LU decomposition --- */
337 double * * invert(double * * A
, int n
, int * err
)
346 col
= (double *)calloc(n
+ 4, sizeof(double));
347 indx
= (int *)calloc((n
+ 1), sizeof(int));
349 if(ludcmp(A
, n
, indx
, &d
) == FALSE
)
352 if((Y
= allocateMatrix(n
, n
)) == NULL
)
354 *err
= ERR_NOT_ENOUGH_MEMORY
;
358 for(j
= 1; j
<= n
; j
++)
360 for(i
= 1; i
<= n
; i
++) col
[i
] = 0.0;
362 lubksb(A
, n
, indx
, col
);
363 for(i
= 1; i
<= n
; i
++) Y
[i
][j
] = col
[i
];
374 /* ------------------------- LU decomposition ---------------------------
375 // algorithms ludcmp() and lubskb() adapted from:
376 // Numerical Recipes in 'C', 2nd Edition
377 // W.H. Press, S.A. Teukolsky
378 // W.T. Vettering, B.P. Flannery
381 int ludcmp(double * * a
, int n
, int * indx
, double * d
)
383 int i
, imax
= 0, j
, k
;
384 double big
, dum
, sum
, temp
;
387 vv
= (double *)calloc(n
+ 4, sizeof(double));
390 /* find abs biggest number in each row and put 1/big in vector */
391 for (i
= 1; i
<= n
; i
++)
394 for(j
= 1;j
<= n
; j
++)
395 if ((temp
= fabs(a
[i
][j
])) > big
) big
= temp
;
406 for (j
= 1; j
<= n
; j
++)
408 for (i
= 1; i
< j
; i
++)
411 for(k
= 1; k
< i
; k
++) sum
-= a
[i
][k
] * a
[k
][j
];
416 for (i
= j
; i
<= n
; i
++)
419 for(k
= 1; k
< j
; k
++)
420 sum
-= a
[i
][k
] * a
[k
][j
];
423 if ( (dum
= vv
[i
] * fabs(sum
)) >= big
)
432 for (k
= 1; k
<= n
; k
++)
435 a
[imax
][k
] = a
[j
][k
];
445 if (a
[j
][j
] == 0.0) a
[j
][j
] = TINY
;
449 dum
= 1.0 / (a
[j
][j
]);
450 for(i
= j
+1; i
<= n
; i
++) a
[i
][j
] *= dum
;
459 void lubksb(double * * a
, int n
, int * indx
, double * b
)
461 int i
, ii
= 0, ip
, j
;
464 for (i
= 1; i
<= n
; i
++)
470 for(j
= ii
; j
<= i
-1; j
++) sum
-= a
[i
][j
] * b
[j
];
476 for (i
= n
; i
>= 1; i
--)
479 for(j
= i
+1; j
<= n
; j
++) sum
-= a
[i
][j
] * b
[j
];
480 b
[i
] = sum
/ a
[i
][i
];
484 /* ------------ make a matrix from list or array expr ----------- */
486 double * * getMatrix(CELL
* params
, int * type
, int * n
, int * m
, int *err
, int evalFlag
)
492 data
= evaluateExpression(params
);
496 if(data
->type
!= CELL_EXPRESSION
&& data
->type
!= CELL_ARRAY
)
498 *err
= ERR_NOT_MATRIX
;
504 if(getDimensions(data
, n
, m
) == FALSE
)
506 *err
= ERR_NOT_MATRIX
;
510 if( (M
= data2matrix(data
, *n
, *m
)) == NULL
)
512 *err
= ERR_NOT_ENOUGH_MEMORY
;
519 double * * makeMatrix(CELL
* number
, int n
, int m
)
526 if(number
->type
== CELL_FLOAT
)
527 s
= *(double *)&number
->aux
;
528 else if(number
->type
== CELL_INT64
)
529 s
= *(INT64
*)&number
->aux
;
531 if(number
->type
== CELL_FLOAT
)
532 s
= *(double *)&number
->contents
;
535 s
= number
->contents
;
537 if((matrix
= allocateMatrix(n
, m
)) == NULL
)
540 for(i
= 1; i
<= n
; i
++)
541 for(j
= 1; j
<= m
; j
++)
547 /* --------------------------- get dimensons or a matrix --------------- */
549 int getDimensions(CELL
* mat
, int * n
, int * m
)
556 if(mat
->type
== CELL_ARRAY
)
558 addr
= (CELL
* *)mat
->contents
;
559 *n
= (mat
->aux
- 1) / sizeof(CELL
*);
561 if(cell
->type
!= CELL_ARRAY
)
563 errorProcExt(ERR_WRONG_DIMENSIONS
, mat
);
566 *m
= (cell
->aux
- 1) / sizeof(CELL
*);
570 /* mat->type is CELL_EXPRESSSION */
572 row
= (CELL
*)mat
->contents
;
573 if(row
->type
!= CELL_EXPRESSION
)
575 errorProcExt(ERR_NOT_MATRIX
, mat
);
579 cell
= (CELL
*)row
->contents
;
582 while(row
!= nilCell
)
588 while(cell
!= nilCell
)
594 if(rows
== 0 || cols
== 0)
596 errorProcExt(ERR_WRONG_DIMENSIONS
, mat
);
607 /* ------------ copy array/list into a matrix of doubles -------- */
610 /* xlate lists or arrays into C arrays with 1-offest for 1st element
611 wrong row type result and missing row elelements result on 0.0 */
612 double * * data2matrix(CELL
* list
, int n
, int m
)
621 if((matrix
= allocateMatrix(n
, m
)) == NULL
)
624 if(list
->type
== CELL_ARRAY
)
626 addr
= (CELL
* *)list
->contents
;
627 for(i
= 1; i
<= n
; i
++)
629 row
= *(addr
+ i
- 1);
630 if(row
->type
!= CELL_ARRAY
)
632 for(j
= 1; j
<= m
; j
++) matrix
[i
][j
] = 0.0;
635 rowAddr
= (CELL
* *)row
->contents
;
636 size
= (row
->aux
- 1)/sizeof(CELL
*);
637 for(j
= 1; j
<= m
; j
++)
640 matrix
[i
][j
] = getDirectFloat((CELL
*)*(rowAddr
+ j
- 1));
641 else matrix
[i
][j
] = 0.0;
647 /* list->type == CELL_EXPRESSION */
649 row
= (CELL
*)list
->contents
;
650 for(i
= 1; i
<= n
; i
++)
652 if(row
->type
!= CELL_EXPRESSION
)
653 for(j
= 1; j
<= m
; j
++) matrix
[i
][j
] = 0.0;
656 cell
= (CELL
*)row
->contents
;
657 for(j
= 1; j
<= m
; j
++)
659 matrix
[i
][j
] = getDirectFloat(cell
);
670 /* ------- allocate an array/list and copy matrix into it ---- */
672 CELL
* matrix2data(double ** matrix
, int type
, int n
, int m
)
682 list
= getCell(type
);
684 if(type
== CELL_EXPRESSION
)
686 row
= getCell(CELL_EXPRESSION
);
687 list
->contents
= (UINT
)row
;
688 for(i
= 1; i
<= n
; i
++)
690 cell
= getCell(CELL_FLOAT
);
691 row
->contents
= (UINT
)cell
;
692 for(j
= 1; j
<= m
; j
++)
696 *(double *)&cell
->aux
= fnum
;
698 *(double *)&cell
->contents
= fnum
;
701 cell
->next
= getCell(CELL_FLOAT
);
705 row
->next
= getCell(CELL_EXPRESSION
);
710 else /* type is CELL_ARRAY */
712 list
->aux
= n
* sizeof(CELL
*) + 1;
713 addr
= (CELL
* *)allocMemory(list
->aux
);
714 list
->contents
= (UINT
)addr
;
716 for(i
= 1; i
<= n
; i
++)
718 cell
= getCell(CELL_ARRAY
);
719 cell
->aux
= m
* sizeof(CELL
*) + 1;
720 rowAddr
= (CELL
* *)allocMemory(cell
->aux
);
721 cell
->contents
= (UINT
)rowAddr
;
722 *(addr
+ i
-1) = cell
;
723 for(j
= 1; j
<= m
; j
++)
726 *(rowAddr
+ j
- 1) = stuffFloat(&fnum
);
735 /* ------------------------ allocate/free a matrix ----------------- */
737 double * * allocateMatrix(int rows
, int cols
)
742 m
= (double **) calloc(rows
+ 1, sizeof(double *));
746 for(i
= 1; i
<= rows
; i
++)
748 m
[i
] = (double *)calloc(cols
+ 1, sizeof(double));
757 void freeMatrix(double * * m
, int rows
)
761 if(m
== NULL
) return;
763 for(i
= 1; i
<= rows
; i
++)