diff --git a/src/modules/Math/math.c b/src/modules/Math/math.c
index 97490acc0ce12cf6110c2342174f29cb41f1e8c6..80159f6dd01cb493a3546e869cb930b5148c3193 100644
--- a/src/modules/Math/math.c
+++ b/src/modules/Math/math.c
@@ -1,5 +1,5 @@
 /*
- * $Id: math.c,v 1.1 1999/03/31 13:12:37 mirar Exp $
+ * $Id: math.c,v 1.2 1999/03/31 18:36:52 mirar Exp $
  */
 
 #include "global.h"
@@ -13,16 +13,23 @@
 
 /* add other parsers here */
 
+struct program *math_matrix_program;
+
 static struct math_class
 {
    char *name;
    void (*func)(void);
+   struct program **pd;
 } sub[] = {
-   {"Matrix",init_math_matrix},
+   {"Matrix",init_math_matrix,&math_matrix_program},
 };
 
 void pike_module_exit(void)
 {
+   int i;
+   for (i=0; i<(int)(sizeof(sub)/sizeof(sub[0])); i++)
+      if (sub[i].pd && sub[i].pd[0])
+	 free_program(sub[i].pd[0]);
 }
 
 void pike_module_init(void)
@@ -37,6 +44,7 @@ void pike_module_init(void)
       sub[i].func();
       p=end_program();
       add_program_constant(sub[i].name,p,0);
-      free_program(p);
+      if (sub[i].pd) sub[i].pd[0]=p;
+      else free_program(p);
    }
 }
diff --git a/src/modules/Math/matrix.c b/src/modules/Math/matrix.c
index a5d69de74750e7baffa392e78852409fa1abf8d3..e3fdc4fa68957ececb44125a7befd5c735c087e0 100644
--- a/src/modules/Math/matrix.c
+++ b/src/modules/Math/matrix.c
@@ -15,6 +15,8 @@
 
 /* ---------------------------------------------------------------- */
 
+extern struct program *math_matrix_program;
+
 #define FTYPE double
 
 struct matrix_storage
@@ -31,7 +33,8 @@ struct matrix_storage
 #define THISOBJ (fp->current_object)
 
 static struct pike_string *s_array;
-static struct pike_string *s_base;
+static struct pike_string *s__clr;
+static struct pike_string *s_identity;
 
 /* ---------------------------------------------------------------- */
 
@@ -58,7 +61,8 @@ static void matrix_create(INT32 args)
       SIMPLE_TOO_FEW_ARGS_ERROR("matrix",1);
 
    if (THIS->m)
-      SIMPLE_BAD_ARG_ERROR("matrix",1,"not to be called again");
+      bad_arg_error("Matrix", sp-args, args, 1, "", sp-args,\
+		    "Has already been called.\n");
    
    if (sp[-args].type==T_ARRAY)
    {
@@ -123,16 +127,22 @@ static void matrix_create(INT32 args)
 	 if (sp[2-args].type==T_INT)
 	    z=(FTYPE)sp[2-args].u.integer;
 	 else if (sp[2-args].type==T_FLOAT)
-	    z=(FTYPE)sp[2-args].u.integer;
-	 else if (sp[2-args].type!=T_STRING)
+	    z=(FTYPE)sp[2-args].u.float_number;
+	 else if (sp[2-args].type==T_STRING)
 	 {
-	    if (sp[2-args].u.string==s_base)
+	    if (sp[2-args].u.string==s__clr)
+	    {
+	       /* internal call: don't care */
+	       MEMSET(m,0,xs*ys*sizeof(FTYPE));
+	       goto done_made;
+	    }
+	    else if (sp[2-args].u.string==s_identity)
 	    {
 	       pop_n_elems(args-2); /* same as nothing */
 	       args=2;
 	    }
 	    else
-	       SIMPLE_BAD_ARG_ERROR("matrix",3,"\"base\"|int|float");
+	       SIMPLE_BAD_ARG_ERROR("matrix",3,"\"identity\"|int|float");
 	    /* insert other base matrices here */
 	 }
 	 else
@@ -185,15 +195,200 @@ void matrix_cast(INT32 args)
 	    f_aggregate(ys);
 	    return;
 	 }
+
    SIMPLE_BAD_ARG_ERROR("matrix->cast",1,"string");
 }
 
