xref: /plan9-contrib/sys/src/libgeometry/matrix.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier /*
2*219b2ee8SDavid du Colombier  * ident(m)		store identity matrix in m
3*219b2ee8SDavid du Colombier  * matmul(a, b)		matrix multiply a*=b
4*219b2ee8SDavid du Colombier  * matmulr(a, b)	matrix multiply a=b*a
5*219b2ee8SDavid du Colombier  * determinant(m)	returns det(m)
6*219b2ee8SDavid du Colombier  * adjoint(m, minv)	minv=adj(m)
7*219b2ee8SDavid du Colombier  * invertmat(m, minv)	invert matrix m, result in minv, returns det(m)
8*219b2ee8SDavid du Colombier  *			if m is singular, minv=adj(m)
9*219b2ee8SDavid du Colombier  */
10*219b2ee8SDavid du Colombier #include <u.h>
11*219b2ee8SDavid du Colombier #include <libc.h>
12*219b2ee8SDavid du Colombier #include <libg.h>
13*219b2ee8SDavid du Colombier #include <geometry.h>
14*219b2ee8SDavid du Colombier void ident(Matrix m){
15*219b2ee8SDavid du Colombier 	register double *s=&m[0][0];
16*219b2ee8SDavid du Colombier 	*s++=1;*s++=0;*s++=0;*s++=0;
17*219b2ee8SDavid du Colombier 	*s++=0;*s++=1;*s++=0;*s++=0;
18*219b2ee8SDavid du Colombier 	*s++=0;*s++=0;*s++=1;*s++=0;
19*219b2ee8SDavid du Colombier 	*s++=0;*s++=0;*s++=0;*s=1;
20*219b2ee8SDavid du Colombier }
21*219b2ee8SDavid du Colombier void matmul(Matrix a, Matrix b){
22*219b2ee8SDavid du Colombier 	register i, j, k;
23*219b2ee8SDavid du Colombier 	double sum;
24*219b2ee8SDavid du Colombier 	Matrix tmp;
25*219b2ee8SDavid du Colombier 	for(i=0;i!=4;i++) for(j=0;j!=4;j++){
26*219b2ee8SDavid du Colombier 		sum=0;
27*219b2ee8SDavid du Colombier 		for(k=0;k!=4;k++)
28*219b2ee8SDavid du Colombier 			sum+=a[i][k]*b[k][j];
29*219b2ee8SDavid du Colombier 		tmp[i][j]=sum;
30*219b2ee8SDavid du Colombier 	}
31*219b2ee8SDavid du Colombier 	for(i=0;i!=4;i++) for(j=0;j!=4;j++)
32*219b2ee8SDavid du Colombier 		a[i][j]=tmp[i][j];
33*219b2ee8SDavid du Colombier }
34*219b2ee8SDavid du Colombier void matmulr(Matrix a, Matrix b){
35*219b2ee8SDavid du Colombier 	register i, j, k;
36*219b2ee8SDavid du Colombier 	double sum;
37*219b2ee8SDavid du Colombier 	Matrix tmp;
38*219b2ee8SDavid du Colombier 	for(i=0;i!=4;i++) for(j=0;j!=4;j++){
39*219b2ee8SDavid du Colombier 		sum=0;
40*219b2ee8SDavid du Colombier 		for(k=0;k!=4;k++)
41*219b2ee8SDavid du Colombier 			sum+=b[i][k]*a[k][j];
42*219b2ee8SDavid du Colombier 		tmp[i][j]=sum;
43*219b2ee8SDavid du Colombier 	}
44*219b2ee8SDavid du Colombier 	for(i=0;i!=4;i++) for(j=0;j!=4;j++)
45*219b2ee8SDavid du Colombier 		a[i][j]=tmp[i][j];
46*219b2ee8SDavid du Colombier }
47*219b2ee8SDavid du Colombier /*
48*219b2ee8SDavid du Colombier  * Return det(m)
49*219b2ee8SDavid du Colombier  */
50*219b2ee8SDavid du Colombier double determinant(Matrix m){
51*219b2ee8SDavid du Colombier 	return m[0][0]*(m[1][1]*(m[2][2]*m[3][3]-m[2][3]*m[3][2])+
52*219b2ee8SDavid du Colombier 			m[1][2]*(m[2][3]*m[3][1]-m[2][1]*m[3][3])+
53*219b2ee8SDavid du Colombier 			m[1][3]*(m[2][1]*m[3][2]-m[2][2]*m[3][1]))
54*219b2ee8SDavid du Colombier 	      -m[0][1]*(m[1][0]*(m[2][2]*m[3][3]-m[2][3]*m[3][2])+
55*219b2ee8SDavid du Colombier 			m[1][2]*(m[2][3]*m[3][0]-m[2][0]*m[3][3])+
56*219b2ee8SDavid du Colombier 			m[1][3]*(m[2][0]*m[3][2]-m[2][2]*m[3][0]))
57*219b2ee8SDavid du Colombier 	      +m[0][2]*(m[1][0]*(m[2][1]*m[3][3]-m[2][3]*m[3][1])+
58*219b2ee8SDavid du Colombier 			m[1][1]*(m[2][3]*m[3][0]-m[2][0]*m[3][3])+
59*219b2ee8SDavid du Colombier 			m[1][3]*(m[2][0]*m[3][1]-m[2][1]*m[3][0]))
60*219b2ee8SDavid du Colombier 	      -m[0][3]*(m[1][0]*(m[2][1]*m[3][2]-m[2][2]*m[3][1])+
61*219b2ee8SDavid du Colombier 			m[1][1]*(m[2][2]*m[3][0]-m[2][0]*m[3][2])+
62*219b2ee8SDavid du Colombier 			m[1][2]*(m[2][0]*m[3][1]-m[2][1]*m[3][0]));
63*219b2ee8SDavid du Colombier }
64*219b2ee8SDavid du Colombier /*
65*219b2ee8SDavid du Colombier  * Store the adjoint (matrix of cofactors) of m in madj.
66*219b2ee8SDavid du Colombier  * Works fine even if m and madj are the same matrix.
67*219b2ee8SDavid du Colombier  */
68*219b2ee8SDavid du Colombier void adjoint(Matrix m, Matrix madj){
69*219b2ee8SDavid du Colombier 	double m00=m[0][0], m01=m[0][1], m02=m[0][2], m03=m[0][3];
70*219b2ee8SDavid du Colombier 	double m10=m[1][0], m11=m[1][1], m12=m[1][2], m13=m[1][3];
71*219b2ee8SDavid du Colombier 	double m20=m[2][0], m21=m[2][1], m22=m[2][2], m23=m[2][3];
72*219b2ee8SDavid du Colombier 	double m30=m[3][0], m31=m[3][1], m32=m[3][2], m33=m[3][3];
73*219b2ee8SDavid du Colombier 	madj[0][0]=m11*(m22*m33-m23*m32)+m21*(m13*m32-m12*m33)+m31*(m12*m23-m13*m22);
74*219b2ee8SDavid du Colombier 	madj[0][1]=m01*(m23*m32-m22*m33)+m21*(m02*m33-m03*m32)+m31*(m03*m22-m02*m23);
75*219b2ee8SDavid du Colombier 	madj[0][2]=m01*(m12*m33-m13*m32)+m11*(m03*m32-m02*m33)+m31*(m02*m13-m03*m12);
76*219b2ee8SDavid du Colombier 	madj[0][3]=m01*(m13*m22-m12*m23)+m11*(m02*m23-m03*m22)+m21*(m03*m12-m02*m13);
77*219b2ee8SDavid du Colombier 	madj[1][0]=m10*(m23*m32-m22*m33)+m20*(m12*m33-m13*m32)+m30*(m13*m22-m12*m23);
78*219b2ee8SDavid du Colombier 	madj[1][1]=m00*(m22*m33-m23*m32)+m20*(m03*m32-m02*m33)+m30*(m02*m23-m03*m22);
79*219b2ee8SDavid du Colombier 	madj[1][2]=m00*(m13*m32-m12*m33)+m10*(m02*m33-m03*m32)+m30*(m03*m12-m02*m13);
80*219b2ee8SDavid du Colombier 	madj[1][3]=m00*(m12*m23-m13*m22)+m10*(m03*m22-m02*m23)+m20*(m02*m13-m03*m12);
81*219b2ee8SDavid du Colombier 	madj[2][0]=m10*(m21*m33-m23*m31)+m20*(m13*m31-m11*m33)+m30*(m11*m23-m13*m21);
82*219b2ee8SDavid du Colombier 	madj[2][1]=m00*(m23*m31-m21*m33)+m20*(m01*m33-m03*m31)+m30*(m03*m21-m01*m23);
83*219b2ee8SDavid du Colombier 	madj[2][2]=m00*(m11*m33-m13*m31)+m10*(m03*m31-m01*m33)+m30*(m01*m13-m03*m11);
84*219b2ee8SDavid du Colombier 	madj[2][3]=m00*(m13*m21-m11*m23)+m10*(m01*m23-m03*m21)+m20*(m03*m11-m01*m13);
85*219b2ee8SDavid du Colombier 	madj[3][0]=m10*(m22*m31-m21*m32)+m20*(m11*m32-m12*m31)+m30*(m12*m21-m11*m22);
86*219b2ee8SDavid du Colombier 	madj[3][1]=m00*(m21*m32-m22*m31)+m20*(m02*m31-m01*m32)+m30*(m01*m22-m02*m21);
87*219b2ee8SDavid du Colombier 	madj[3][2]=m00*(m12*m31-m11*m32)+m10*(m01*m32-m02*m31)+m30*(m02*m11-m01*m12);
88*219b2ee8SDavid du Colombier 	madj[3][3]=m00*(m11*m22-m12*m21)+m10*(m02*m21-m01*m22)+m20*(m01*m12-m02*m11);
89*219b2ee8SDavid du Colombier }
90*219b2ee8SDavid du Colombier /*
91*219b2ee8SDavid du Colombier  * Store the inverse of m in minv.
92*219b2ee8SDavid du Colombier  * If m is singular, minv is instead its adjoint.
93*219b2ee8SDavid du Colombier  * Returns det(m).
94*219b2ee8SDavid du Colombier  * Works fine even if m and minv are the same matrix.
95*219b2ee8SDavid du Colombier  */
96*219b2ee8SDavid du Colombier double invertmat(Matrix m, Matrix minv){
97*219b2ee8SDavid du Colombier 	double d, dinv;
98*219b2ee8SDavid du Colombier 	int i, j;
99*219b2ee8SDavid du Colombier 	d=determinant(m);
100*219b2ee8SDavid du Colombier 	adjoint(m, minv);
101*219b2ee8SDavid du Colombier 	if(d!=0.){
102*219b2ee8SDavid du Colombier 		dinv=1./d;
103*219b2ee8SDavid du Colombier 		for(i=0;i!=4;i++) for(j=0;j!=4;j++) minv[i][j]*=dinv;
104*219b2ee8SDavid du Colombier 	}
105*219b2ee8SDavid du Colombier 	return d;
106*219b2ee8SDavid du Colombier }
107