Classes for Matrix Rings and Matrix Algebras
ClassPrintName:
AC.PrintNameProc = {
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[Rope.Cat[
Convert.RopeFromCard[data.size],
" x ",
Convert.RopeFromCard[data.size],
" Matrices over ",
data.elementStructure.class.printName[data.elementStructure]
] ];
};
ClassCharacteristic:
AC.StructureRankOp = {
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[ data.elementStructure.class.characteristic[data.elementStructure] ]
};
ClassDimension:
AC.StructureRankOp = {
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[data.size * data.size]
};
ClassLegalFirstChar:
AC.LegalFirstCharOp = {
SELECT char
FROM
'[ => RETURN[TRUE];
ENDCASE;
RETURN[FALSE];
};
ClassRead:
AC.ReadOp = {
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[ReadMatrix[in, data.size, data.elementStructure] ];
};
ClassFromRope:
AC.FromRopeOp = {
stream: IO.STREAM ← IO.RIS[in];
RETURN[ ClassRead[stream, structure] ];
};
ClassToRope:
AC.ToRopeOp = {
matrix: Matrix ← NARROW[in];
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[ MatrixToRope[matrix, data.elementStructure] ] -- use defaults
};
ClassWrite:
AC.WriteOp = {
matrix: Matrix ← NARROW[in];
IO.PutRope[stream, ClassToRope[matrix, structure] ]
};
ClassZero:
AC.NullaryOp = {
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[ DiagMatrix[data.elementStructure.class.zero[data.elementStructure], data.size, data.elementStructure] ]
};
ClassOne:
AC.NullaryOp = {
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[ DiagMatrix[data.elementStructure.class.one[data.elementStructure], data.size, data.elementStructure] ]
};
ClassAdd:
AC.BinaryOp = {
firstMatrix: Matrix ← NARROW[firstArg];
secondMatrix: Matrix ← NARROW[secondArg];
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[ Add[firstMatrix, secondMatrix, data.elementStructure] ]
};
ClassNegate:
AC.UnaryOp = {
matrix: Matrix ← NARROW[arg];
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[ Negate[matrix, data.elementStructure] ]
};
ClassSubtract:
AC.BinaryOp = {
firstMatrix: Matrix ← NARROW[firstArg];
secondMatrix: Matrix ← NARROW[secondArg];
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[ Subtract[firstMatrix, secondMatrix, data.elementStructure] ]
};
ClassMultiply:
AC.BinaryOp = {
firstMatrix: Matrix ← NARROW[firstArg];
secondMatrix: Matrix ← NARROW[secondArg];
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[ Multiply[firstMatrix, secondMatrix, data.elementStructure] ]
};
ClassEqual:
AC.EqualityOp = {
firstMatrix: Matrix ← NARROW[firstArg];
secondMatrix: Matrix ← NARROW[secondArg];
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[ Equal[firstMatrix, secondMatrix, data.elementStructure] ]
};
ClassTranspose:
AC.UnaryOp = {
matrix: Matrix ← NARROW[arg];
RETURN[ Transp[matrix] ]
};
ClassDeterminant:
AC.StructuredToGroundOp = {
matrix: Matrix ← NARROW[structuredElt];
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[ Det[matrix, data.elementStructure] ]
};
matrixRingOps: MatrixOps ←
NEW[MatrixOpsRec ← [
diagonalMatrix: DiagMatrix,
transpose: ClassTranspose,
determinant: ClassDeterminant
] ];
matrixProp: Atom.DottedPair ← NEW[Atom.DottedPairNode← [$MatrixRing, matrixRingOps]]; -- having the $MatrixRing property actually means being a matrix structure but not an algebra
matrixRingClass:
PUBLIC
AC.StructureClass ←
NEW[
AC.StructureClassRec ← [
flavor: ring,
printName: ClassPrintName,
characteristic: ClassCharacteristic,
legalFirstChar: ClassLegalFirstChar,
read: ClassRead,
fromRope: ClassFromRope,
toRope: ClassToRope,
write: ClassWrite,
add: ClassAdd,
negate: ClassNegate,
subtract: ClassSubtract,
zero: ClassZero,
multiply: ClassMultiply,
commutative: FALSE,
one: ClassOne,
equal: ClassEqual,
integralDomain: FALSE,
gcdDomain: FALSE,
euclideanDomain: FALSE,
propList: LIST[matrixProp]
] ];
ClassInvert:
AC.UnaryOp = {
matrix: Matrix ← NARROW[arg];
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[ Invert[matrix, data.elementStructure] ]
};
ClassDivide:
AC.BinaryOp = {
firstMatrix: Matrix ← NARROW[firstArg];
secondMatrix: Matrix ← NARROW[secondArg];
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[ Divide[firstMatrix, secondMatrix, data.elementStructure] ]
};
ClassScalarMultiply:
AC.BinaryOp = {
scalar: REF ← firstArg;
inMatrix: Matrix ← NARROW[secondArg];
data: MatrixStructureData ← NARROW[structure.instanceData];
RETURN[ ScalarMultiply[scalar, inMatrix, data.elementStructure] ]
};
matrixAlgebraClass:
PUBLIC
AC.StructureClass ←
NEW[
AC.StructureClassRec ← [
flavor: algebra,
printName: ClassPrintName,
characteristic: ClassCharacteristic,
dimension: ClassDimension,
legalFirstChar: ClassLegalFirstChar,
read: ClassRead,
fromRope: ClassFromRope,
toRope: ClassToRope,
write: ClassWrite,
add: ClassAdd,
negate: ClassNegate,
subtract: ClassSubtract,
zero: ClassZero,
multiply: ClassMultiply,
commutative: FALSE,
invert: ClassInvert, -- it is up to the user not to try to invert a singular matrix
divide: ClassDivide,
one: ClassOne,
scalarMultiply: ClassScalarMultiply,
equal: ClassEqual,
integralDomain: FALSE,
gcdDomain: FALSE,
euclideanDomain: FALSE,
propList: LIST[matrixProp]
] ];
Conversion and IO
ReadMatrix:
PUBLIC
PROC [in:
IO.
STREAM, size:
NAT, elementStructure:
AC.Structure]
RETURNS [matrix: Matrix] = {
puncChar: CHAR;
rows: RowSeq ← NEW[RowSeqRec[size]];
[]← in.SkipWhitespace[];
puncChar ← in.GetChar[ ];
IF puncChar # '[ THEN ERROR SyntaxError[$LeftBracketExpected];
FOR i:
NAT
IN [1..size]
DO
row: Row ← NEW[RowRec[size]];
[]← in.SkipWhitespace[];
puncChar ← in.GetChar[ ];
IF puncChar # '[ THEN ERROR SyntaxError[$LeftBracketExpected];
FOR j:
NAT
IN [1..size]
DO
row[j] ← elementStructure.class.read[in, elementStructure];
[]← in.SkipWhitespace[];
puncChar ← in.GetChar[];
[]← in.SkipWhitespace[];
IF j < size THEN IF puncChar # ', THEN ERROR SyntaxError[$CommaExpected];
ENDLOOP;
IF puncChar # '] THEN ERROR SyntaxError[$RightBracketExpected];
rows[i] ← row;
puncChar ← in.GetChar[];
[]← in.SkipWhitespace[];
IF i < size THEN IF puncChar # ', THEN SyntaxError[$CommaExpected];
ENDLOOP;
IF puncChar # '] THEN ERROR SyntaxError[$RightBracketExpected];
matrix ← NEW[MatrixRec ← [size: size, rows: rows] ];
};
MatrixFromRope:
PUBLIC
PROC [in: Rope.
ROPE, size:
NAT, elementStructure:
AC.Structure]
RETURNS [out: Matrix] = {
stream: IO.STREAM ← IO.RIS[in];
out ← ReadMatrix[stream, size, elementStructure];
};
MatrixToRope:
PUBLIC
PROC [in: Matrix, elementStructure:
AC.Structure]
RETURNS [out: Rope.
ROPE] = {
out ← "[ ";
FOR i:
NAT
IN [1..in.size]
DO
out ← out.Concat["[ "];
FOR j:
NAT
IN [1..in.size]
DO
out ← out.Concat[elementStructure.class.toRope[in.rows[i][j], elementStructure] ];
IF j < in.size THEN out ← out.Concat[", "];
ENDLOOP;
out ← out.Concat["] "];
IF i < in.size THEN out ← out.Concat[", "];
ENDLOOP;
out ← out.Concat["] "];
};
WriteMatrix:
PUBLIC
PROC [in: Matrix, elementStructure:
AC.Structure, out:
IO.
STREAM] = {
out.PutF["\n %g \n", IO.rope[MatrixToRope[in, elementStructure]] ];
};
Arithmetic
Create:
PROC [size:
NAT]
RETURNS [a: Matrix] = {
a ←
NEW[MatrixRec ← [
size: size,
rows: NEW[RowSeqRec[size]]
] ];
FOR i: NAT IN [1..size] DO a.rows[i] ← NEW[RowRec[size]]; ENDLOOP;
};
Add:
PUBLIC
PROC [in1, in2: Matrix, elementStructure:
AC.Structure]
RETURNS [out: Matrix] ~ {
out ← Create[in1.size];
FOR i:
NAT
IN [1..in1.size]
DO
FOR j:
NAT
IN [1..in1.size]
DO
out.rows[i][j] ← elementStructure.class.add[in1.rows[i][j], in2.rows[i][j], elementStructure];
ENDLOOP;
ENDLOOP;
};
Negate:
PUBLIC
PROC [in: Matrix, elementStructure:
AC.Structure]
RETURNS [out: Matrix] ~ {
out ← Create[in.size];
FOR i:
NAT
IN [1..in.size]
DO
FOR j:
NAT
IN [1..in.size]
DO
out.rows[i][j] ← elementStructure.class.negate[in.rows[i][j], elementStructure];
ENDLOOP;
ENDLOOP;
};
Subtract:
PUBLIC
PROC [in1, in2: Matrix, elementStructure:
AC.Structure]
RETURNS [Matrix] ~ {
RETURN[ Add[ in1, Negate[ in2, elementStructure], elementStructure ] ];
};
Multiply:
PUBLIC
PROC [in1, in2: Matrix, elementStructure:
AC.Structure]
RETURNS [out: Matrix] ~ {
zero: REF ← elementStructure.class.zero[elementStructure];
out ← Create[in1.size];
FOR i:
NAT
IN [1..in1.size]
DO
FOR j:
NAT
IN [1..in1.size]
DO
out.rows[i][j] ← zero;
FOR k:
NAT
IN [1..in1.size]
DO
out.rows[i][j] ← elementStructure.class.add[
out.rows[i][j],
elementStructure.class.multiply[in1.rows[i][k], in2.rows[k][j], elementStructure],
elementStructure]
ENDLOOP;
ENDLOOP;
ENDLOOP;
};
Invert:
PUBLIC
PROC [in: Matrix, elementField:
AC.Structure]
RETURNS [out: Matrix] ~ {
det: REF ← Det[in, elementField];
tempVal: REF;
Aij: Matrix ← Create[in.size-1];
IF elementField.class.flavor # field THEN ERROR CantInvertError[elementField];
out ← Create[in.size];
FOR i:
NAT
IN [1..in.size]
DO
FOR j:
NAT
IN [1..in.size]
DO
MakeAij[in, Aij, i, j];
tempVal ← elementField.class.divide[Det[Aij, elementField], det, elementField]; -- error will be generated here if Det[Aij] = 0
IF NOT Even[i + j] THEN tempVal ← elementField.class.negate[tempVal, elementField];
out.rows[j][i] ← tempVal;
ENDLOOP;
ENDLOOP;
RETURN[out];
};
Divide:
PUBLIC
PROC [in1, in2: Matrix, elementField:
AC.Structure]
RETURNS [out: Matrix]~ {
RETURN[ Multiply[ in1, Invert[ in2, elementField], elementField ] ];
};
ScalarMultiply:
PUBLIC
PROC [scalar:
REF, inMatrix: Matrix, elementField:
AC.Structure]
RETURNS [outMatrix: Matrix]~ {
outMatrix ← Create[inMatrix.size];
FOR i:
NAT
IN [1..inMatrix.size]
DO
FOR j:
NAT
IN [1..inMatrix.size]
DO
outMatrix.rows[i][j] ← elementField.class.multiply[scalar, inMatrix.rows[i][j], elementField];
ENDLOOP;
ENDLOOP;
};