+/* --- helpers ---------------------------------------------------- */
+
+static INLINE struct matrix_storage * _push_new_matrix(int xsize,int ysize)
+{
+   push_int(xsize);
+   push_int(ysize);
+   ref_push_string(s__clr);
+   push_object(clone_object(math_matrix_program,3));
+   return (struct matrix_storage*)
+      get_storage(sp[-1].u.object,math_matrix_program);
+}
+
+/* --- real math stuff --------------------------------------------- */
+
+static void matrix_transpose(INT32 args)
+{
+   struct matrix_storage *mx;
+   int x,y,xs,ys;
+   FTYPE *s,*d;
+
+   pop_n_elems(args);
+   mx=_push_new_matrix(THIS->ysize,THIS->xsize);
+
+   ys=THIS->ysize;
+   xs=THIS->xsize;
+   s=THIS->m;
+   d=mx->m;
+
+   y=xs;
+   while (y--)
+   {
+      x=ys;
+      while (x--)
+	 *(d++)=*s,s+=xs;
+      s-=xs*ys-1;
+   }
+}
+
+static void matrix_add(INT32 args)
+{
+   struct matrix_storage *mx=NULL;
+   struct matrix_storage *dmx;
+   int n;
+   FTYPE *s1,*s2,*d;
+
+   if (args<1)
+      SIMPLE_TOO_FEW_ARGS_ERROR("matrix->`+",1);
+
+   if (sp[-1].type!=T_OBJECT ||
+       !((mx=(struct matrix_storage*)
+	  get_storage(sp[-1].u.object,math_matrix_program))))
+      SIMPLE_BAD_ARG_ERROR("matrix->`+",1,"object(Math.Matrix)");
+
+   if (mx->xsize != THIS->xsize ||
+       mx->ysize != THIS->ysize)
+      math_error("Matrix->`+",sp-args,args,0,
+		 "Can't add matrices of different size");
+
+   pop_n_elems(args-1); /* shouldn't be needed */
+   
+   dmx=_push_new_matrix(mx->xsize,mx->ysize);
+
+   s1=THIS->m;
+   s2=mx->m;
+   d=dmx->m;
+   n=mx->xsize*mx->ysize;
+   while (n--)
+      *(d++)=*(s1++)+*(s2++);
+
+   stack_swap();
+   pop_stack();
+}
+
+static void matrix_sub(INT32 args)
+{
+   struct matrix_storage *mx=NULL;
+   struct matrix_storage *dmx;
+   int n;
+   FTYPE *s1,*s2=NULL,*d;
+
+   if (args) 
+   {
+      if (sp[-1].type!=T_OBJECT ||
+	  !((mx=(struct matrix_storage*)
+	     get_storage(sp[-1].u.object,math_matrix_program))))
+	 SIMPLE_BAD_ARG_ERROR("matrix->`-",1,"object(Math.Matrix)");
+
+      if (mx->xsize != THIS->xsize ||
+	  mx->ysize != THIS->ysize)
+	 math_error("Matrix->`-",sp-args,args,0,
+		    "Can't add matrices of different size");
+
+      pop_n_elems(args-1); /* shouldn't be needed */
+
+      s2=mx->m;
+   }
+   
+   dmx=_push_new_matrix(THIS->xsize,THIS->ysize);
+
+   s1=THIS->m;
+   d=dmx->m;
+   n=THIS->xsize*THIS->ysize;
+
+   if (s2)
+   {
+      while (n--)
+	 *(d++)=*(s1++)-*(s2++);
+      stack_swap();
+      pop_stack();
+   }
+   else
+      while (n--)
+	 *(d++)=-*(s1++);
+}
+
+static void matrix_mult(INT32 args)
+{
+   struct matrix_storage *mx=NULL;
+   struct matrix_storage *dmx;
+   int n,i,j,k,m,p;
+   FTYPE *s1,*s2,*d,*st;
+   FTYPE z;
+
+   if (args<1)
+      SIMPLE_TOO_FEW_ARGS_ERROR("matrix->`*",1);
+
+   pop_n_elems(args-1); /* shouldn't be needed */
+
+   if (sp[-1].type==T_INT)
+   {
+      z=(FTYPE)sp[-1].u.integer;
+      goto scalar_mult;
+   }
+   else if (sp[-1].type==T_FLOAT)
+   {
+      z=(FTYPE)sp[-1].u.float_number;
+scalar_mult:
+
+      dmx=_push_new_matrix(THIS->xsize,THIS->ysize);
+      
+      s1=THIS->m;
+      d=dmx->m;
+      n=THIS->xsize*THIS->ysize;
+      while (n--)
+	 *(d++)=*(s1++)*z;
+
+      stack_swap();
+      pop_stack();
+      return;
+   }
+	 
+   if (sp[-1].type!=T_OBJECT ||
+       !((mx=(struct matrix_storage*)
+	  get_storage(sp[-1].u.object,math_matrix_program))))
+      SIMPLE_BAD_ARG_ERROR("matrix->`*",1,"object(Math.Matrix)");
+
+   if (mx->xsize != THIS->ysize)
+      math_error("Matrix->`*",sp-args,args,0,
+		 "Incompatible matrices");
+
+   m=THIS->xsize;
+   n=THIS->ysize; /* == mx->xsize */
+   p=mx->ysize;
+
+   dmx=_push_new_matrix(m,p);
+
+   s1=THIS->m;
+   s2=mx->m;
+   d=dmx->m;
+   for (k=0; k<p; k++)
+      for (i=0; i<m; i++)
+      {
+	 z=0.0;
+	 st=s2+k*n;
+	 for (j=0; j<n; j++)
+	    z+=s1[i+j*m]**(st++);
+	 *(d++)=z;
+      }
+
+   stack_swap();
+   pop_stack();
+}
+
 /* ---------------------------------------------------------------- */
 
 void init_math_matrix()
 {
    MAKE_CONSTANT_SHARED_STRING(s_array,"array");
-   MAKE_CONSTANT_SHARED_STRING(s_base,"base");
+   MAKE_CONSTANT_SHARED_STRING(s__clr,"_clr");
+   MAKE_CONSTANT_SHARED_STRING(s_identity,"identity");
 
    ADD_STORAGE(struct matrix_storage);
    
@@ -207,4 +402,26 @@ void init_math_matrix()
    
    add_function("cast",matrix_cast,
 		"function(string:array(array(float)))",0);
+
+
+   add_function("transpose",matrix_transpose,
+		"function(:object)",0);
+
+   add_function("add",matrix_add,
+		"function(object:object)",0);
+   add_function("`+",matrix_add,
+		"function(object:object)",0);
+   add_function("`-",matrix_sub,
+		"function(object:object)",0);
+
+   add_function("mult",matrix_mult,
+		"function(object|float|int:object)",0);
+   add_function("`*",matrix_mult,
+		"function(object|float|int:object)",0);
+   add_function("``*",matrix_mult,
+		"function(object|float|int:object)",0);
+   add_function("`�",matrix_mult,
+		"function(object|float|int:object)",0);
+   add_function("``�",matrix_mult,
+		"function(object|float|int:object)",0);
 }