Matrix-exponentiation operator: Difference between revisions
→{{header|Scheme}}: Added some missing functions |
|||
Line 1,905: | Line 1,905: | ||
<lang scheme> |
<lang scheme> |
||
(define (even? n) |
|||
(if (= 0 (remainder n 2)) |
|||
#t |
|||
#f)) |
|||
(define (dec x) |
(define (dec x) |
||
(- x 1)) |
(- x 1)) |
Revision as of 22:47, 21 January 2014
You are encouraged to solve this task according to the task description, using any language you may know.
Most programming languages have a built-in implementation of exponentiation for integers and reals only.
Demonstrate how to implement matrix exponentiation as an operator.
Ada
This is a generic solution for any natural power exponent. It will work with any type that has +,*, additive and multiplicative 0s. The implementation factors out powers A2n: <lang ada>with Ada.Text_IO; use Ada.Text_IO;
procedure Test_Matrix is
generic type Element is private; Zero : Element; One : Element; with function "+" (A, B : Element) return Element is <>; with function "*" (A, B : Element) return Element is <>; with function Image (X : Element) return String is <>; package Matrices is type Matrix is array (Integer range <>, Integer range <>) of Element; function "*" (A, B : Matrix) return Matrix; function "**" (A : Matrix; Power : Natural) return Matrix; procedure Put (A : Matrix); end Matrices;
package body Matrices is function "*" (A, B : Matrix) return Matrix is R : Matrix (A'Range (1), B'Range (2)); Sum : Element := Zero; begin for I in R'Range (1) loop for J in R'Range (2) loop Sum := Zero; for K in A'Range (2) loop Sum := Sum + A (I, K) * B (K, J); end loop; R (I, J) := Sum; end loop; end loop; return R; end "*";
function "**" (A : Matrix; Power : Natural) return Matrix is begin if Power = 1 then return A; end if; declare R : Matrix (A'Range (1), A'Range (2)) := (others => (others => Zero)); P : Matrix := A; E : Natural := Power; begin for I in P'Range (1) loop -- R is identity matrix R (I, I) := One; end loop; if E = 0 then return R; end if; loop if E mod 2 /= 0 then R := R * P; end if; E := E / 2; exit when E = 0; P := P * P; end loop; return R; end; end "**"; procedure Put (A : Matrix) is begin for I in A'Range (1) loop for J in A'Range (1) loop Put (Image (A (I, J))); end loop; New_Line; end loop; end Put; end Matrices; package Integer_Matrices is new Matrices (Integer, 0, 1, Image => Integer'Image); use Integer_Matrices; M : Matrix (1..2, 1..2) := ((3,2),(2,1));
begin
Put_Line ("M ="); Put (M); Put_Line ("M**0 ="); Put (M**0); Put_Line ("M**1 ="); Put (M**1); Put_Line ("M**2 ="); Put (M**2); Put_Line ("M*M ="); Put (M*M); Put_Line ("M**3 ="); Put (M**3); Put_Line ("M*M*M ="); Put (M*M*M); Put_Line ("M**4 ="); Put (M**4); Put_Line ("M*M*M*M ="); Put (M*M*M*M); Put_Line ("M**10 ="); Put (M**10); Put_Line ("M*M*M*M*M*M*M*M*M*M ="); Put (M*M*M*M*M*M*M*M*M*M);
end Test_Matrix;</lang> Sample output:
M = 3 2 2 1 M**0 = 1 0 0 1 M**1 = 3 2 2 1 M**2 = 13 8 8 5 M*M = 13 8 8 5 M**3 = 55 34 34 21 M*M*M = 55 34 34 21 M**4 = 233 144 144 89 M*M*M*M = 233 144 144 89 M**10 = 1346269 832040 832040 514229 M*M*M*M*M*M*M*M*M*M = 1346269 832040 832040 514229
The following program implements exponentiation of a square Hermitian complex matrix by any complex power. The limitation to be Hermitian is not essential and comes for the limitation of the standard Ada linear algebra library. <lang ada>with Ada.Text_IO; use Ada.Text_IO; with Ada.Complex_Text_IO; use Ada.Complex_Text_IO; with Ada.Numerics.Complex_Types; use Ada.Numerics.Complex_Types; with Ada.Numerics.Real_Arrays; use Ada.Numerics.Real_Arrays; with Ada.Numerics.Complex_Arrays; use Ada.Numerics.Complex_Arrays; with Ada.Numerics.Complex_Elementary_Functions; use Ada.Numerics.Complex_Elementary_Functions;
procedure Test_Matrix is
function "**" (A : Complex_Matrix; Power : Complex) return Complex_Matrix is L : Real_Vector (A'Range (1)); X : Complex_Matrix (A'Range (1), A'Range (2)); R : Complex_Matrix (A'Range (1), A'Range (2)); RL : Complex_Vector (A'Range (1)); begin Eigensystem (A, L, X); for I in L'Range loop RL (I) := (L (I), 0.0) ** Power; end loop; for I in R'Range (1) loop for J in R'Range (2) loop declare Sum : Complex := (0.0, 0.0); begin for K in RL'Range (1) loop Sum := Sum + X (K, I) * RL (K) * X (K, J); end loop; R (I, J) := Sum; end; end loop; end loop; return R; end "**"; procedure Put (A : Complex_Matrix) is begin for I in A'Range (1) loop for J in A'Range (1) loop Put (A (I, J)); end loop; New_Line; end loop; end Put; M : Complex_Matrix (1..2, 1..2) := (((3.0,0.0),(2.0,1.0)),((2.0,-1.0),(1.0,0.0)));
begin
Put_Line ("M ="); Put (M); Put_Line ("M**0 ="); Put (M**(0.0,0.0)); Put_Line ("M**1 ="); Put (M**(1.0,0.0)); Put_Line ("M**0.5 ="); Put (M**(0.5,0.0));
end Test_Matrix;</lang> This solution is not tested, because the available version of GNAT GPL Ada compiler (20070405-41) does not provide an implementation of the standard library.
ALGOL 68
File: Matrix_algebra.a68 <lang algol68>INT default upb=3; MODE VEC = [default upb]COSCAL; MODE MAT = [default upb,default upb]COSCAL;
OP * = (VEC a,b)COSCAL: (
COSCAL result:=0; FOR i FROM LWB a TO UPB a DO result+:= a[i]*b[i] OD; result );
OP * = (VEC a, MAT b)VEC: ( # overload vec times matrix #
[2 LWB b:2 UPB b]COSCAL result; FOR j FROM 2 LWB b TO 2 UPB b DO result[j]:=a*b[,j] OD; result );
OP * = (MAT a, b)MAT: ( # overload matrix times matrix #
[LWB a:UPB a, 2 LWB b:2 UPB b]COSCAL result; FOR k FROM LWB result TO UPB result DO result[k,]:=a[k,]*b OD; result );
OP IDENTITY = (INT upb)MAT:(
[upb,upb] COSCAL out; FOR i TO upb DO FOR j TO upb DO out[i,j]:= ( i=j |1|0) OD OD; out
);</lang>File: Matrix-exponentiation_operator.a68 <lang algol68>OP ** = (MAT base, INT exponent)MAT: (
BITS binary exponent:=BIN exponent ; MAT out := IF bits width ELEM binary exponent THEN base ELSE IDENTITY UPB base FI; MAT sq:=base;
WHILE binary exponent := binary exponent SHR 1; binary exponent /= BIN 0 DO sq := sq * sq; IF bits width ELEM binary exponent THEN out := out * sq FI OD; out
);</lang>File: test_Matrix-exponentiation_operator.a68 <lang algol68>#!/usr/local/bin/a68g --script #
MODE COSCAL = COMPL; PR READ "Matrix_algebra.a68" PR PR READ "Matrix-exponentiation_operator.a68" PR
PROC compl mat printf= (FORMAT scal fmt, MAT m)VOID:(
FORMAT vec math = $n(2 UPB m)(f(scal fmt)"&")$, mat math = $"Failed to parse (unknown function "\begin{bmat}"): {\displaystyle \begin{bmat}"ln(UPB m)(xxf(vec fmt)"\\"l)"\end{bmat}} "$, vec fmt = $"("n(2 UPB m-1)(f(scal fmt)",")f(scal fmt)")"$, mat fmt = $x"("n(UPB m-1)(f(vec fmt)","lxx)f(vec fmt)");"$; # finally print the result # printf((mat fmt,m))
);
FORMAT scal fmt = $-d.dddd,+d.dddd"i"$; # width of 4, with no leading '+' sign, 1 decimals # MAT mat=((sqrt(0.5)I0 , sqrt(0.5)I0 , 0I0),
( 0I-sqrt(0.5), 0Isqrt(0.5), 0I0), ( 0I0 , 0I0 , 0I1))
printf(($" mat ** "g(0)":"l$,24)); compl mat printf(scal fmt, mat**24); print(newline)</lang> Output:
mat ** 24: (( 1.0000+0.0000i, 0.0000+0.0000i, 0.0000+0.0000i), ( 0.0000+0.0000i, 1.0000+0.0000i, 0.0000+0.0000i), ( 0.0000+0.0000i, 0.0000+0.0000i, 1.0000+0.0000i));
BBC BASIC
<lang bbcbasic> DIM matrix(1,1), output(1,1)
matrix() = 3, 2, 2, 1 FOR power% = 0 TO 9 PROCmatrixpower(matrix(), output(), power%) PRINT "matrix()^" ; power% " = " FOR row% = 0 TO DIM(output(), 1) FOR col% = 0 TO DIM(output(), 2) PRINT output(row%,col%); NEXT PRINT NEXT row% NEXT power% END DEF PROCmatrixpower(src(), dst(), pow%) LOCAL i% dst() = 0 FOR i% = 0 TO DIM(dst(), 1) : dst(i%,i%) = 1 : NEXT IF pow% THEN FOR i% = 1 TO pow% dst() = dst() . src() NEXT ENDIF ENDPROC</lang>
Output:
matrix()^0 = 1 0 0 1 matrix()^1 = 3 2 2 1 matrix()^2 = 13 8 8 5 matrix()^3 = 55 34 34 21 matrix()^4 = 233 144 144 89 matrix()^5 = 987 610 610 377 matrix()^6 = 4181 2584 2584 1597 matrix()^7 = 17711 10946 10946 6765 matrix()^8 = 75025 46368 46368 28657 matrix()^9 = 317811 196418 196418 121393
C
C doesn't support classes or allow operator overloading. The following is code that defines a function, SquareMtxPower that will raise a matrix to a positive integer power. <lang c>#include <math.h>
- include <stdio.h>
- include <stdlib.h>
typedef struct squareMtxStruct {
int dim; double *cells; double **m;
} *SquareMtx;
/* function for initializing row r of a new matrix */ typedef void (*FillFunc)( double *cells, int r, int dim, void *ff_data);
SquareMtx NewSquareMtx( int dim, FillFunc fillFunc, void *ff_data ) {
SquareMtx sm = malloc(sizeof(struct squareMtxStruct)); if (sm) { int rw; sm->dim = dim; sm->cells = malloc(dim*dim * sizeof(double)); sm->m = malloc( dim * sizeof(double *)); if ((sm->cells != NULL) && (sm->m != NULL)) { for (rw=0; rw<dim; rw++) { sm->m[rw] = sm->cells + dim*rw; fillFunc( sm->m[rw], rw, dim, ff_data ); } } else { free(sm->m); free(sm->cells); free(sm); printf("Square Matrix allocation failure\n"); return NULL; } } else { printf("Malloc failed for square matrix\n"); } return sm;
}
void ffMatxSquare( double *cells, int rw, int dim, SquareMtx m0 ) {
int col, ix; double sum; double *m0rw = m0->m[rw]; for (col = 0; col < dim; col++) { sum = 0.0; for (ix=0; ix<dim; ix++) sum += m0rw[ix] * m0->m[ix][col]; cells[col] = sum; }
}
void ffMatxMulply( double *cells, int rw, int dim, SquareMtx mplcnds[] ) {
SquareMtx mleft = mplcnds[0]; SquareMtx mrigt = mplcnds[1]; double sum; double *m0rw = mleft->m[rw]; int col, ix;
for (col = 0; col < dim; col++) { sum = 0.0; for (ix=0; ix<dim; ix++) sum += m0rw[ix] * mrigt->m[ix][col]; cells[col] = sum; }
}
void MatxMul( SquareMtx mr, SquareMtx left, SquareMtx rigt) {
int rw; SquareMtx mplcnds[2]; mplcnds[0] = left; mplcnds[1] = rigt;
for (rw = 0; rw < left->dim; rw++) ffMatxMulply( mr->m[rw], rw, left->dim, mplcnds);
}
void ffIdentity( double *cells, int rw, int dim, void *v ) {
int col; for (col=0; col<dim; col++) cells[col] = 0.0; cells[rw] = 1.0;
} void ffCopy(double *cells, int rw, int dim, SquareMtx m1) {
int col; for (col=0; col<dim; col++) cells[col] = m1->m[rw][col];
}
void FreeSquareMtx( SquareMtx m ) {
free(m->m); free(m->cells); free(m);
}
SquareMtx SquareMtxPow( SquareMtx m0, int exp ) {
SquareMtx v0 = NewSquareMtx(m0->dim, ffIdentity, NULL); SquareMtx v1 = NULL; SquareMtx base0 = NewSquareMtx( m0->dim, ffCopy, m0); SquareMtx base1 = NULL; SquareMtx mplcnds[2], t;
while (exp) { if (exp % 2) { if (v1) MatxMul( v1, v0, base0); else { mplcnds[0] = v0; mplcnds[1] = base0; v1 = NewSquareMtx(m0->dim, ffMatxMulply, mplcnds); } {t = v0; v0=v1; v1 = t;} } if (base1) MatxMul( base1, base0, base0); else base1 = NewSquareMtx( m0->dim, ffMatxSquare, base0); t = base0; base0 = base1; base1 = t; exp = exp/2; } if (base0) FreeSquareMtx(base0); if (base1) FreeSquareMtx(base1); if (v1) FreeSquareMtx(v1); return v0;
}
FILE *fout; void SquareMtxPrint( SquareMtx mtx, const char *mn ) {
int rw, col; int d = mtx->dim;
fprintf(fout, "%s dim:%d =\n", mn, mtx->dim);
for (rw=0; rw<d; rw++) { fprintf(fout, " |"); for(col=0; col<d; col++) fprintf(fout, "%8.5f ",mtx->m[rw][col] ); fprintf(fout, " |\n"); } fprintf(fout, "\n");
}
void fillInit( double *cells, int rw, int dim, void *data) {
double theta = 3.1415926536/6.0; double c1 = cos( theta); double s1 = sin( theta);
switch(rw) { case 0: cells[0]=c1; cells[1]=s1; cells[2]=0.0; break; case 1: cells[0]=-s1; cells[1]=c1; cells[2]=0; break; case 2: cells[0]=0.0; cells[1]=0.0; cells[2]=1.0; break; }
}
int main() {
SquareMtx m0 = NewSquareMtx( 3, fillInit, NULL); SquareMtx m1 = SquareMtxPow( m0, 5); SquareMtx m2 = SquareMtxPow( m0, 9); SquareMtx m3 = SquareMtxPow( m0, 2);
// fout = stdout;
fout = fopen("matrx_exp.txt", "w"); SquareMtxPrint(m0, "m0"); FreeSquareMtx(m0); SquareMtxPrint(m1, "m0^5"); FreeSquareMtx(m1); SquareMtxPrint(m2, "m0^9"); FreeSquareMtx(m2); SquareMtxPrint(m3, "m0^2"); FreeSquareMtx(m3); fclose(fout);
return 0;
}</lang> Output:
m0 dim:3 = | 0.86603 0.50000 0.00000 | |-0.50000 0.86603 0.00000 | | 0.00000 0.00000 1.00000 | m0^5 dim:3 = |-0.86603 0.50000 0.00000 | |-0.50000 -0.86603 0.00000 | | 0.00000 0.00000 1.00000 | m0^9 dim:3 = | 0.00000 -1.00000 0.00000 | | 1.00000 0.00000 0.00000 | | 0.00000 0.00000 1.00000 | m0^2 dim:3 = | 0.50000 0.86603 0.00000 | |-0.86603 0.50000 0.00000 | | 0.00000 0.00000 1.00000 |
C++
This is an implementation in C++. <lang cpp>#include <complex>
- include <cmath>
- include <iostream>
using namespace std;
template<int MSize = 3, class T = complex<double> > class SqMx {
typedef T Ax[MSize][MSize]; typedef SqMx<MSize, T> Mx;
private:
Ax a; SqMx() { }
public:
SqMx(const Ax &_a) { // constructor with pre-defined array for (int r = 0; r < MSize; r++) for (int c = 0; c < MSize; c++) a[r][c] = _a[r][c]; }
static Mx identity() { Mx m; for (int r = 0; r < MSize; r++) for (int c = 0; c < MSize; c++) m.a[r][c] = (r == c ? 1 : 0); return m; }
friend ostream &operator<<(ostream& os, const Mx &p) { // ugly print for (int i = 0; i < MSize; i++) { for (int j = 0; j < MSize; j++) os << p.a[i][j] << ","; os << endl; } return os; }
Mx operator*(const Mx &b) { Mx d; for (int r = 0; r < MSize; r++) for (int c = 0; c < MSize; c++) { d.a[r][c] = 0; for (int k = 0; k < MSize; k++) d.a[r][c] += a[r][k] * b.a[k][c]; } return d; }</lang>
This is the task part. <lang cpp> // C++ does not have a ** operator, instead, ^ (bitwise Xor) is used.
Mx operator^(int n) { if (n < 0) throw "Negative exponent not implemented";
Mx d = identity(); for (Mx sq = *this; n > 0; sq = sq * sq, n /= 2) if (n % 2 != 0) d = d * sq; return d; }
};
typedef SqMx<> M3; typedef complex<double> creal;
int main() {
double q = sqrt(0.5); creal array[3][3] = {{creal(q, 0), creal(q, 0), creal(0, 0)}, {creal(0, -q), creal(0, q), creal(0, 0)}, {creal(0, 0), creal(0, 0), creal(0, 1)}}; M3 m(array);
cout << "m ^ 23=" << endl << (m ^ 23) << endl;
return 0;
}</lang> Output:
m ^ 23= (0.707107,0),(0,0.707107),(0,0), (0.707107,0),(0,-0.707107),(0,0), (0,0),(0,0),(0,-1),
An alternative way would be to implement operator*= and conversion from number (giving multiples of the identity matrix) for the matrix and use the generic code from Exponentiation operator#C++ with support for negative exponents removed (or alternatively, implement matrix inversion as well, implement /= in terms of it, and use the generic code unchanged). Note that the algorithm used there is much faster as well.
Common Lisp
This Common Lisp implementation uses 2D Arrays to represent matrices, and checks to make sure that the arrays are the right dimensions for multiplication and square for exponentiation. <lang lisp>(defun multiply-matrices (matrix-0 matrix-1)
"Takes two 2D arrays and returns their product, or an error if they cannot be multiplied" (let* ((m0-dims (array-dimensions matrix-0)) (m1-dims (array-dimensions matrix-1)) (m0-dim (length m0-dims)) (m1-dim (length m1-dims))) (if (or (/= 2 m0-dim) (/= 2 m1-dim)) (error "Array given not a matrix") (let ((m0-rows (car m0-dims)) (m0-cols (cadr m0-dims)) (m1-rows (car m1-dims)) (m1-cols (cadr m1-dims))) (if (/= m0-cols m1-rows) (error "Incompatible dimensions") (do ((rarr (make-array (list m0-rows m1-cols) :initial-element 0) rarr) (n 0 (if (= n (1- m0-cols)) 0 (1+ n))) (cc 0 (if (= n (1- m0-cols)) (if (/= cc (1- m1-cols)) (1+ cc) 0) cc)) (cr 0 (if (and (= (1- m0-cols) n) (= (1- m1-cols) cc)) (1+ cr) cr))) ((= cr m0-rows) rarr) (setf (aref rarr cr cc) (+ (aref rarr cr cc) (* (aref matrix-0 cr n) (aref matrix-1 n cc))))))))))
(defun matrix-identity (dim)
"Creates a new identity matrix of size dim*dim" (do ((rarr (make-array (list dim dim) :initial-element 0) rarr) (n 0 (1+ n))) ((= n dim) rarr) (setf (aref rarr n n) 1)))
(defun matrix-expt (matrix exp)
"Takes the first argument (a matrix) and multiplies it by itself exp times" (let* ((m-dims (array-dimensions matrix)) (m-rows (car m-dims)) (m-cols (cadr m-dims))) (cond ((/= m-rows m-cols) (error "Non-square matrix")) ((zerop exp) (matrix-identity m-rows)) ((= 1 exp) (do ((rarr (make-array (list m-rows m-cols)) rarr) (cc 0 (if (= cc (1- m-cols)) 0 (1+ cc))) (cr 0 (if (= cc (1- m-cols)) (1+ cr) cr))) ((= cr m-rows) rarr) (setf (aref rarr cr cc) (aref matrix cr cc)))) ((zerop (mod exp 2)) (let ((me2 (matrix-expt matrix (/ exp 2)))) (multiply-matrices me2 me2))) (t (let ((me2 (matrix-expt matrix (/ (1- exp) 2)))) (multiply-matrices matrix (multiply-matrices me2 me2)))))))</lang>
Output (note that this lisp implementation uses single-precision floats for decimals by default). We can also use rationals:
CL-USER> (setf 5x5-matrix (make-array '(5 5) :initial-contents '((0 1 -1 -2 2) (0.4 4 3.2 -3 -10) (4.5 -2 0.5 1 7) (10 1 0 1.5 -2) (4 5 -3 -2 1)))) #2A((0 1 -1 -2 2) (0.4 4 3.2 -3 -10) (4.5 -2 0.5 1 7) (10 1 0 1.5 -2) (4 5 -3 -2 1)) CL-USER> (matrix-expt 5x5-matrix 3) #2A((-163.25 -19.5 92.25 -7.5999985 -184.3) (156.6 -412.09998 0.7999954 331.45 597.4) (-129.82501 401.25 -66.975 -302.55 -390.15) (-148.9 39.25 -5.200001 -67.225006 -7.300003) (-495.05 -231.5 310.85 33.0 -328.5)) CL-USER> (setf 4x4-matrix (make-array '(4 4) :initial-contents '(( 1/2 -1/2 4 8) (-3/4 7/3 8/5 -2) (-5 17 20/3 -5/2) ( 3/2 -1 -7/3 6)))) #2A((1/2 -1/2 4 8) (-3/4 7/3 8/5 -2) (-5 17 20/3 -5/2) (3/2 -1 -7/3 6)) CL-USER> (matrix-expt 4x4-matrix 3) #2A((-233/8 182723/720 757/30 353/6) (-73517/480 838241/2160 77789/450 -67537/180) (-5315/9 66493/45 90883/135 -54445/36) (37033/144 -27374/45 -15515/54 12109/18))
Chapel
This uses the '*' operator for arrays as defined in Matrix_multiplication#Chapel <lang chapel>proc **(a, e) {
// create result matrix of same dimensions var r:[a.domain] a.eltType; // and initialize to identity matrix forall ij in r.domain do r(ij) = if ij(1) == ij(2) then 1 else 0;
for 1..e do r *= a;
return r;
}</lang>
Usage example (like Perl): <lang chapel>var m:[1..3, 1..3] int; m(1,1) = 1; m(1,2) = 2; m(1,3) = 0; m(2,1) = 0; m(2,2) = 3; m(2,3) = 1; m(3,1) = 1; m(3,2) = 0; m(3,3) = 0;
config param n = 10;
for i in 0..n do {
writeln("Order ", i); writeln(m ** i, "\n");
}</lang>
- Output:
Order 0 1 0 0 0 1 0 0 0 1 Order 1 1 2 0 0 3 1 1 0 0 Order 2 1 8 2 1 9 3 1 2 0 Order 3 3 26 8 4 29 9 1 8 2 Order 4 11 84 26 13 95 29 3 26 8 Order 5 37 274 84 42 311 95 11 84 26 Order 6 121 896 274 137 1017 311 37 274 84 Order 7 395 2930 896 448 3325 1017 121 896 274 Order 8 1291 9580 2930 1465 10871 3325 395 2930 896 Order 9 4221 31322 9580 4790 35543 10871 1291 9580 2930 Order 10 13801 102408 31322 15661 116209 35543 4221 31322 9580
D
<lang d>import std.stdio, std.string, std.math, std.array;
struct SquareMat(T = creal) {
public static string fmt = "%8.3f"; private alias TM = T[][]; private TM a;
public this(in size_t side) pure nothrow in { assert(side > 0); } body { a = new TM(side, side); }
public this(in TM m) pure nothrow in { assert(!m.empty); foreach (const row; m) assert(m.length == m[0].length); } body { a.length = m.length; foreach (immutable i, const row; m) //a[i] = row.dup; // Not nothrow. a[i] = row ~ []; // Slower. }
string toString() const { return format("<%(%(" ~ fmt ~ ", %)\n %)>", a); }
public static SquareMat identity(in size_t side) pure nothrow { SquareMat m; m.a.length = side; foreach (immutable r, ref row; m.a) { row.length = side; foreach (immutable c; 0 .. side) row[c] = cast(T)(r == c ? 1 : 0); } return m; }
public SquareMat opBinary(string op:"*")(in SquareMat other) const pure nothrow in { assert (a.length == other.a.length); } body { immutable size_t side = other.a.length; SquareMat d; d.a = new TM(side, side); foreach (immutable r; 0 .. side) foreach (immutable c; 0 .. side) { d.a[r][c] = cast(T)0; foreach (immutable k, immutable ark; a[r]) d.a[r][c] += ark * other.a[k][c]; } return d; }
// This is the task part --------------- public SquareMat opBinary(string op:"^^")(int n) const pure nothrow in { assert(n >= 0, "Negative exponent not implemented."); } body { auto sq = SquareMat(this.a); auto d = SquareMat.identity(a.length); for (; n > 0; sq = sq * sq, n >>= 1) if (n & 1) d = d * sq; return d; }
}
void main() {
alias M = SquareMat!(); immutable real q = sqrt(0.5); immutable m = M([[ q + 0*1.0Li, q + 0*1.0Li, 0.0L + 0.0Li], [0.0L - q*1.0Li, 0.0L + q*1.0Li, 0.0L + 0.0Li], [0.0L + 0.0Li, 0.0L + 0.0Li, 0.0L + 1.0Li]]); M.fmt = "%5.2f"; foreach (immutable p; [0, 1, 23, 24]) writefln("m ^^ %d =\n%s", p, m ^^ p);
}</lang>
- Output:
m ^^ 0 = < 1.00+ 0.00i, 0.00+ 0.00i, 0.00+ 0.00i 0.00+ 0.00i, 1.00+ 0.00i, 0.00+ 0.00i 0.00+ 0.00i, 0.00+ 0.00i, 1.00+ 0.00i> m ^^ 1 = < 0.71+ 0.00i, 0.71+ 0.00i, 0.00+ 0.00i 0.00+-0.71i, 0.00+ 0.71i, 0.00+ 0.00i 0.00+ 0.00i, 0.00+ 0.00i, 0.00+ 1.00i> m ^^ 23 = < 0.71+ 0.00i, 0.00+ 0.71i, 0.00+ 0.00i 0.71+ 0.00i, 0.00+-0.71i, 0.00+ 0.00i 0.00+ 0.00i, 0.00+ 0.00i, 0.00+-1.00i> m ^^ 24 = < 1.00+ 0.00i, 0.00+ 0.00i, 0.00+ 0.00i 0.00+ 0.00i, 1.00+ 0.00i, 0.00+ 0.00i 0.00+ 0.00i, 0.00+ 0.00i, 1.00+ 0.00i>
Factor
There is already a built-in word (m^n
) that implements exponentiation. Here is a simple and less efficient implementation.
<lang factor>USING: kernel math math.matrices sequences ;
- my-m^n ( m n -- m' )
dup 0 < [ "no negative exponents" throw ] [ [ drop length identity-matrix ] [ swap '[ _ m. ] times ] 2bi ] if ;</lang>
( scratchpad ) { { 3 2 } { 2 1 } } 0 my-m^n . { { 1 0 } { 0 1 } } ( scratchpad ) { { 3 2 } { 2 1 } } 4 my-m^n . { { 233 144 } { 144 89 } }
Fortran
<lang fortran>module matmod
implicit none
! Overloading the ** operator does not work because the compiler cannot ! differentiate between matrix exponentiation and the elementwise raising ! of an array to a power therefore we define a new operator
interface operator (.matpow.) module procedure matrix_exp end interface
contains
function matrix_exp(m, n) result (res)
real, intent(in) :: m(:,:) integer, intent(in) :: n real :: res(size(m,1),size(m,2)) integer :: i if(n == 0) then res = 0 do i = 1, size(m,1) res(i,i) = 1 end do return end if
res = m do i = 2, n res = matmul(res, m) end do
end function matrix_exp end module matmod
program Matrix_exponentiation
use matmod implicit none
integer, parameter :: n = 3 real, dimension(n,n) :: m1, m2 integer :: i, j m1 = reshape((/ (i, i = 1, n*n) /), (/ n, n /), order = (/ 2, 1 /)) do i = 0, 4 m2 = m1 .matpow. i do j = 1, size(m2,1) write(*,*) m2(j,:) end do write(*,*) end do
end program Matrix_exponentiation</lang> Output
1.00000 0.00000 0.00000 0.00000 1.00000 0.00000 0.00000 0.00000 1.00000 1.00000 2.00000 3.00000 4.00000 5.00000 6.00000 7.00000 8.00000 9.00000 30.0000 36.0000 42.0000 66.0000 81.0000 96.0000 102.000 126.000 150.000 468.000 576.000 684.000 1062.00 1305.00 1548.00 1656.00 2034.00 2412.00 7560.00 9288.00 11016.0 17118.0 21033.0 24948.0 26676.0 32778.0 38880.0
GAP
<lang gap># Matrix exponentiation is built-in A := [[0 , 1], [1, 1]]; PrintArray(A);
- [ [ 0, 1 ],
- [ 1, 1 ] ]
PrintArray(A^10);
- [ [ 34, 55 ],
- [ 55, 89 ] ]</lang>
Haskell
Instead of writing it directly, we can re-use the built-in exponentiation operator if we declare matrices as an instance of Num, using matrix multiplication (and addition). For simplicity, we use the inefficient representation as list of lists. Note that we don't check the dimensions (there are several ways to do that on the type-level, for example with phantom types).
<lang haskell>import Data.List
xs <+> ys = zipWith (+) xs ys xs <*> ys = sum $ zipWith (*) xs ys
newtype Mat a = Mat a deriving (Eq, Show)
instance Num a => Num (Mat a) where
negate (Mat x) = Mat $ map (map negate) x Mat x + Mat y = Mat $ zipWith (<+>) x y Mat x * Mat y = Mat [[xs <*> ys | ys <- transpose y] | xs <- x] fromInteger _ = undefined -- don't know dimension of the desired matrix</lang>
Output:
*Main> Mat [[1,2],[0,1]]^4 Mat [[1,8],[0,1]]
This will work for matrices over any numeric type, including complex numbers. The implementation of (^) uses the fast binary algorithm for exponentiation.
Note: this implementation does not work for a power of 0.
J
<lang j>mp=: +/ .* NB. Matrix multiplication pow=: pow0=: 4 : 'mp&x^:y =i.#x'</lang>
or, from the J wiki, and faster for large exponents:
<lang j>pow=: pow1=: 4 : 'mp/ mp~^:(I.|.#:y) x'</lang>
This implements an optimization where the exponent is represented in base 2, and repeated squaring is used to create a list of relevant powers of the base matrix, which are then combined using matrix multiplication. Note, however, that these two definitions treat a zero exponent differently (m pow0 0 gives an identity matrix whose shape matches m, while m pow1 0 gives a scalar 1).
Example use:
(3 2,:2 1) pow 3 55 34 34 21
JavaScript
for the print()
and Array.forEach()
functions.
Extends Matrix Transpose#JavaScript and Matrix multiplication#JavaScript <lang javascript>// IdentityMatrix is a "subclass" of Matrix function IdentityMatrix(n) {
this.height = n; this.width = n; this.mtx = []; for (var i = 0; i < n; i++) { this.mtx[i] = []; for (var j = 0; j < n; j++) { this.mtx[i][j] = (i == j ? 1 : 0); } }
} IdentityMatrix.prototype = Matrix.prototype;
// the Matrix exponentiation function // returns a new matrix Matrix.prototype.exp = function(n) {
var result = new IdentityMatrix(this.height); for (var i = 1; i <= n; i++) { result = result.mult(this); } return result;
}
var m = new Matrix([[3, 2], [2, 1]]); [0,1,2,3,4,10].forEach(function(e){print(m.exp(e)); print()})</lang> output
1,0 0,1 3,2 2,1 13,8 8,5 55,34 34,21 233,144 144,89 1346269,832040 832040,514229
Julia
Matrix exponentiation is implemented by the built-in ^
operator.
<lang Julia>julia> [1 1 ; 1 0]^10
2x2 Array{Int64,2}:
89 55 55 34</lang>
Liberty BASIC
There is no native matrix capability. A set of functions is available at http://www.diga.me.uk/RCMatrixFuncs.bas implementing matrices of arbitrary dimension in a string format. <lang lb> MatrixD$ ="3, 3, 0.86603, 0.50000, 0.00000, -0.50000, 0.86603, 0.00000, 0.00000, 0.00000, 1.00000"
print "Exponentiation of a matrix"
call DisplayMatrix MatrixD$
print " Raised to power 5 ="
MatrixE$ =MatrixToPower$( MatrixD$, 5)
call DisplayMatrix MatrixE$
print " Raised to power 9 ="
MatrixE$ =MatrixToPower$( MatrixD$, 9)
call DisplayMatrix MatrixE$
</lang>
Exponentiation of a matrix
| 0.86603 0.50000 0.00000 |
| -0.50000 0.86603 0.00000 |
| 0.00000 0.00000 1.00000 |
Raised to power 5 =
| -0.86604 0.50002 0.00000 |
| -0.50002 -0.86604 0.00000 |
| 0.00000 0.00000 1.00000 |
Raised to power 9 =
| -0.00002 -1.00004 0.00000 |
| 1.00004 -0.00002 0.00000 |
| 0.00000 0.00000 1.00000 |
Lua
<lang lua>Matrix = {}
function Matrix.new( dim_y, dim_x )
assert( dim_y and dim_x ) local matrix = {} local metatab = {} setmetatable( matrix, metatab ) metatab.__add = Matrix.Add metatab.__mul = Matrix.Mul metatab.__pow = Matrix.Pow
matrix.dim_y = dim_y matrix.dim_x = dim_x matrix.data = {} for i = 1, dim_y do matrix.data[i] = {} end return matrix
end
function Matrix.Show( m )
for i = 1, m.dim_y do for j = 1, m.dim_x do io.write( tostring( m.data[i][j] ), " " ) end io.write( "\n" ) end
end
function Matrix.Add( m, n )
assert( m.dim_x == n.dim_x and m.dim_y == n.dim_y ) local r = Matrix.new( m.dim_y, m.dim_x ) for i = 1, m.dim_y do for j = 1, m.dim_x do r.data[i][j] = m.data[i][j] + n.data[i][j] end end return r
end
function Matrix.Mul( m, n )
assert( m.dim_x == n.dim_y ) local r = Matrix.new( m.dim_y, n.dim_x ) for i = 1, m.dim_y do for j = 1, n.dim_x do r.data[i][j] = 0 for k = 1, m.dim_x do r.data[i][j] = r.data[i][j] + m.data[i][k] * n.data[k][j] end end end return r
end
function Matrix.Pow( m, p )
assert( m.dim_x == m.dim_y ) local r = Matrix.new( m.dim_y, m.dim_x ) if p == 0 then for i = 1, m.dim_y do for j = 1, m.dim_x do if i == j then r.data[i][j] = 1 else r.data[i][j] = 0 end end end elseif p == 1 then for i = 1, m.dim_y do for j = 1, m.dim_x do r.data[i][j] = m.data[i][j] end end else r = m for i = 2, p do r = r * m end end return r
end
m = Matrix.new( 2, 2 )
m.data = { { 1, 2 }, { 3, 4 } }
n = m^4;
Matrix.Show( n )</lang>
Maple
Maple handles matrix powers implicitly with the built-in exponentiation operator: <lang Maple>> M := <<1,2>|<3,4>>; > M ^ 2;</lang>
If you want elementwise powers, you can use the elementwise ^~
operator:
<lang Maple>> M := <<1,2>|<3,4>>;
> M ^~ 2;</lang>
Mathematica
In Mathematica there is an distinction between powering elements wise and as a matrix. So m^2 will give m with each element squared. To do matrix exponentation we use the function MatrixPower. It can handle all types of numbers for the power (integers, floats, rationals, complex) but also symbols for the power, and all types for the matrix (numbers, symbols et cetera), and will always keep the result exact if the matrix and the exponent is exact. <lang Mathematica>a = {{3, 2}, {4, 1}}; MatrixPower[a, 0] MatrixPower[a, 1] MatrixPower[a, -1] MatrixPower[a, 4] MatrixPower[a, 1/2] MatrixPower[a, Pi]</lang> gives back:
Symbolic matrices like {{i,j},{k,l}} to the power m give general solutions for all possible i,j,k,l, and m: <lang Mathematica>MatrixPower[{{i, j}, {k, l}}, m] // Simplify</lang> gives back (note that the simplification is not necessary for the evaluation, it just gives a shorter output):
Final note: Do not confuse MatrixPower with MatrixExp; the former is for matrix exponentiation, and the latter for the matrix exponential (E^m).
MATLAB
For exponents in the form of A*A*A*A*...*A, A must be a square matrix: <lang Matlab>function [output] = matrixexponentiation(matrixA, exponent)
output = matrixA^(exponent);</lang>
Otherwise, to take the individual array elements to the power of an exponent (the matrix need not be square): <lang Matlab>function [output] = matrixexponentiation(matrixA, exponent)
output = matrixA.^(exponent);</lang>
Maxima
<lang maxima>a: matrix([3, 2],
[4, 1])$
a ^^ 4; /* matrix([417, 208],
[416, 209]) */
a ^^ -1; /* matrix([-1/5, 2/5],
[4/5, -3/5]) */</lang>
OCaml
We will use some auxiliary functions
<lang ocaml>(* identity matrix *) let eye n =
let a = Array.make_matrix n n 0.0 in for i=0 to n-1 do a.(i).(i) <- 1.0 done; (a)
(* matrix dimensions *) let dim a = Array.length a, Array.length a.(0);;
(* make matrix from list in row-major order *) let matrix p q v =
if (List.length v) <> (p * q) then failwith "bad dimensions" else let a = Array.make_matrix p q (List.hd v) in let rec g i j = function | [] -> a | x::v -> a.(i).(j) <- x; if j+1 < q then g i (j+1) v else g (i+1) 0 v in g 0 0 v
(* matrix product *) let matmul a b =
let n, p = dim a and q, r = dim b in if p <> q then failwith "bad dimensions" else let c = Array.make_matrix n r 0.0 in for i=0 to n-1 do for j=0 to r-1 do for k=0 to p-1 do c.(i).(j) <- c.(i).(j) +. a.(i).(k) *. b.(k).(j) done done done; (c)
(* generic exponentiation, usual algorithm *) let pow one mul a n =
let rec g p x = function | 0 -> x | i -> g (mul p p) (if i mod 2 = 1 then mul p x else x) (i/2) in g a one n
(* example with integers *) pow 1 ( * ) 2 16;; (* - : int = 65536 *)</lang>
Now matrix power is simply a special case of pow :
<lang ocaml>let matpow a n =
let p, q = dim a in if p <> q then failwith "bad dimensions" else pow (eye p) matmul a n;;
matpow (matrix 2 2 [ 1.0; 1.0; 1.0; 0.0 ]) 10;; (* - : float array array = [|[|89.; 55.|]; [|55.; 34.|]|] *)
(* use as infix operator *) let ( ^^ ) = matpow;;
[| [| 1.0; 1.0|]; [| 1.0; 0.0 |] |] ^^ 10;; (* - : float array array = [|[|89.; 55.|]; [|55.; 34.|]|] *)</lang>
Octave
Of course GNU Octave handles matrix and operations on matrix "naturally".
<lang octave>M = [ 3, 2; 2, 1 ]; M^0 M^1 M^2 M^(-1) M^0.5</lang>
Output:
ans = 1 0 0 1 ans = 3 2 2 1 ans = 13 8 8 5 ans = -1.0000 2.0000 2.0000 -3.0000 ans = 1.48931 + 0.13429i 0.92044 - 0.21729i 0.92044 - 0.21729i 0.56886 + 0.35158i
(Of course this is not an implementation, but it can be used as reference for the results)
PARI/GP
<lang parigp>M^n</lang>
Perl
<lang perl>use strict; package SquareMatrix; use Carp; # standard, "it's not my fault" module
use overload (
'""' => \&_string, # overload string operator so we can just print '*' => \&_mult, # multiplication, needed for expo '*=' => \&_mult, # ditto, explicitly defined to trigger copy '**' => \&_expo, # overload exponentiation '=' => \&_copy, # copy operator
);
sub make {
my $cls = shift; my $n = @_; for (@_) { # verify each row given is the right length confess "Bad data @$_: matrix must be square " if @$_ != $n; }
bless [ map [@$_], @_ ] # important: actually copy all the rows
}
sub identity {
my $self = shift; my $n = @$self - 1; my @rows = map [ (0) x $_, 1, (0) x ($n - $_) ], 0 .. $n; bless \@rows
}
sub zero {
my $self = shift; my $n = @$self; bless [ map [ (0) x $n ], 1 .. $n ]
}
sub _string {
"[ ".join("\n " => map join(" " => map(sprintf("%12.6g", $_), @$_)), @{+shift} )." ]\n";
}
sub _mult {
my ($a, $b) = @_; my $x = $a->zero; my @idx = (0 .. $#$x); for my $j (@idx) { my @col = map($a->[$_][$j], @idx); for my $i (@idx) { my $row = $b->[$i]; $x->[$i][$j] += $row->[$_] * $col[$_] for @idx; } } $x
}
sub _expo {
my ($self, $n) = @_; confess "matrix **: must be non-negative integer power" unless $n >= 0 && $n == int($n);
my ($tmp, $out) = ($self, $self->identity); do { $out *= $tmp if $n & 1; $tmp *= $tmp; } while $n >>= 1;
$out
}
sub _copy { bless [ map [ @$_ ], @{+shift} ] }
- now use our matrix class
package main;
my $m = SquareMatrix->make(
[1, 2, 0], [0, 3, 1], [1, 0, 0] );
print "### Order $_\n", $m ** $_ for 0 .. 10;
$m = SquareMatrix->make(
[ 1.0001, 0, 0, 1 ], [ 0, 1.001, 0, 0 ], [ 0, 0, 1, 0.99998 ], [ 1e-8, 0, 0, 1.0002 ]);
print "\n### Matrix is now\n", $m; print "\n### Big power:\n", $m ** 100_000; print "\n### Too big:\n", $m ** 1_000_000; print "\n### WAY too big:\n", $m ** 1_000_000_000_000; print "\n### But identity matrix can handle that\n",
$m->identity ** 1_000_000_000_000;</lang>
Perl 6
<lang perl6>subset SqMat of Array where { .elems == all(.[]».elems) }
multi infix:<*>(SqMat $a, SqMat $b) {[
for ^$a -> $r {[ for ^$b[0] -> $c { [+] ($a[$r][] Z* $b[].map: *[$c]) } ]}
]}
multi infix:<**> (SqMat $m, Int $n is copy where { $_ >= 0 }) {
my $tmp = $m; my $out = [for ^$m -> $i { [ for ^$m -> $j { +($i == $j) } ] } ]; loop {
$out = $out * $tmp if $n +& 1; last unless $n +>= 1; $tmp = $tmp * $tmp;
} $out;
}
multi show (SqMat $m) {
my $size = 1; for ^$m X ^$m -> $i, $j { $size max= $m[$i][$j].Str.chars; } say join "\n", $m».fmt("%{$size}s");
}
my @m = [1, 2, 0], [0, 3, 1], [1, 0, 0];
for 0 .. 10 -> $order {
say "### Order $order"; show @m ** $order;
}</lang> Output:
### Order 0 1 0 0 0 1 0 0 0 1 ### Order 1 1 2 0 0 3 1 1 0 0 ### Order 2 1 8 2 1 9 3 1 2 0 ### Order 3 3 26 8 4 29 9 1 8 2 ### Order 4 11 84 26 13 95 29 3 26 8 ### Order 5 37 274 84 42 311 95 11 84 26 ### Order 6 121 896 274 137 1017 311 37 274 84 ### Order 7 395 2930 896 448 3325 1017 121 896 274 ### Order 8 1291 9580 2930 1465 10871 3325 395 2930 896 ### Order 9 4221 31322 9580 4790 35543 10871 1291 9580 2930 ### Order 10 13801 102408 31322 15661 116209 35543 4221 31322 9580
PicoLisp
Uses the 'matMul' function from Matrix multiplication#PicoLisp <lang PicoLisp>(de matIdent (N)
(let L (need N (1) 0) (mapcar '(() (copy (rot L))) L) ) )
(de matExp (Mat N)
(let M (matIdent (length Mat)) (do N (setq M (matMul M Mat)) ) M ) )
(matExp '((3 2) (2 1)) 3)</lang> Output:
-> ((55 34) (34 21))
Python
Using matrixMul from Matrix multiplication#Python <lang python>>>> from operator import mul >>> def matrixMul(m1, m2):
return map( lambda row: map( lambda *column: sum(map(mul, row, column)), *m2), m1)
>>> def identity(size): size = range(size) return [[(i==j)*1 for i in size] for j in size]
>>> def matrixExp(m, pow): assert pow>=0 and int(pow)==pow, "Only non-negative, integer powers allowed" accumulator = identity(len(m)) for i in range(pow): accumulator = matrixMul(accumulator, m) return accumulator
>>> def printtable(data): for row in data: print ' '.join('%-5s' % ('%s' % cell) for cell in row)
>>> m = [[3,2], [2,1]]
>>> for i in range(5):
print '\n%i:' % i
printtable( matrixExp(m, i) )
0: 1 0 0 1
1: 3 2 2 1
2: 13 8 8 5
3: 55 34 34 21
4: 233 144 144 89 >>> printtable( matrixExp(m, 10) ) 1346269 832040 832040 514229 >>></lang>
R
<lang R>library(Biodem) m <- matrix(c(3,2,2,1), nrow=2) mtx.exp(m, 0)
- [,1] [,2]
- [1,] 1 0
- [2,] 0 1
mtx.exp(m, 1)
- [,1] [,2]
- [1,] 3 2
- [2,] 2 1
mtx.exp(m, 2)
- [,1] [,2]
- [1,] 13 8
- [2,] 8 5
mtx.exp(m, 3)
- [,1] [,2]
- [1,] 55 34
- [2,] 34 21
mtx.exp(m, 10)
- [,1] [,2]
- [1,] 1346269 832040
- [2,] 832040 514229</lang>
Note that non-integer powers are not supported with this function.
Racket
<lang Racket>
- lang racket
(require math)
(define a (matrix ((3 2) (2 1))))
- Using the builtin matrix exponentiation
(for ([i 11])
(printf "a^~a = ~s\n" i (matrix-expt a i)))
- Output
- a^0 = (array #[#[1 0] #[0 1]])
- a^1 = (array #[#[3 2] #[2 1]])
- a^2 = (array #[#[13 8] #[8 5]])
- a^3 = (array #[#[55 34] #[34 21]])
- a^4 = (array #[#[233 144] #[144 89]])
- a^5 = (array #[#[987 610] #[610 377]])
- a^6 = (array #[#[4181 2584] #[2584 1597]])
- a^7 = (array #[#[17711 10946] #[10946 6765]])
- a^8 = (array #[#[75025 46368] #[46368 28657]])
- a^9 = (array #[#[317811 196418] #[196418 121393]])
- a^10 = (array #[#[1346269 832040] #[832040 514229]])
- But it could be implemented manually, using matrix multiplication
(define (mpower M p)
(cond [(= p 1) M] [(even? p) (mpower (matrix* M M) (/ p 2))] [else (matrix* M (mpower M (sub1 p)))]))
(for ([i (in-range 1 11)])
(printf "a^~a = ~s\n" i (matrix-expt a i)))
</lang>
Ruby
Ruby's standard library already provides the matrix-exponentiation operator. It is Matrix#**
from package 'matrix' of the standard library. MRI 1.9.x implements the matrix-exponentiation operator in file matrix.rb, def **
(around line 961).
$ irb irb(main):001:0> require 'matrix' => true irb(main):002:0> m=Matrix[[3,2],[2,1]] => Matrix[[3, 2], [2, 1]] irb(main):003:0> m**0 => Matrix[[1, 0], [0, 1]] irb(main):004:0> m ** 1 => Matrix[[3, 2], [2, 1]] irb(main):005:0> m ** 2 => Matrix[[13, 8], [8, 5]] irb(main):006:0> m ** 5 => Matrix[[987, 610], [610, 377]] irb(main):007:0> m ** 10 => Matrix[[1346269, 832040], [832040, 514229]]
Starting with Ruby 1.9.3, it can also calculate Matrix ** Float.
irb(main):008:0> m ** 1.5 => Matrix[[(6.308803769316981-0.03170173099577213i), (3.8990551577913446+0.05129 4478253365354i)], [(3.899055157791345+0.05129447825336536i), (2.4097486115256355 -0.0829962092491375i)]]
With older Ruby, it raises an exception for Matrix ** Float.
irb(main):008:0> m ** 1.5 ExceptionForMatrix::ErrOperationNotDefined: This operation(**) can't defined from /usr/lib/ruby/1.8/matrix.rb:665:in `**' from (irb):8
Scala
<lang scala>class Matrix[T](matrix:Array[Array[T]])(implicit n: Numeric[T], m: ClassManifest[T]) {
import n._ val rows=matrix.size val cols=matrix(0).size def row(i:Int)=matrix(i) def col(i:Int)=matrix map (_(i))
def *(other: Matrix[T]):Matrix[T] = new Matrix( Array.tabulate(rows, other.cols)((row, col) => (this.row(row), other.col(col)).zipped.map(_*_) reduceLeft (_+_) ))
def **(x: Int)=x match { case 0 => createIdentityMatrix case 1 => this case 2 => this * this case _ => List.fill(x)(this) reduceLeft (_*_) }
def createIdentityMatrix=new Matrix(Array.tabulate(rows, cols)((row,col) => if (row == col) one else zero) )
override def toString = matrix map (_.mkString("[", ", ", "]")) mkString "\n"
}
object MatrixTest {
def main(args:Array[String])={ val m=new Matrix[BigInt](Array(Array(3,2), Array(2,1))) println("-- m --\n"+m)
Seq(0,1,2,3,4,10,20,50) foreach {x => println("-- m**"+x+" --") println(m**x) } }
}</lang>
- Output:
-- m -- [3, 2] [2, 1] -- m**0 -- [1, 0] [0, 1] -- m**1 -- [3, 2] [2, 1] -- m**2 -- [13, 8] [8, 5] -- m**3 -- [55, 34] [34, 21] -- m**4 -- [233, 144] [144, 89] -- m**10 -- [1346269, 832040] [832040, 514229] -- m**20 -- [2504730781961, 1548008755920] [1548008755920, 956722026041] -- m**50 -- [16130531424904581415797907386349, 9969216677189303386214405760200] [9969216677189303386214405760200, 6161314747715278029583501626149]
Scheme
For simplicity, the matrix is represented as a list of lists, and no dimension checking occurs.
<lang scheme> (define (dec x)
(- x 1))
(define (halve x)
(/ x 2))
(define (row*col row col)
(apply + (map * row col)))
(define (multiply-matrix m1 m2)
(map (lambda (row) (apply map (lambda col (row*col row col)) m2)) m1))
(define (matrix-expo mat exp)
(cond ((= exp 1) mat) ((even? exp) (square-matrix (matrix-expo mat (halve exp)))) (else (multiply-matrix mat (matrix-expo mat (dec exp))))))
</lang>
Seed7
The example below uses several features of Seed7:
- Overloading of the operators * and ** .
- The template enable_output, which allows writing a matrix with write (the function str must be defined before calling enable_output).
- A for loop which loops over values listed in an array literal
<lang seed7>$ include "seed7_05.s7i";
include "float.s7i";
const type: matrix is array array float;
const func string: str (in matrix: mat) is func
result var string: stri is ""; local var integer: row is 0; var integer: column is 0; begin for row range 1 to length(mat) do for column range 1 to length(mat[row]) do stri &:= str(mat[row][column]); if column < length(mat[row]) then stri &:= ", "; end if; end for; if row < length(mat) then stri &:= "\n"; end if; end for; end func;
enable_output(matrix);
const func matrix: (in matrix: mat1) * (in matrix: mat2) is func
result var matrix: product is matrix.value; local var integer: row is 0; var integer: column is 0; var integer: k is 0; begin product := length(mat1) times length(mat1) times 0.0; for row range 1 to length(mat1) do for column range 1 to length(mat1) do product[row][column] := 0.0; for k range 1 to length(mat1) do product[row][column] +:= mat1[row][k] * mat2[k][column]; end for; end for; end for; end func;
const func matrix: (in var matrix: base) ** (in var integer: exponent) is func
result var matrix: power is matrix.value; local var integer: row is 0; var integer: column is 0; begin if exponent < 0 then raise NUMERIC_ERROR; else if odd(exponent) then power := base; else # Create identity matrix power := length(base) times length(base) times 0.0; for row range 1 to length(base) do for column range 1 to length(base) do if row = column then power[row][column] := 1.0; end if; end for; end for; end if; exponent := exponent div 2; while exponent > 0 do base := base * base; if odd(exponent) then power := power * base; end if; exponent := exponent div 2; end while; end if; end func;
const proc: main is func
local var matrix: m is [] ( [] (4.0, 3.0), [] (2.0, 1.0)); var integer: exponent is 0; begin for exponent range [] (0, 1, 2, 3, 5, 7, 11, 13, 17, 19, 23) do writeln("m ** " <& exponent <& " ="); writeln(m ** exponent); end for; end func;</lang>
Original source of matrix exponentiation: [1]
Output:
m ** 0 = 1.0, 0.0 0.0, 1.0 m ** 1 = 4.0, 3.0 2.0, 1.0 m ** 2 = 22.0, 15.0 10.0, 7.0 m ** 3 = 118.0, 81.0 54.0, 37.0 m ** 5 = 3406.0, 2337.0 1558.0, 1069.0 m ** 7 = 98302.0, 67449.0 44966.0, 30853.0 m ** 11 = 81883680.0, 56183720.0 37455816.0, 25699956.0 m ** 13 = 2363278336.0, 1621541248.0 1081027456.0, 741736960.0 m ** 17 = 1968565387264.0, 1350712688640.0 900475125760.0, 617852567552.0 m ** 19 = 56815568027648.0, 38983467794432.0 25988979228672.0, 17832093941760.0 m ** 23 = 47326274699395072.0, 32472478198530048.0 21648320946503680.0, 14853792205897728.0
Tcl
Using code at Matrix multiplication#Tcl and Matrix Transpose#Tcl <lang tcl>package require Tcl 8.5 namespace path {::tcl::mathop ::tcl::mathfunc}
proc matrix_exp {m pow} {
if { ! [string is int -strict $pow]} { error "non-integer exponents not implemented" } if {$pow < 0} { error "negative exponents not implemented" } lassign [size $m] rows cols # assume square matrix set temp [identity $rows] for {set n 1} {$n <= $pow} {incr n} { set temp [matrix_multiply $temp $m] } return $temp
}
proc identity {size} {
set i [lrepeat $size [lrepeat $size 0]] for {set n 0} {$n < $size} {incr n} {lset i $n $n 1} return $i
}</lang>
% print_matrix [matrix_exp {{3 2} {2 1}} 1] 3 2 2 1 % print_matrix [matrix_exp {{3 2} {2 1}} 0] 1 0 0 1 % print_matrix [matrix_exp {{3 2} {2 1}} 2] 13 8 8 5 % print_matrix [matrix_exp {{3 2} {2 1}} 3] 55 34 34 21 % print_matrix [matrix_exp {{3 2} {2 1}} 4] 233 144 144 89 % print_matrix [matrix_exp {{3 2} {2 1}} 10] 1346269 832040 832040 514229
TI-89 BASIC
Built-in exponentiation:
<lang ti89b>[3,2;4,1]^4</lang>
Output:
Ursala
For matrices of floating point numbers, the library function mmult
can be used as shown. The user-defined id
function takes a square matrix to the identity matrix of the same dimensions. The mex
function takes a pair
representing a real matrix and a natural exponent to the exponentiation using the naive algorithm.
<lang Ursala>#import nat
- import lin
id = @h ^|CzyCK33/1.! 0.!* mex = ||id@l mmult:-0^|DlS/~& iota</lang> Alternatively, this version uses the fast binary algorithm. <lang Ursala>mex = ~&ar^?\id@al (~&lr?/mmult@llPrX ~&r)^/~&alrhPX mmult@falrtPXPRiiX</lang> This test program raises a 2 by 2 matrix to a selection of powers. <lang Ursala>#cast %eLLL
test = mex/*<<3.,2.>,<2.,1.>> <0,1,2,3,4,10></lang> output:
< < <1.000000e+00,0.000000e+00>, <0.000000e+00,1.000000e+00>>, < <3.000000e+00,2.000000e+00>, <2.000000e+00,1.000000e+00>>, < <1.300000e+01,8.000000e+00>, <8.000000e+00,5.000000e+00>>, < <5.500000e+01,3.400000e+01>, <3.400000e+01,2.100000e+01>>, < <2.330000e+02,1.440000e+02>, <1.440000e+02,8.900000e+01>>, < <1.346269e+06,8.320400e+05>, <8.320400e+05,5.142290e+05>>>
- Programming Tasks
- Matrices
- Java/Omit
- Ada
- ALGOL 68
- BBC BASIC
- C
- C++
- Common Lisp
- Chapel
- D
- Factor
- Fortran
- GAP
- Haskell
- J
- JavaScript
- Julia
- Liberty BASIC
- Lua
- Maple
- Mathematica
- MATLAB
- Maxima
- OCaml
- Octave
- PARI/GP
- Perl
- Perl 6
- PicoLisp
- Python
- R
- Biodem
- Racket
- Ruby
- Scala
- Scheme
- Seed7
- Tcl
- TI-89 BASIC
- TI-89 BASIC examples needing attention
- Examples needing attention
- Ursala
- Go/Omit
- Icon/Omit
- Unicon/Omit
- Pages with math errors
- Pages with math render errors