<?xml version="1.0" encoding="UTF-8"?>
<Worksheet><Version major="6" minor="1"/><View-Properties><Zoom percentage="100"/></View-Properties><Styles><Layout alignment="left" bullet="none" firstindent="0.0" leftmargin="0.0" linebreak="space" linespacing="0.0" name="Normal" rightmargin="0.0" spaceabove="0.0" spacebelow="0.0"/><Font background="[0,0,0]" bold="true" executable="true" family="Monospaced" foreground="[255,0,0]" name="Maple Input" opaque="false" size="12"/></Styles><Group><Input><Text-field layout="Normal" prompt="&gt; " style="Maple Input"><Font italic="false" size="10" subscript="false" superscript="false" underline="false">COSVAM := module()

	option package, load = oLoad, unload = oUnLoad:
	local oLoad, oUnLoad, oKernel, oUnits, oTriples, oTableIm, oTable, oAddSubCheck:
	export	
		oVersion, oGetUnits, oSetTriples, oGetTriples, oGetTable,
		oImToL, oImToV, oToL, oToV, oImFromL, oImFromV, oFromL, oFromV,
		oNorm, oInner, oConj, oHermConj, oRe, oIm, oInv,
		oCos, oSin, oTan, oCot, oCosh, oSinh, oTanh,	oCoth,
		oExp, oLn, oPowerInt, oPower, oAdd, oSub, oMul, oDiv, oCom, oAntiCom, oAssoc,
		oImCross, oCross, v7Cross, v8Cross, oArea, oVolume, v7Area, v8Volume,
		oTrace, oDotProd:

	###########################################################################################
	# DOCUMENTATION									#
	###########################################################################################

	oVersion := proc()
		print(`------------------------------------------------------------------------------------`):
		print(`COSVAM - Complex-Octonion Scalars, Vectors, And Matrices`):
		print(`A Maple Package for Computation with`):
		print(`Complex-Octonion-valued Scalars, Vectors, and Matrices`):
		print(`Last revised: March 19, 2005`):
		print(`Copyright 2005, by John Fredsted`):
		print(`Tranbjergvej 35, DK-8310 Tranbjerg, Denmark`):
		print(`Email: johnfredsted@mail.dk`):
		print(`------------------------------------------------------------------------------------`):
	end proc:

	###########################################################################################
	# KERNEL: NO TYPECHECKING / POLYMORPHISM - NOT DIRECTLY ACCESSIBLE			#
	###########################################################################################

	oKernel := module()
		export
			oSimplify, oConj, oRe, oIm, oNorm, oInner,
			oImToL, oImToV, oToL, oToV, oImFromL, oImFromV, oFromL, oFromV,
			oMul, oInv, oDiv, oPowerInt, oExp, oLn, oPower, oCom, oAntiCom, oAssoc,
			oImCross, oCross, v7Cross, v8Cross, oArea, oVolume,
			oCos, oSin, oTan, oCot, oCosh, oSinh, oTanh, oCoth:
		oSimplify := (o) -&gt; collect(simplify(o),{op(oUnits)}):
		oConj := proc(o)
			option remember:
			subs(seq(oUnits[i] = -oUnits[i],i=1..7),o):
		end proc:
		oRe := proc(o)
			option remember:
			oSimplify((o + oConj(o)) / 2):
		end proc:
		oIm := proc(o)
			option remember:
			oSimplify((o - oConj(o)) / 2):
		end proc:
		oImToL := proc(o)
			option remember:
			oSimplify(map2(diff,o,oUnits)):
		end proc:
		oImToV := proc(o)
			option remember:
			Vector(oImToL(o)):
		end proc:
		oToL := proc(o)
			option remember:
			oSimplify([oRe(o),op(map2(diff,oIm(o),oUnits))]):
		end proc:
		oToV := proc(o)
			option remember:
			Vector(oToL(o)):
		end proc:
		oImFromL := proc(l)
			option remember:
			add(l[i] * oUnits[i],i=1..7):
		end proc:
		oImFromV := proc(v)
			option remember:
			oImFromL(convert(v,list)):
		end proc:
		oFromL := proc(l)
			option remember:
			l[1] + add(l[i+1] * oUnits[i],i=1..7):
		end proc:
		oFromV := proc(v)
			option remember:
			oFromL(convert(v,list)):
		end proc:
		oNorm := proc(o)
			option remember:
			simplify(LinearAlgebra:-VectorNorm(oToV(o),2,conjugate=false)):
		end proc:
		oInner := proc(o1,o2)
			option remember:
			simplify(LinearAlgebra:-DotProduct(oToV(o1),oToV(o2),conjugate=false)):
		end proc:
		oMul := proc(o1,o2)
			option remember:
			oSimplify(LinearAlgebra:-Multiply(
				LinearAlgebra:-Transpose(oToV(o1)),
				LinearAlgebra:-Multiply(oTable,oToV(o2))
			)):
		end proc:
		oInv := proc(o)
			option remember:
			if oNorm(o) = 0 then error "No inverse exists because the norm is zero" end if:
			oSimplify(oConj(o) / oNorm(o)^2):
		end proc:
		oDiv := proc(o1,o2)
			option remember:
			oSimplify(oMul(o1,oInv(o2))):
		end proc:
		oExp := proc(o)
			option remember:
			local r, i, n:
			r, i := oRe(o), oIm(o):
			n := oNorm(i):
			if n = 0 then return oSimplify(exp(r) * (1 + i)) end if:
			if n &lt;&gt; 0 then return exp(r) * (cos(n) + sin(n) * i/n) end if:
		end proc:
		oLn := proc(o)
			option remember:
			local r, i, n:
			r, i := oKernel:-oRe(o), oKernel:-oIm(o):
			n := oKernel:-oNorm(i):
			if r &lt;&gt; 0 and n &lt;&gt; 0 then return ln(sqrt(r^2 + n^2)) + arctan(n/r) * i/n end if:
			if r &lt;&gt; 0 and n = 0 then return ln(r) + i/r end if:
			if r = 0 and n &lt;&gt; 0 then return ln(n) + Pi/2 * i/n end if:
			error "oLn is undefined":
		end proc:
		oPowerInt := proc(o,n)
			option remember:
			local o_:
			if n &lt; 0 then return oInv(oPowerInt(o,-n)) end if:
			if n = 0 then return 1 end if:
			if n = 1 then return o end if:
			if n &gt; 1  then
				o_ := oPowerInt(o,floor(n/2)):
				if type(n,even) then return oMul(o_,o_) end if:
				if type(n,odd) then return oMul(o,oMul(o_,o_)) end if:
			end if:
		end proc:
		oPower := proc(o,c)
			option remember:
			if type(c,integer) then return oPowerInt(o,c) end if:
			oSimplify(oExp(c * oLn(o))):
		end proc:
		oCom := proc(o1,o2)
			option remember:
			oSimplify(oSub(oMul(o1,o2),oMul(o2,o1))):
		end proc:
		oAntiCom := proc(o1,o2)
			option remember:
			oSimplify(oAdd(oMul(o1,o2),oMul(o2,o1))):
		end proc:
		oAssoc := proc(o1,o2,o3)
			option remember:
			oSimplify(oSub(oMul(oMul(o1,o2),o3),oMul(o1,oMul(o2,o3)))):
		end proc:
		oImCross := proc(o1,o2)
			option remember:
			oSimplify(oCom(o1,o2) / 2):
		end proc:
		oCross := proc(o1,o2,o3)
			option remember:
			local f1, f2, f3:
			f1 := oMul(o1,oSub(oMul(oConj(o2),o3),oMul(oConj(o3),o2))):
			f2 := oMul(o2,oSub(oMul(oConj(o3),o1),oMul(oConj(o1),o3))):
			f3 := oMul(o3,oSub(oMul(oConj(o1),o2),oMul(oConj(o2),o1))):
			oSimplify(oAdd(f1,oAdd(f2,f3)) / 6):
		end proc:
		oArea := proc(o1,o2)
			option remember:
			sqrt(LinearAlgebra:-Determinant(
				Matrix([[oInner(o1,o1),oInner(o1,o2)],[oInner(o2,o1),oInner(o2,o2)]]))):
		end proc:
		oVolume := proc(o1,o2,o3)
			option remember:
			sqrt(LinearAlgebra:-Determinant(Matrix(
				[[oInner(o1,o1),oInner(o1,o2),oInner(o1,o3)],
				[oInner(o2,o1),oInner(o2,o2),oInner(o2,o3)],
				[oInner(o3,o1),oInner(o3,o2),oInner(o3,o3)]])
			)):
		end proc:
		oCos := proc(o)
			option remember:
			oSimplify((oExp(I*o) + oExp(-I*o))/2):
		end proc:
		oSin := proc(o)
			option remember:
			oSimplify((oExp(I*o) - oExp(-I*o))/ (2*I)):
		end proc:
		oTan := proc(o)
			option remember:
			if oNorm(oCos(o)) = 0 then error "oTan is undefined because oCos is zero" end if:
			oDiv(oSin(o),oCos(o)):
		end proc:
		oCot := proc(o)
			option remember:
			if oNorm(oSin(o)) = 0 then error "oCot is undefined because oSin is zero" end if:
			oDiv(oCos(o),oSin(o)):
		end proc:
		oCosh := proc(o)
			option remember:
			oSimplify((oExp(o) + oExp(-o))/2):
		end proc:
		oSinh := proc(o)
			option remember:
			oSimplify((oExp(o) - oExp(-o))/ 2):
		end proc:
		oTanh := proc(o)
			option remember:
			if oNorm(oCosh(o)) = 0 then error "oTanh is undefined because oCosh is zero" end if:
			oDiv(oSinh(o),oCosh(o)):
		end proc:
		oCoth := proc(o)
			option remember:
			if oNorm(oSinh(o)) = 0 then error "oCoth is undefined because oSinh is zero" end if:
			oDiv(oCosh(o),oSinh(o)):
		end proc:
	end module:

	###########################################################################################
	# SHELL: TYPECHECKING / POLYMORPHISM - DIRECTLY ACCESSIBLE				#
	###########################################################################################

	# ENVIRONMENT PROCEDURES
	oSetTriples := proc(triples)
		local count, triple, unit, i, j, k:
		# CHECK
		count := [seq(0,i=1..7)]:
		if not type(triples,list) then error "The argument must be a list of triples" end if:
		if nops(triples) &lt;&gt; 7 then error "There must be seven triples" end if:
		for triple in triples do
			if not type(triple,list) then error "Each triple must be a list" end if:
			if nops(triple) &lt;&gt; 3 then error "Each triple must consists of three units" end if:
			for unit in triple do
				if not member(unit,oUnits) then
					error "A nonexisting unit name has been specified":
				end if:
				if unit = oUnits[1] then count[1] := count[1] + 1 end if:
				if unit = oUnits[2] then count[2] := count[2] + 1 end if:
				if unit = oUnits[3] then count[3] := count[3] + 1 end if:
				if unit = oUnits[4] then count[4] := count[4] + 1 end if:
				if unit = oUnits[5] then count[5] := count[5] + 1 end if:
				if unit = oUnits[6] then count[6] := count[6] + 1 end if:
				if unit = oUnits[7] then count[7] := count[7] + 1 end if:
			end do:
		end do:
		if count &lt;&gt; [seq(3,i=1..7)] then
			error "Each unit must be in exactly three triples"
		end if:
		# BUILD oTableIm
		for i from 1 to 7 do
		for j from 1 to 7 do
			if i = j then oTableIm[i,j] := -1 end if:
			if i &lt;&gt; j then
				for k from 1 to 7 do
				if is(oUnits[i] in triples[k]) and (oUnits[j] in triples[k]) then
					if oUnits[i] = triples[k][1] and oUnits[j] = triples[k][2] then
						oTableIm[i,j] := triples[k][3] end if:
					if oUnits[i] = triples[k][2] and oUnits[j] = triples[k][3] then
						oTableIm[i,j] := triples[k][1] end if:
					if oUnits[i] = triples[k][3] and oUnits[j] = triples[k][1] then
						oTableIm[i,j] := triples[k][2] end if:
					if oUnits[i] = triples[k][2] and oUnits[j] = triples[k][1] then
						oTableIm[i,j] := -triples[k][3] end if:
					if oUnits[i] = triples[k][3] and oUnits[j] = triples[k][2] then
						oTableIm[i,j] := -triples[k][1] end if:
					if oUnits[i] = triples[k][1] and oUnits[j] = triples[k][3] then
						oTableIm[i,j] := -triples[k][2] end if:
				end if:
				end do:
			end if:
		end do:
		end do:
		# BUILD oTable
		oTable[1,1] := 1:
		for i from 1 to 7 do
			oTable[1,i+1] := oUnits[i]:
			oTable[i+1,1] := oUnits[i]:
			for j from 1 to 7 do
				oTable[i+1,j+1] := oTableIm[i,j]:
			end do:
		end do:
		# RETURN
		oTriples := triples:
	end proc:
	oGetUnits := () -&gt; oUnits:
	oGetTriples := () -&gt; oTriples:
	oGetTable := () -&gt; oTable:

	# MATHEMATICAL PROCEDURES
	oImToL := (o::oImScalar) -&gt; oKernel:-oImToL(o):
	oImToV := (o::oImScalar) -&gt; oKernel:-oImToV(o):
	oToL := (o::oScalar) -&gt; oKernel:-oToL(o):
	oToV := (o::oScalar) -&gt; oKernel:-oToV(o):
	oImFromL := (l::[oReScalar,oReScalar,oReScalar,oReScalar,oReScalar,oReScalar,oReScalar]) -&gt;
		oKernel:-oImFromL(l):
	oImFromV := (v::'Vector'(7,oReScalar)) -&gt; oKernel:-oImFromV(v):
	oFromL := (l::[oReScalar,oReScalar,oReScalar,oReScalar,oReScalar,oReScalar,oReScalar,oReScalar]) -&gt;
		oKernel:-oFromL(l):
	oFromV := (v::'Vector'(8,oReScalar)) -&gt; oKernel:-oFromV(v):
	oRe := proc(o::{oScalar,oVector,oMatrix})
		if type(o,oScalar) then return oKernel:-oRe(o) end if:
		if type(o,oVector) or type(o,oMatrix) then return simplify(map(oKernel:-oRe,o)) end if:
	end proc:
	oIm := proc(o::{oScalar,oVector,oMatrix})
		if type(o,oScalar) then return oKernel:-oIm(o) end if:
		if type(o,oVector) or type(o,oMatrix) then return simplify(map(oKernel:-oIm,o)) end if:
	end proc:
	oConj := proc(o::{oScalar,oVector,oMatrix})
		if type(o,oScalar) then return oKernel:-oConj(o) end if:
		if type(o,oVector) or type(o,oMatrix) then return simplify(map(oKernel:-oConj,o)) end if:
	end proc:
	oHermConj := proc(o::{oScalar,oVector,oMatrix})
		if type(o,oScalar) then return oConj(o) end if:
		if type(o,oVector) or type(o,oMatrix) then
			simplify(map(oKernel:-oConj,LinearAlgebra:-Transpose(o))):
		end if:
	end proc:
	oNorm := (o::oScalar) -&gt; oKernel:-oNorm(o):
	oCos := (o::oScalar) -&gt; oKernel:-oCos(o):
	oSin := (o::oScalar) -&gt; oKernel:-oSin(o):
	oTan := (o::oScalar) -&gt; oKernel:-oTan(o):
	oCot := (o::oScalar) -&gt; oKernel:-oCot(o):
	oCosh := (o::oScalar) -&gt; oKernel:-oCosh(o):
	oSinh := (o::oScalar) -&gt; oKernel:-oSinh(o):
	oTanh := (o::oScalar) -&gt; oKernel:-oTanh(o):
	oCoth := (o::oScalar) -&gt; oKernel:-oCoth(o):
	oExp := (o::oScalar) -&gt; oKernel:-oExp(o):
	oLn := (o::oScalar) -&gt; oKernel:-oLn(o):
	oInv := (o::oScalar) -&gt; oKernel:-oInv(o):
	oPowerInt := proc(o::{oScalar,oMatrix},n::integer)
		local o_:
		if type(o,oScalar) then return oKernel:-oPowerInt(o,n) end if:
		if type(o,oMatrix) then
			if nops({LinearAlgebra:-Dimension(o)}) &gt; 1 then
				error "The matrix must be a square matrix":
			end if:
			if n &lt; 0 then error "For a matrix the exponent must be nonnegative" end if:
			if n = 0 then return Matrix(LinearAlgebra:-Dimension(o),shape=identity) end if:
			if n &gt; 0 then
				o_ := oPowerInt(o,floor(n/2)):
				if type(n,even) then return oMul(o_,o_) end if:
				if type(n,odd) then return oMul(o,oMul(o_,o_)) end if:
			end if:
		end if:
	end proc:
	oPower := proc(o::{oScalar,oMatrix},c::scalar)
		if type(o,oScalar) then return oKernel:-oPower(o,c) end if:
		if type(o,oMatrix) then
			if not (c = 0 or type(c,posint)) then
				error "For a matrix the exponent must be a nonnegative integer":
			end if:
			return oPowerInt(o,c):
		end if:
	end proc:
	oTrace := proc(o::{oScalar,oMatrix})
		if type(o,oScalar) then return o end if:
		if type(o,oMatrix) then
			if nops({LinearAlgebra:-Dimension(o)}) &gt; 1 then
				error "The matrix must be a square matrix":
			end if:
			return oKernel:-oSimplify(LinearAlgebra:-Trace(o)):
		end if:
	end proc:
	oInner := (o1::oScalar,o2::oScalar) -&gt; oKernel:-oInner(o1,o2):
	oAddSubCheck := proc(o1,o2)
		if not (
			(type(o1,oScalar) and type(o2,oScalar)) or
			(type(o1,oVector) and type(o2,oVector)) or
			(type(o1,oMatrix) and type(o2,oMatrix))
		) then
			return "The arguments must be both either scalars, vectors, or matrices":
		end if:
		if type(o1,oVector) and type(o2,oVector) then
			if nops({LinearAlgebra:-Dimension(o1),LinearAlgebra:-Dimension(o2)}) &gt; 1 then
				return "The vectors must have the same dimension" end if:
			end if:
			if
			(type(o1,Vector[column]) and type(o2,Vector[row])) or
			(type(o1,Vector[row]) and type(o2,Vector[column])) then
				return "The vectors must be both either columns or rows":
			end if:
		if type(o1,oMatrix) and type(o2,oMatrix) then
			if nops({LinearAlgebra:-Dimension(o1),LinearAlgebra:-Dimension(o2)}) &gt; 1 then
				return "The matrices must have the same dimensions":
			end if:
		end if:
		return NULL:
	end proc:
	oAdd := proc(o1::{oScalar,oVector,oMatrix},o2::{oScalar,oVector,oMatrix})
		local check:
		check := oAddSubCheck(o1,o2):
		if check &lt;&gt; NULL then error check end if:
		map(oKernel:-oSimplify,o1 + o2):
	end proc:
	oSub := proc(o1::{oScalar,oVector,oMatrix},o2::{oScalar,oVector,oMatrix})
		local check:
		check := oAddSubCheck(o1,o2):
		if check &lt;&gt; NULL then error check end if:
		map(oKernel:-oSimplify,o1 - o2):
	end proc:
	oMul := proc(o1::{oScalar,oVector,oMatrix},o2::{oScalar,oVector,oMatrix})
		local dim, dim1, dim2, dims, i, j, o:
		if type(o1,oScalar) and type(o2,oScalar) then return oKernel:-oMul(o1,o2) end if:
		if type(o1,oScalar) and type(o2,oVector) then return map((x) -&gt; oKernel:-oMul(o1,x),o2) end if:
		if type(o1,oScalar) and type(o2,oMatrix) then return map((x) -&gt; oKernel:-oMul(o1,x),o2) end if:
		if type(o1,oVector) and type(o2,oScalar) then return map((x) -&gt; oKernel:-oMul(x,o2),o1) end if:
		if type(o1,oVector) and type(o2,oVector) then
			if type(o1,Vector[row]) and type(o2,Vector[column]) then
				dim := {LinearAlgebra:-Dimension(o1),LinearAlgebra:-Dimension(o2)}:
				if nops(dim) = 1 then
					return oKernel:-oSimplify(add(oKernel:-oMul(o1[i],o2[i]),i=1..op(dim))):
				end if:
			end if:
			if type(o1,Vector[column]) and type(o2,Vector[row]) then
				dim := [LinearAlgebra:-Dimension(o1),LinearAlgebra:-Dimension(o2)]:
				o := Matrix(1..op(dim)[1],1..op(dim)[2]):
				for i from 1 to op(dim)[1] do
				for j from 1 to op(dim)[2] do
					o[i,j] := oKernel:-oMul(o1[i],o2[j]):
				end do:
				end do:
				return o:
			end if:
			error "Arguments are incompatible for multiplication":
		end if:
		if type(o1,oVector) and type(o2,oMatrix) then
			if type(o1,Vector[row]) then
				dims := {LinearAlgebra:-Dimension(o1),LinearAlgebra:-Dimension(o2)[1]}:
				if nops(dims) = 1 then
					dim := LinearAlgebra:-Dimension(o2)[2]:
					o := Vector[row](1..dim):
					for i from 1 to dim do
						o[i] := oKernel:-oSimplify(
							add(oKernel:-oMul(o1[j],o2[j,i]),j=1..op(dims))
						):
					end do:
					return o:
				end if:
			end if:
			error "Arguments are incompatible for multiplication":
		end if:
		if type(o1,oMatrix) and type(o2,oScalar) then return map((x) -&gt; oKernel:-oMul(x,o2),o1) end if:
		if type(o1,oMatrix) and type(o2,oVector) then
			if type(o2,Vector[column]) then
				dims := {LinearAlgebra:-Dimension(o1)[2],LinearAlgebra:-Dimension(o2)}:
				if nops(dims) = 1 then
					dim := LinearAlgebra:-Dimension(o1)[1]:
					o := Vector[column](1..dim):
					for i from 1 to dim do
						o[i] := oKernel:-oSimplify(
							add(oKernel:-oMul(o1[i,j],o2[j]),j=1..op(dims))
						):
					end do:
					return o:
				end if:
			end if:
			error "Arguments are incompatible for multiplication":
		end if:
		if type(o1,oMatrix) and type(o2,oMatrix) then
			dims := {LinearAlgebra:-Dimension(o1)[2],LinearAlgebra:-Dimension(o2)[1]}:
			if nops(dims) = 1 then
				dim1 := LinearAlgebra:-Dimension(o1)[1]:
				dim2 := LinearAlgebra:-Dimension(o2)[2]:
				o := Matrix(1..dim1,1..dim2):
				for i from 1 to dim1 do
				for j from 1 to dim2 do
					o[i,j] := oKernel:-oSimplify(
						add(oKernel:-oMul(o1[i,k],o2[k,j]),k=1..op(dims))
					):
				end do:
				end do:
				return o:
			end if:
			error "Arguments are incompatible for multiplication":
		end if:
	end proc:
	oDiv := proc(o1::{oScalar,oVector,oMatrix},o2::oScalar)
		if oKernel:-oNorm(o2) = 0 then error "The norm of the divisor is zero" end if:
		return map((x) -&gt; oKernel:-oDiv(x,o2),o1):
	end proc:
	oCom := proc(o1::{oScalar,oVector,oMatrix},o2::{oScalar,oVector,oMatrix})
		if type(o1,oScalar) and type(o2,oScalar) then return oKernel:-oCom(o1,o2) end if:
		if (
		(type(o1,oScalar) and type(o2,oVector)) or
		(type(o1,oScalar) and type(o2,oMatrix)) or
		(type(o1,oVector) and type(o2,oScalar)) or
		(type(o1,oMatrix) and type(o2,oScalar))) then
			return oSub(oMul(o1,o2),oMul(o2,o1))
		end if:
		if type(o1,oMatrix) and type(o2,oMatrix) then
			if nops({LinearAlgebra:-Dimension(o1)} union {LinearAlgebra:-Dimension(o2)}) &gt; 1 then
				error "Both matrices must be square matrices of the same dimensions":
			end if:
			return oSub(oMul(o1,o2),oMul(o2,o1)):
		end if:
		error "Illegal arguments":
	end proc:
	oAntiCom := proc(o1::{oScalar,oVector,oMatrix},o2::{oScalar,oVector,oMatrix})
		if type(o1,oScalar) and type(o2,oScalar) then return oKernel:-oAntiCom(o1,o2) end if:
		if (
		(type(o1,oScalar) and type(o2,oVector)) or
		(type(o1,oScalar) and type(o2,oMatrix)) or
		(type(o1,oVector) and type(o2,oScalar)) or
		(type(o1,oMatrix) and type(o2,oScalar))) then
			return oAdd(oMul(o1,o2),oMul(o2,o1))
		end if:
		if type(o1,oMatrix) and type(o2,oMatrix) then
			if nops({LinearAlgebra:-Dimension(o1)} union {LinearAlgebra:-Dimension(o2)}) &gt; 1 then
				error "Both matrices must be square matrices of the same dimensions":
			end if:
			return oAdd(oMul(o1,o2),oMul(o2,o1)):
		end if:
		error "Illegal arguments":
	end proc:
	oAssoc := proc(o1::{oScalar,oMatrix},o2::{oScalar,oMatrix},o3::{oScalar,oMatrix})
		if type(o1,oScalar) and type(o2,oScalar) and type(o3,oScalar) then
			return oKernel:-oAssoc(o1,o2,o3)
		end if:
		if type(o1,oMatrix) and type(o2,oMatrix) and type(o3,oMatrix) then
			if nops(
				{LinearAlgebra:-Dimension(o1)} union
				{LinearAlgebra:-Dimension(o2)} union
				{LinearAlgebra:-Dimension(o3)}
			) &gt; 1 then
				error "All matrices must be square matrices of the same dimensions":
			end if:
			return oSub(oMul(oMul(o1,o2),o3),oMul(o1,oMul(o2,o3))):
		end if:
		error "The arguments must all be scalars or square matrices":
	end proc:
	oDotProd := proc(o1::oVector,o2::oVector)
		if LinearAlgebra:-Dimension(o1) &lt;&gt; LinearAlgebra:-Dimension(o2) then
			error "The vectors must have the same dimensionality":
		end if:
		if type(o1,Vector[column]) and type(o2,Vector[column]) then
			return oMul(LinearAlgebra:-Transpose(o1),o2):
		end if:
		if type(o1,Vector[column]) and type(o2,Vector[row]) then
			return oMul(LinearAlgebra:-Transpose(o1),LinearAlgebra:-Transpose(o2)):
		end if:
		if type(o1,Vector[row]) and type(o2,Vector[column]) then
			return oMul(o1,o2):
		end if:
		if type(o1,Vector[row]) and type(o2,Vector[row]) then
			return oMul(o1,LinearAlgebra:-Transpose(o2)):
		end if:
	end proc:
	oImCross := (o1::oImScalar,o2::oImScalar) -&gt; oKernel:-oImCross(o1,o2):
	oCross := (o1::oScalar,o2::oScalar,o3::oScalar) -&gt; oKernel:-oCross(o1,o2,o3):
	v7Cross := proc(v1::'Vector'(7,oReScalar),v2::'Vector'(7,oReScalar))
		oImToV(oImCross(oImFromV(v1),oImFromV(v2))):
	end proc:
	v8Cross := proc(v1::'Vector'(8,oReScalar),v2::'Vector'(8,oReScalar),v3::'Vector'(8,oReScalar))
		oToV(oCross(oFromV(v1),oFromV(v2),oFromV(v3))):
	end proc:
	oArea := (o1::oImScalar,o2::oImScalar) -&gt; oKernel:-oArea(o1,o2):
	oVolume := (o1::oScalar,o2::oScalar,o3::oScalar) -&gt; oKernel:-oVolume(o1,o2,o3):
	v7Area := proc(v1::'Vector'(7,oReScalar),v2::'Vector'(7,oReScalar))
		oArea(oImFromV(v1),oImFromV(v2)):
	end proc:
	v8Volume := proc(v1::'Vector'(8,oReScalar),v2::'Vector'(8,oReScalar),v3::'Vector'(8,oReScalar))
		oVolume(oFromV(v1),oFromV(v2),oFromV(v3)):
	end proc:

	###########################################################################################
	# ON LOAD PROCEDURE								#
	###########################################################################################

	oLoad := proc()
		local
			isOScalar, isOVector, isOMatrix,
			isOImScalar, isOImVector, isOImMatrix,
			isOReScalar, isOReVector, isOReMatrix:

		# DEFINE TYPES
		isOScalar := proc(o)
			if not type(o,scalar) then return false end if:
			LinearAlgebra:-Equal(
				Matrix(map2(diff,map2(diff,o,oUnits),oUnits)),
				Matrix(1..7,1..7,shape=zero)
			):
		end proc:
		isOVector := (o) -&gt; type(o,'Vector'(oScalar)):
		isOMatrix := (o) -&gt; type(o,'Matrix'(oScalar)):
		isOImScalar := proc(o)
			if not type(o,scalar) then return false end if:
			if oRe(o) &lt;&gt; 0 then return false end if:
			is(LinearAlgebra:-MatrixNorm(Matrix(map2(diff,map2(diff,o,oUnits),oUnits))) = 0):
		end proc:
		isOImVector := (o) -&gt; type(o,'Vector'(oImScalar)):
		isOImMatrix := (o) -&gt; type(o,'Matrix'(oImScalar)):
		isOReScalar := proc(o)
			if not type(o,scalar) then return false end if:
			evalb(oIm(o) = 0):
		end proc:
		isOReVector := (o) -&gt; type(o,'Vector'(oReScalar)):
		isOReMatrix := (o) -&gt; type(o,'Matrix'(oReScalar)):
		TypeTools:-AddType(oScalar,(o) -&gt; isOScalar(o)):
		TypeTools:-AddType(oVector,(o) -&gt; isOVector(o)):
		TypeTools:-AddType(oMatrix,(o) -&gt; isOMatrix(o)):
		TypeTools:-AddType(oImScalar,(o) -&gt; isOImScalar(o)):
		TypeTools:-AddType(oImVector,(o) -&gt; isOImVector(o)):
		TypeTools:-AddType(oImMatrix,(o) -&gt; isOImMatrix(o)):
		TypeTools:-AddType(oReScalar,(o) -&gt; isOReScalar(o)):
		TypeTools:-AddType(oReVector,(o) -&gt; isOReVector(o)):
		TypeTools:-AddType(oReMatrix,(o) -&gt; isOReMatrix(o)):

		# DEFINE UNITS AND TRIPLES
		oUnits := [seq(e||i,i=1..7)]:
		oTableIm := Matrix(1..7,1..7):
		oTable := Matrix(1..8,1..8):
		oSetTriples([[e1,e2,e4],[e2,e3,e5],[e3,e4,e6],[e4,e5,e7],[e5,e6,e1],[e6,e7,e2],[e7,e1,e3]]):
	end proc:
	protect(seq(e||i,i=1..7)):
	protect(
		oVersion, oGetUnits, oSetTriples, oGetTriples, oGetTable,
		oImToL, oImToV, oToL, oToV, oImFromL, oImFromV, oFromL, oFromV,
		oNorm, oInner, oConj, oHermConj, oRe, oIm, oInv,
		oCos, oSin, oTan, oCot, oCosh, oSinh, oTanh,	oCoth,
		oExp, oLn, oPowerInt, oPower, oAdd, oSub, oMul, oDiv, oCom, oAntiCom, oAssoc,
		oImCross, oCross, v7Cross, v8Cross, oArea, oVolume, v7Area, v8Volume,
		oTrace, oDotProd
	):

	###########################################################################################
	# ON UNLOAD PROCEDURE								#
	###########################################################################################

	oUnLoad := proc()
	end proc:

end module:</Font></Text-field></Input></Group><Text-field/></Worksheet>