should handle any table of structure t[i][j] = value
we always return a matrix with scripts metatable
cause its faster than setmetatable( mtx, getmetatable( input matrix ) )
///////////////////////////////
// matrix 'matrix' functions //
///////////////////////////////
// for real, complx and symbolic matrices //--
note: real and complex matrices may be added, subtracted, etc.
real and symbolic matrices may also be added, subtracted, etc.
but one should avoid using symbolic matrices with complex ones
since it is not clear which metatable then is used
// matrix.add ( m1, m2 )
Add 2 matrices; m2 may be of bigger size than m1
syntax
function matrix.add( m1, m2 )
parameters
matrix.sub
// matrix.sub ( m1 ,m2 )
Subtract 2 matrices; m2 may be of bigger size than m1
syntax
function matrix.sub( m1, m2 )
parameters
matrix.mul
// matrix.mul ( m1, m2 )
Multiply 2 matrices; m1 columns must be equal to m2 rows
e.g. #m1[1] == #m2
syntax
function matrix.mul( m1, m2 )
parameters
matrix.div
// matrix.div ( m1, m2 )
Divide 2 matrices; m1 columns must be equal to m2 rows
m2 must be square, to be inverted,
if that fails returns the rank of m2 as second argument
e.g. #m1[1] = #m2; #m2 =
#m2[1]
syntax
function matrix.div( m1, m2 )
parameters
matrix.mulnum
// matrix.mulnum ( m1, num )
Multiply matrix with a number
num may be of type 'number','complex number' or 'string'
strings get converted to complex number, if that fails then to symbol
syntax
function matrix.mulnum( m1, num )
parameters
matrix.divnum
// matrix.divnum ( m1, num )
Divide matrix by a number
num may be of type 'number','complex number' or 'string'
strings get converted to complex number, if that fails then to symbol
syntax
function matrix.divnum( m1, num )
parameters
matrix.pow
// for real and complex matrices only //--
// matrix.pow ( m1, num )
Power of matrix; mtx^(num)
num is an integer and may be negative
m1 has to be square
if num is negative and inverting m1 fails
returns the rank of matrix m1 as second argument
syntax
function matrix.pow( m1, num )
parameters
matrix.det
// matrix.det ( m1 )
Calculate the determinant of a matrix
m1 needs to be square
Can calc the det for symbolic matrices up to 3x3 too
The function to calculate matrices bigger 3x3
is quite fast and for matrices of medium size ~(100x100)
and average values quite accurate
here we try to get the nearest element to |1|, (smallest pivot element)
os that usually we have |mtx[i][j]/subdet| > 1 or mtx[i][j];
with complex matrices we use the complex.abs function to check if it is bigger or smaller
local fiszerocomplex = function( cx ) return complex.is(cx,0,0) end
local fiszeronumber = function( num ) return num == 0 end
syntax
function matrix.det( m1 )
parameters
matrix.dogauss
// matrix.dogauss ( mtx )
Gauss elimination, Gauss-Jordan Method
this function changes the matrix itself
returns on success: true,
returns on failure: false,'rank of matrix'
locals
checking here for the nearest element to 1 or -1; (smallest pivot element)
this way the factor of the evolving number division should be > 1 or the divided number itself,
what gives better results
local setelementtosmallest = function( mtx,i,j,fiszero,fisone,abs )
-- check if element is one
if fisone(mtx[i][j]) then return true end
-- check for lowest value
local _ilow
for _i = i,#mtx do
local e = mtx[_i][j]
if fisone(e) then
break
end
if not _ilow then
if not fiszero(e) then
_ilow = _i
end
elseif (not fiszero(e)) and math.abs(abs(e)-1) < math.abs(abs(mtx[_ilow][j])-1) then
_ilow = _i
end
end
if _ilow then
-- switch lines if not input line
-- legal operation
if _ilow ~= i then
mtx[i],mtx[_ilow] = mtx[_ilow],mtx[i]
end
return true
end
end
local cxfiszero = function( cx ) return complex.is(cx,0,0) end
local cxfsetzero = function( mtx,i,j ) complex.set(mtx[i][j],0,0) end
local cxfisone = function( cx ) return complex.abs(cx) == 1 end
local cxfsetone = function( mtx,i,j ) complex.set(mtx[i][j],1,0) end
local numfiszero = function( num ) return num == 0 end
local numfsetzero = function( mtx,i,j ) mtx[i][j] = 0 end
local numfisone = function( num ) return math.abs(num) == 1 end
local numfsetone = function( mtx,i,j ) mtx[i][j] = 1 end
note: in --// ... //-- we have a way that does no divison,
however with big number and matrices we get problems since we do no reducing
syntax
function matrix.dogauss( mtx )
parameters
matrix.invert
// matrix.invert ( m1 )
Get the inverted matrix or m1
matrix must be square and not singular
on success: returns inverted matrix
on failure: returns nil,'rank of matrix'
syntax
function matrix.invert( m1 )
parameters
matrix.sqrt
// matrix.sqrt ( m1 [,iters] )
calculate the square root of a matrix using "Denman鏈唀avers square root iteration"
condition: matrix rows == matrix columns; must have a invers matrix and a square root
if called without additional arguments, the function finds the first nearest square root to
input matrix, there are others but the error between them is very small
if called with agument iters, the function will return the matrix by number of iterations
the script returns:
as first argument, matrix^.5
as second argument, matrix^-.5
as third argument, the average error between (matrix^.5)^2-inputmatrix
you have to determin for yourself if the result is sufficent enough for you
local average error
local function get_abs_avg( m1, m2 )
local dist = 0
local abs = matrix.type(m1) == "complex" and complex.abs or math.abs
for i=1,#m1 do
for j=1,#m1[1] do
dist = dist + abs(m1[i][j]-m2[i][j])
end
end
-- norm by numbers of entries
return dist/(#m1*2)
end
square root function
syntax
function matrix.sqrt( m1, iters )
parameters
matrix.root
// matrix.root ( m1, root [,iters] )
calculate any root of a matrix
source: http://www.dm.unipi.it/~cortona04/slides/bruno.pdf
m1 and root have to be given;(m1 = matrix, root = number)
conditions same as matrix.sqrt
returns same values as matrix.sqrt
syntax
function matrix.root( m1, root, iters )
parameters
matrix.normf
// Norm functions //--
// matrix.normf ( mtx )
calculates the Frobenius norm of the matrix.
||mtx||_F = sqrt(SUM_{i,j} |a_{i,j}|^2)
http://en.wikipedia.org/wiki/Frobenius_norm#Frobenius_norm
syntax
function matrix.normf(mtx)
parameters
matrix.normmax
// matrix.normmax ( mtx )
calculates the max norm of the matrix.
||mtx||_{max} = max{|a_{i,j}|}
Does not work with symbolic matrices
http://en.wikipedia.org/wiki/Frobenius_norm#Max_norm
syntax
function matrix.normmax(mtx)
parameters
matrix.round
// only for number and complex type //--
Functions changing the matrix itself
// matrix.round ( mtx [, idp] )
perform round on elements
local numround = function( num,mult )
return math.floor( num * mult + 0.5 ) / mult
end
local tround = function( t,mult )
for i,v in ipairs(t) do
t[i] = math.floor( v * mult + 0.5 ) / mult
end
return t
end
syntax
function matrix.round( mtx, idp )
parameters
matrix.random
// matrix.random( mtx [,start] [, stop] [, idip] )
fillmatrix with random values
local numfill = function( _,start,stop,idp )
return math.random( start,stop ) / idp
end
local tfill = function( t,start,stop,idp )
for i in ipairs(t) do
t[i] = math.random( start,stop ) / idp
end
return t
end
syntax
function matrix.random( mtx,start,stop,idp )
parameters
matrix.type
//////////////////////////////
// Object Utility Functions //
//////////////////////////////
// for all types and matrices //--
// matrix.type ( mtx )
get type of matrix, normal/complex/symbol or tensor
syntax
function matrix.type( mtx )
parameters
matrix.copy
// matrix.copy ( m1 )
Copy a matrix
simple copy, one can write other functions oneself
syntax
function matrix.copy( m1 )
parameters
matrix.transpose
// matrix.transpose ( m1 )
Transpose a matrix
switch rows and columns
syntax
function matrix.transpose( m1 )
parameters
matrix.subm
// matrix.subm ( m1, i1, j1, i2, j2 )
Submatrix out of a matrix
input: i1,j1,i2,j2
i1,j1 are the start element
i2,j2 are the end element
condition: i1,j1,i2,j2 are elements of the matrix
syntax
function matrix.subm( m1,i1,j1,i2,j2 )
parameters
matrix.concath
// matrix.concath( m1, m2 )
Concatenate 2 matrices, horizontal
will return m1m2; rows have to be the same
e.g.: #m1 == #m2
syntax
function matrix.concath( m1,m2 )
parameters
matrix.concatv
// matrix.concatv ( m1, m2 )
Concatenate 2 matrices, vertical
will return m1
m2
columns have to be the same; e.g.: #m1[1] == #m2[1]
syntax
function matrix.concatv( m1,m2 )
parameters
matrix.rotl
// matrix.rotl ( m1 )
Rotate Left, 90 degrees
syntax
function matrix.rotl( m1 )
parameters
matrix.rotr
// matrix.rotr ( m1 )
Rotate Right, 90 degrees
syntax
function matrix.rotr( m1 )
parameters
matrix.tostring
local get_elemnts in string
local get_tstr = function( t )
return "["..table.concat(t,",").."]"
end
local get_str = function( e )
return tostring(e)
end
local get_elemnts in string and formated
local getf_tstr = function( t,fstr )
local tval = {}
for i,v in ipairs( t ) do
tval[i] = string.format( fstr,v )
end
return "["..table.concat(tval,",").."]"
end
local getf_cxstr = function( e,fstr )
return complex.tostring( e,fstr )
end
local getf_symstr = function( e,fstr )
return string.format( fstr,e[1] )
end
local getf_str = function( e,fstr )
return string.format( fstr,e )
end
// matrix.tostring ( mtx, formatstr )
tostring function
syntax
function matrix.tostring( mtx, formatstr )
parameters
matrix.print
// matrix.print ( mtx [, formatstr] )
print out the matrix, just calls tostring
syntax
function matrix.print( ... )
matrix.latex
// matrix.latex ( mtx [, align] )
LaTeX output
syntax
function matrix.latex( mtx, align )
parameters
matrix.rows
// Functions not changing the matrix
// matrix.rows ( mtx )
return number of rows
syntax
function matrix.rows( mtx )
parameters
matrix.columns
// matrix.columns ( mtx )
return number of columns
syntax
function matrix.columns( mtx )
parameters
matrix.size
// matrix.size ( mtx )
get matrix size as string rows,columns
syntax
function matrix.size( mtx )
parameters
matrix.getelement
// matrix.getelement ( mtx, i, j )
return specific element ( row,column )
returns element on success and nil on failure
syntax
function matrix.getelement( mtx,i,j )
parameters
matrix.setelement
// matrix.setelement( mtx, i, j, value )
set an element ( i, j, value )
returns 1 on success and nil on failure
syntax
function matrix.setelement( mtx,i,j,value )
parameters
matrix.ipairs
// matrix.ipairs ( mtx )
iteration, same for complex
syntax
function matrix.ipairs( mtx )
parameters
matrix.scalar
///////////////////////////////
// matrix 'vector' functions //
///////////////////////////////
a vector is defined as a 3x1 matrix
get a vector; vec = matrix{{ 1,2,3 }}^'T'
// matrix.scalar ( m1, m2 )
returns the Scalar Product of two 3x1 matrices (vectors)
syntax
function matrix.scalar( m1, m2 )
parameters
matrix.cross
// matrix.cross ( m1, m2 )
returns the Cross Product of two 3x1 matrices (vectors)
syntax
function matrix.cross( m1, m2 )
parameters
matrix.len
// matrix.len ( m1 )
returns the Length of a 3x1 matrix (vector)
syntax
function matrix.len( m1 )
parameters
matrix.tocomplex
////////////////////////////////
// matrix 'complex' functions //
////////////////////////////////
// matrix.tocomplex ( mtx )
we set now all elements to a complex number
also set the metatable
syntax
function matrix.tocomplex( mtx )
parameters
matrix.remcomplex
// matrix.remcomplex ( mtx )
set the matrix elements to a number or complex number string
syntax
function matrix.remcomplex( mtx )
parameters
matrix.conjugate
// matrix.conjugate ( m1 )
get the conjugate complex matrix
syntax
function matrix.conjugate( m1 )
parameters
matrix.tosymbol
/////////////////////////////////
// matrix 'symbol' functions //
/////////////////////////////////
// matrix.tosymbol ( mtx )
set the matrix elements to symbolic values
syntax
function matrix.tosymbol( mtx )
parameters
matrix.gsub
// matrix.gsub( m1, from, to )
perform gsub on all elements
syntax
function matrix.gsub( m1,from,to )
parameters
matrix.replace
// matrix.replace ( m1, ... )
replace one letter by something else
replace( "a",4,"b",7, ... ) will replace a with 4 and b with 7
syntax
function matrix.replace( m1,... )
parameters
matrix.solve
// matrix.solve ( m1 )
solve; tries to solve a symbolic matrix to a number
syntax
function matrix.solve( m1 )
parameters
TEA-1.0
Description
Tiny Encryption Algorythm implementation
Sample Code
NPL.load("(gl)script/ide/math/TEA.lua");
local TEA = commonlib.LibStub("TEA")
local s0 = 'message digest'
local s3 = '12345678901234567890123456789012345678901234567890123456789012345678901234567890'
local k3 = TEA:GenerateKey(s3)
assert(TEA:Decrypt(TEA:Encrypt(s0, k3), k3) == s0)
Member Functions
lib:GenerateKey
local function StringToIntArray(text)
local a, l = {}, string.len(text)
for i = 1, l, 4 do
local acc = 0
if l >= i + 3 then
acc = acc + string.byte(text, i + 3) + string.byte(text, i + 2) * 256 + string.byte(text, i + 1) * 65536 + string.byte(text, i + 0) * 16777216
elseif l >= i + 2 then
acc = acc + string.byte(text, i + 2) * 256 + string.byte(text, i + 1) * 65536 + string.byte(text, i + 0) * 16777216
elseif l >= i + 1 then
acc = acc + string.byte(text, i + 1) * 65536 + string.byte(text, i + 0) * 16777216
elseif l >= i + 0 then
acc = acc + string.byte(text, i + 0) * 16777216
end
table.insert(a, acc)
end
if (math.fmod(#(a), 2) == 1) then
table.insert(a, 0)
end
return a
end
local function IntArrayToString(array)
local a = {}
for i = 1, #(array) do
for j = 3, 0, -1 do
local b = bit.band(bit.rshift(array[i], j * 8), 255)
table.insert(a, string.char(b))
end
end
while true do
local n = #(a)
if n > 0 and string.byte(a[n]) == 0 then
table.remove(a, n)
else
break
end
end
return table.concat(a)
end
syntax
function lib:GenerateKey(key)
parameters