home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
sa104os2.zip
/
SATHR104.ZIP
/
SATHER
/
LIBRARY
/
MAT.SA
< prev
next >
Wrap
Text File
|
1995-02-04
|
16KB
|
457 lines
-- Copyright (C) International Computer Science Institute, 1994. COPYRIGHT --
-- NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY and is subject --
-- to the terms of the SATHER LIBRARY GENERAL PUBLIC LICENSE contained in --
-- the file "Doc/License" of the Sather distribution. The license is also --
-- available from ICSI, 1947 Center St., Suite 600, Berkeley CA 94704, USA. --
--------> Please email comments to "sather-bugs@icsi.berkeley.edu". <----------
-- mat.sa: Matrices of FLT.
-------------------------------------------------------------------
class MAT is
-- Matrices of FLT.
include ARRAY2{FLT};
-- Gets
-- create(nr,nc),create(ARRAY{ARRAY{T}}),
-- copy
-- aget, aset,
-- nr, nc
-- row_ind!, col_ind!
-- row_elt!, col_elt!
-- set_row!, set_col!
-- diag_elt! set_diag_elt!
-- to_portion_of
create_identity(sz:INT):SAME is
-- A new square identity matrix of size sz.
return(create_diagonal(sz,1.0)) end;
create_diagonal(sz: INT, diag_val: FLT): SAME
-- A diagonal matrix with diag_val on the diagonal
pre sz>0 is
res ::= #SAME(sz,sz);
loop i::=sz.times!; res[i,i]:=diag_val end;
return(res);
end;
same_shape_p(m1:SAME):BOOL is
-- True if self and m1 have the same dimensions.
return(m1.nr=nr and m1.nc=nc) end;
-- row_col_ind!: TUP{INT,INT} is
-- loop r::=asize1.dotimes!;
-- loop yield(#TUP2{INT,INT}(r,asize2.dotimes!)) end; end; end;
to(val:SAME)
-- Set self equal to val
pre same_shape_p(val) is
loop set!(val.elt!) end end;
row_elts_in(r:INT, s:FSTR): FSTR is
-- Write successive elements of row `r' into s.
res ::= s;
-- loop res := res + row_elt!(r).str end end; -- NLP ?
loop res := res + row_elt!(r).str end; return res; end; -- NLP ?
-- row_lists_in(s:FSTR) is
-- -- Write lists containing successive rows into s.
-- loop s.listify(ITER(row_elts_in(nr.do,_))) end end;
-- str_in(STRCAT) is
-- -- Write a list version of self into arg.
-- arg.listify(ITER(row_lists_in(_))) end;
-- str:STR is
-- -- A string version of self.
-- return(#FSTR+str; (sc); res:=sc.str end;
-- append_row_lists!(STRCAT) is
-- -- Appends list form of successive rows to arg.
-- loop
-- end end;
str:STR is
-- The string form of self represented as a list of rows,
-- eg. "||1.00,2.33|,|4.5,2.8|,|9.7,3.2||".
sc::=#FSTR + "|";
loop r::=nr.times!;
if r/=0 then sc := sc+ "," end;
sc := sc + "|";
loop c::=nc.times!;
if c/=0 then sc := sc+"," end;
sc := sc + [r,c]; end;
-- #OUT+r+","+c+":"+sc+"\n"; end;
sc := sc+ "|" end;
sc := sc+"|";
return(sc.str) end;
-- from_str(STR):SAME is
-- Create a new matrix from a string with a list of rows,
-- eg. "((1.00 2.33) (4.5 2.8) (9.7 3.2))".
-- Returns `void' if not of this form (extra white space is ignored).
-- Must be at least one entry.
-- sc::=arg.cursor; tmp::=LIST{LIST{FLT}}::create;
-- sc.skip_space; if not sc.c_accept('(') then return end;
-- loop sc.skip_space; if sc.c_accept(')') then break end;
-- tmp:=tmp.push(LIST{FLT}::create);
-- if not sc.c_accept('(') then return end;
-- loop sc.skip_space; if sc.c_accept(')') then break end;
-- tmp:=tmp.push(tmp.pop.push(sc.get_f));
-- if sc.error/=0 then return end end end;
-- loop if tmp.elts.size/=tmp[0].size then return end;
-- res:=create(tmp.size,tmp.top.size);
-- loop r::=res.nr.do; loop res.set_row_elts(r,tmp[r].elts) end end end;
-- to_portion_of(SAME) is
-- -- Copy into self as much of arg as will fit and return it. Don't
-- -- alter other elements.
-- loop r::=nr.min(arg.nr).dotimes;
-- loop set_row_elts(r,arg.row_elts) end end end;
scale_by(s:FLT) is
-- Scale self by s.
loop set!(s*elt!) end end;
scale_col_by(c: INT, s: FLT) is
-- Scale the "c"th column of self by s
loop set_col!(c,s*col_elt!(c)) end end;
scale_row_by(r: INT, s: FLT) is
-- Scale the "r"th row of self by s
loop set_row!(r,s*row_elt!(r)) end end;
to_zero is
-- Set self to the zero matrix.
loop set!(0.0) end end;
to_identity is
-- Set self to the identity matrix. Add extra zeroes if non-square.
to_zero; loop i::=nr.min(nc).times!; [i,i]:=1.0 end end;
plus(m1:SAME):SAME
-- The sum of self and m1. -> Self+m1
pre same_shape_p(m1) is
res::=create(nr,nc); res.to_sum_of(self,m1); return(res); end;
add(m1:SAME)
-- Set self to its sum with m1. Self <- Self + m1
pre same_shape_p(m1) is
loop set!(elt!+m1.elt!) end end;
add_scalar(s: FLT) is
-- Add scalar "s" to all elements fo the matrix
loop set!(elt!+s) end; end;
add_scaled(scale:FLT, m1: SAME)
-- Set self to self + scale*m1
pre same_shape_p(m1) is
loop set!(elt!+scale*m1.elt!) end end;
scale_and_add_scaled(scale_self,scale_m1:FLT, m1: SAME)
-- Set self to self_scale*self + scale_m1*m1
pre same_shape_p(m1) is
loop set!(scale_self*elt!+scale_m1*m1.elt!) end end;
to_sum_of(m1,m2:SAME)
-- Set self to sum of m1 and m2. Self <- m1+m2
pre same_shape_p(m1) and same_shape_p(m2) is
loop set!(m1.elt!+m2.elt!) end end;
minus(m1:SAME):SAME
-- ->Self-m1.
pre same_shape_p(m1) is
res::=create(nr,nc); loop res.set!(elt!-m1.elt!) end;
return(res);
end;
to_difference_with(m1:SAME)
-- Self <- Self - m1.
pre same_shape_p(m1) is
loop set!(elt!-m1.elt!) end end;
to_difference_of(m1,m2:SAME)
-- Set self to difference of m1 and m2. Self <- m1-m2
pre same_shape_p(m1) and same_shape_p(m2) is
loop set!(m1.elt!-m2.elt!) end end;
add_difference_of(m1,m2: SAME)
-- Add to self the difference of m1 and m2. Self <- Self + m1-m2
pre same_shape_p(m1) and same_shape_p(m2) is
loop set!(elt! + (m1.elt!-m2.elt!)) end end;
times(m1:SAME):SAME
-- Self times m1. -> Self*m1
pre m1.nr=nc is
res::=create(nr,m1.nc);
res.to_product_of(self,m1);
return(res);
end;
to_product_of(a,b:SAME)
-- Set self to the matrix product of `a' and `b'.
pre nr=a.nr and nc=b.nc and a.nc=b.nr is
loop t::=inds!; x::=0.0;
a_row ::= t.t1; b_col ::= t.t2;
loop x:=x+a.row_elt!(a_row)*b.col_elt!(b_col) end;
[a_row,b_col]:= x end end;
add_product_of(a,b: SAME)
-- Add the matrix product of `a' and `b' to self
-- Self <- Self+a*b
pre nr=a.nr and nc=b.nc and a.nc=b.nr is
loop t::=inds!; x::=0.0;
a_row ::= t.t1; b_col ::= t.t2;
loop x:=x+a.row_elt!(a_row)*b.col_elt!(b_col) end;
[a_row,b_col]:= [a_row,b_col]+x end end;
scale_and_add_product_of(scale_self,scale_prod: FLT, a,b: SAME)
-- Add the matrix product of `a' and `b' to scaled*self
-- SELF <- scale_self*SELF +scale_product*A*B
-- Blas 3 routine: might want to write other routines to call this
pre nr=a.nr and nc=b.nc and a.nc=b.nr is
loop t::=inds!; x::=0.0;
a_row ::= t.t1; b_col ::= t.t2;
loop x:=x+a.row_elt!(a_row)*b.col_elt!(b_col) end;
[a_row,b_col]:= scale_prod*[a_row,b_col]+scale_self*x end end;
to_product_with_diagonal(v1:VEC) is
-- Set self to be the product of itself with a diagonal matrix whose
-- diagonal entries are the components of v1 truncated or extended
-- with zeroes to be the correct size.
-- Scale the columns of self with the elements of v1
-- Self <- Self*v1 (as diagonal of a matrix)
loop c::=nc.min(v1.dim).times!;
loop set_col!(c,v1[c]*col_elt!(c)) end end;
loop c::=v1.dim.upto!(nc-1); loop set_col!(c,0.0) end end end;
times(v1:VEC):VEC is
-- A new vector equal to self times v1. -> self*v1
res ::= #VEC(nr); times_in(v1,res); return(res) end;
times_in(v,vr:VEC)
-- Set `vr' to the result of self acting on `v'. vr <- self*v1
pre v.dim=nc and vr.dim=nr is
loop r::=vr.ind!; x::=0.0; loop x:=x+row_elt!(r)*v.elt! end;
vr[r]:=x end end;
times_accum_in(v,vr: VEC)
-- Add to `vr' the result of self acting on `v'. vr <- vr+self*v1
pre v.dim=nc and vr.dim=nr is
loop r::=vr.ind!; x::=0.0; loop x:=x+row_elt!(r)*v.elt! end;
vr[r]:=v[r]+x end end;
transpose_times(v:VEC):VEC is
-- The transpose of self times `v' .
-- Used by vec*matrix
res ::= #VEC(nc);
transpose_times_in(v,res);
return(res) end;
transpose_times_in(v,vr:VEC)
-- Set `vr' to the result of the transpose of self acting on `v'.
pre v.dim=nr and vr.dim=nc is
vr.to_zero;
i ::=0; loop until!(i=nc);
j::=0; loop until!(j=nr); vr[i]:=vr[i]+[j,i]*v[j]; j:=j+1 end;
i:=i+1
end; --loop
end;
transpose_times_add_into(v,vr: VEC)
-- Add to `vr' to the result of the transpose of self acting on `v'.
pre v.dim=nr and vr.dim=nc is
i ::=0; loop until!(i=nc);
j::=0; loop until!(j=nr); vr[i]:=vr[i]+[j,i]*v[j]; j:=j+1 end;
i:=i+1
end; --loop
end;
col(j:INT):VEC is
-- The `j'th col of self as a vector
v::=#VEC(nr); col_in(j,v); return(v) end;
col_in(j:INT, v:VEC) is
-- Copy as much of the `j'th col of self into `v' as will fit.
loop v.set!(col_elt!(j)) end end;
set_col(j:INT, v:VEC) is
-- Copy as much of `v' as will fit into the `j'th col of self
loop set_col!(j,v.elt!) end; end;
row(i:INT):VEC is
-- The `i'th row of self.
v::=#VEC(nc); row_in(i,v); return(v) end;
row_in(i:INT, v:VEC) is
-- Copy as much of the `i'th row of self into `v' as will fit.
loop v.set!(row_elt!(i)) end; end;
set_row(i:INT, v:VEC) is
-- Copy as much of `v' as will fit into the `i'th row of self
loop set_row!(i,v.elt!) end end;
diagonal_in(v:VEC)
-- Copy as much of the diagonal of self into `v' as will fit.
pre v.dim = nr.min(nc) is
loop v.set!(diag_elt!) end; end;
trace:FLT is
-- The trace of self. Sum of diagonal even if not square.
res ::= 0.0; loop res := res + diag_elt! end end;
to_uniform_random is
-- Make self's entries uniform in `[0.,1.)' and return it;
loop r::=row_ind!; loop [r,col_ind!] := (RND::uniform).flt; end; end;
end; -- to_uniform_random
to_outer_product_of(u,v:VEC)
-- Set `self[r,c]' to `u.r * v.c' (like `u v^T').
pre nr=u.dim and nc=v.dim is
loop r_ind ::= u.ind!;
loop c_ind ::= v.ind!;
[r_ind,c_ind] := u[r_ind]*v[c_ind];
end; end; end;
add_outer_product_of(u,v:VEC)
-- Add to `self[r,c]' `u.r * v.c' (like `u v^T').
pre nr=u.dim and nc=v.dim is
loop r_ind ::= u.ind!;
loop c_ind ::= v.ind!;
[r_ind,c_ind] := [r_ind,c_ind] + u[r_ind]*v[c_ind];
end; end; end;
end; -- class MAT
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class TEST_MAT is
-- Test of `MAT'
include TEST;
main is
-- Test of `MAT' and `NR_SVD'.
class_name("MAT");
m ::= #MAT(||1.1,4.2|,|3.7,5.6|,|5.9,6.3||);
test("nr", m.nr.str, "3");
test("nc", m.nc.str, "2");
test("create_from_s and to_s", m.str,
"||1.1,4.2|,|3.7,5.6|,|5.9,6.3||");
-- Having tested m.str, we should be able to
-- use it in the tests that follow to avoid
-- heavy dependance on the exact printout format of flts
m2 ::=#MAT(3,2);
m2.to(m);
test("to and create", m2.str, m.str);
m3 ::= #MAT(2,1);
m3.to_portion_of(m);
m_portion_test ::= #MAT(||1.10|,|3.70||);
test("to_portion_of", m3.str, m_portion_test.str);
m4 ::= m.copy;
test("copy",m4.str,m.str);
m4.to_zero;
m_test ::= #MAT(||0.0,0.0|,|0.0,0.0|,|0.0,0.0||);
test("to_zero", m4.str,m_test.str);
m_test.copy(||1.0,0.0|,|0.0,1.0|,|0.0,0.0||);
m4.to_identity;
test("to_identity", m4.str,m_test.str);
m_test.copy(||2.10,4.20|,|3.70,6.60|,|5.90,6.30||);
test("plus", (m4+m).str, m_test.str);
m_test.copy(||2.10, 4.20|, |3.70, 6.60|, |5.90, 6.30||);
m5 ::= m4.copy;
m5.add(m);
test("add", m5.str,m_test.str);
m_test.copy(||0.10, 4.20|, |3.70, 4.60|, |5.90, 6.30||);
test("minus", (m-m4).str,m_test.str);
m_test.copy(||2.0,0.0|,|0.0,2.0|,|0.0,0.0||);
m6 ::= m4.copy;
m6.scale_by(2.0);
test("scale_by", m6.str,m_test.str);
m_test.copy(||1.10, 4.20|, |3.70, 5.60|, |5.90, 6.30||);
m_ident ::= MAT::create_identity(2);
test("times", (m*m_ident).str, m_test.str);
v ::= #VEC(2);
v.to_ones;
m.to_product_with_diagonal(v);
test("times", m.str, m_test.str);
m_trans_test ::= #MAT(||1.10, 3.70, 5.90|,|4.20,5.60,6.30||);
m_trans::=m.transpose;
test("transpose",m_trans.str,m_trans_test.str);
m_trans.to_zero;
m_trans_test.copy(||0.0, 0.00, 0.00|,|0.0,0.0,0.0||);
test("to_zero",m_trans.str,m_trans_test.str);
v.to_ones;
m_mul ::= m*v;
v_res ::= #VEC(|5.3,9.3,12.2|);
test("times vector",m_mul.str,v_res.str);
v1 ::= #VEC(|5.0,7.0|);
v2 ::= #VEC(|3.0,9.0,4.0|);
m_res ::= v1.outer_product(v2);
m_trans.copy(||15.0,45.0,20.0|,|21.0,63.0,28.0||);
test("outer product (VEC test)", m_res.str,m_trans.str);
m_trans := m.transpose;
v_m ::= v*m_trans;
v_test ::= #VEC(|5.3,9.3,12.2|);
test("vector * matrix i.e. transpose_times",v_m.str,v_test.str);
-- test("transpose", m.transpose.str,
-- "((1.10, 3.70, 5.90), (4.20, 5.60, 6.30))");
-- test("to_transpose_of", MAT::create(2,3).to_transpose_of(m).str,
-- "((1.10, 3.70, 5.90), (4.20, 5.60, 6.30))");
-- test("transpose_act_on", m.transpose.transpose_act_on(v).str,
-- "(1.10, 3.70, 5.90)");
-- m.transpose.transpose_act_on_in(v,v2);
-- test("transpose_act_on_in", v2.str, "(1.10, 3.70, 5.90)");
-- v:VEC :=VEC::create_from_s("(1.0, 0.0)");
-- test("act_on", m.act_on(v).str, "(1.10, 3.70, 5.90)");
-- v2:VEC :=VEC::create(3); m.act_on_in(v,v2);
-- test("act_on_in", v2.str, "(1.10, 3.70, 5.90)");
-- v3:VEC :=VEC::create_from_s("(0.0)");
-- test("column", m.column(0).str, "(1.10, 3.70, 5.90)");
-- m.column_in(0,v2);
-- test("column_in", v2.str, "(1.10, 3.70, 5.90)");
-- test("column_from", m.copy.column_from(0,v2.to_zero).str,
-- "((0.00, 4.20), (0.00, 5.60), (0.00, 6.30))");
-- test("row", m.row(0).str, "(1.10, 4.20)");
-- m.row_in(0,v);
-- test("row_in", v.str, "(1.10, 4.20)");
-- test("row_from", m.copy.row_from(0,v.to_zero).str,
-- "((0.00, 0.00), (3.70, 5.60), (5.90, 6.30))");
-- m.diagonal_in(v);
-- test("diagonal_in", v.str, "(1.10, 5.60)");
-- test("trace", m.trace.str, (m[0,0]+m[1,1]).str);
-- a:MAT:=MAT::create(3,4).to_uniform_random;
-- svd_mat_test(1, a);
-- a:=MAT::create(4,3).to_uniform_random;
-- a:=MAT::create_from_s("((0.,1.,0.),(0.,1.,1.),(0.,0.,0.))");
-- test("to_uniform_random",
-- lfm.copy.to_uniform_random.nr.str, "3");
-- test("to_outer_product_of",
-- em.to_outer_product_of
-- (VEC::create_from_s("(1.,1.,1.)"),
-- VEC::create_from_s("(1.,1.,1.)")).str,
-- "((1.00, 1.00, 1.00), (1.00, 1.00, 1.00), (1.00, 1.00, 1.00))");
finish;
end; -- main
end; -- class TEST_MAT
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~