home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 1 / ARM_CLUB_CD.iso / contents / apps / clib / progs / meschach / !Meschach / c / zmatop < prev    next >
Encoding:
Text File  |  1994-01-12  |  14.9 KB  |  684 lines

  1. ows */
  2.   for (i=0; i < l; i++)
  3.     mat->me[i] = &mat->me2d[i*m];
  4.  
  5.   return mat;
  6. }
  7.  
  8.  
  9. /* deallocate a variable of type MAT3D */
  10.  
  11. int m3d_free(ma, m, n;
  12.     complex    tmp, /* *A_e, */ *out_ve;
  13.     
  14.     if ( ! v1 || ! v2 || ! A )
  15.     error(E_NULL,"zvm_mltadd");
  16.     if ( v2 == out )
  17.     error(E_INSITU,"zvm_mltadd");
  18.     if ( v1->dim != A->n || A->m != v2->dim )
  19.     error(E_SIZES,"zvm_mltadd");
  20.     
  21.     tracecatch(out = zv_copy(v1,out),"zvm_mltadd");
  22.     
  23.     out_ve = out->ve;    m = A->m;    n = A->n;
  24.     for ( j = 0; j < m; j++ )
  25.     {
  26.     /* tmp = zmlt(v2->ve[j],alpha); */
  27.     tmp.re =   v2->ve[j].re*alpha.re - v2->ve[j].im*alpha.im;
  28.     tmp.im =   v2->ve[j].re*alpha.im + v2->ve[j].im*alpha.re;
  29.     if ( tmp.re != 0.0 || tmp.im != 0.0 )
  30.         __zmltadd__(out_ve,A->me[j],tmp,(int)n,Z_CONJ);
  31.     /**************************************************
  32.       A_e = A->me[j];
  33.       for ( i = 0; i < n; i++ )
  34.       out_ve[i] += A_e[i]*tmp;
  35.     **************************************************/
  36.     }
  37.     
  38.     return out;
  39. }
  40.  
  41. /* zget_col -- gets a specified column of a matrix; returned as a vector */
  42. ZVEC    *zget_col(mat,col,vec)
  43. int    col;
  44. ZMAT    *mat;
  45. ZVEC    *vec;
  46. {
  47.     u_int    i;
  48.  
  49.     if ( mat==ZMNULL )
  50.         error(E_NULL,"zget_col");
  51.     if ( col < 0 || col >= mat->n )
  52.         error(E_RANGE,"zget_col");
  53.     if ( vec==ZVNULL || vec->dim<mat->m )
  54.         vec = zv_resize(vec,mat->m);
  55.  
  56.     for ( i=0; i<mat->m; i++ )
  57.         vec->ve[i] = mat->me[i][col];
  58.  
  59.     return (vec);
  60. }
  61.  
  62. /* zget_row -- gets a specified row of a matrix and retruns it as a vector */
  63. ZVEC    *zget_row(mat,row,vec)
  64. int    row;
  65. ZMAT    *mat;
  66. ZVEC    *vec;
  67. {
  68.     int    /* i, */ lim;
  69.  
  70.     if ( mat==ZMNULL )
  71.         error(E_NULL,"zget_row");
  72.     if ( row < 0 || row >= mat->m )
  73.         error(E_RANGE,"zget_row");
  74.     if ( vec==ZVNULL || vec->dim<mat->n )
  75.         vec = zv_resize(vec,mat->n);
  76.  
  77.     lim = min(mat->n,vec->dim);
  78.  
  79.     /* for ( i=0; i<mat->n; i++ ) */
  80.     /*     vec->ve[i] = mat->me[row][i]; */
  81.     MEMCOPY(mat->me[row],vec->ve,lim,complex);
  82.  
  83.     return (vec);
  84. }
  85.  
  86. /* zset_col -- sets column of matrix to values given in vec (in situ) */
  87. ZMAT    *zset_col(mat,col,vec)
  88. ZMAT    *mat;
  89. ZVEC    *vec;
  90. int    col;
  91. {
  92.     u_int    i,lim;
  93.  
  94.     if ( mat==ZMNULL || vec==ZVNULL )
  95.         error(E_NULL,"zset_col");
  96.     if ( col < 0 || col >= mat->n )
  97.         error(E_RANGE,"zset_col");
  98.     lim = min(mat->m,vec->dim);
  99.     for ( i=0; i<lim; i++ )
  100.         mat->me[i][col] = vec->ve[i];
  101.  
  102.     return (mat);
  103. }
  104.  
  105. /* zset_row -- sets row of matrix to values given in vec (in situ) */
  106. ZMAT    *zset_row(mat,row,vec)
  107. ZMAT    *mat;
  108. ZVEC    *vec;
  109. int    row;
  110. {
  111.     u_int    /* j, */ lim;
  112.  
  113.     if ( mat==ZMNULL || vec==ZVNULL )
  114.         error(E_NULL,"zset_row");
  115.     if ( row < 0 || row >= mat->m )
  116.         error(E_RANGE,"zset_row");
  117.     lim = min(mat->n,vec->dim);
  118.     /* for ( j=j0; j<lim; j++ ) */
  119.     /*     mat->me[row][j] = vec->ve[j]; */
  120.     MEMCOPY(vec->ve,mat->me[row],lim,complex);
  121.  
  122.     return (mat);
  123. }
  124.  
  125. /* zm_rand -- randomise a complex matrix; uniform in [0,1)+[0,1)*i */
  126. ZMAT    *zm_rand(A)
  127. ZMAT    *A;
  128. {
  129.     int        i;
  130.  
  131.     if ( ! A )
  132.     error(E_NULL,"zm_rand");
  133.  
  134.     for ( i = 0; i < A->m; i++ )
  135.     mrandlist((Real *)(A->me[i]),2*A->n);
  136.  
  137.     return A;
  138. }
  139. FileDataŵzmemory«;Eÿÿÿ`hA¨°
  140. /**************************************************************************
  141. **
  142. ** Copyright (C) 1993 David E. Steward & Zbigniew Leyk, all rights reserved.
  143. **
  144. **                 Meschach Library
  145. ** 
  146. ** This Meschach Library is provided "as is" without any express 
  147. ** or implied warranty of any kind with respect to this software. 
  148. ** In particular the authors shall not be liable for any direct, 
  149. ** indirect, special, incidental or consequential damages arising 
  150. ** in any way from use of the software.
  151. ** 
  152. ** Everyone is granted permission to copy, modify and redistribute this
  153. ** Meschach Library, provided:
  154. **  1.  All copies contain this copyright notice.
  155. **  2.  All modified copies shall carry a notice stating who
  156. **      made the last modification and the date of such modification.
  157. **  3.  No charge is made for this software or works derived from it.  
  158. **      This clause shall not be construed as constraining other software
  159. **      distributed on the same medium as this software, nor is a
  160. **      distribution fee considered a charge.
  161. **
  162. ***************************************************************************/
  163.  
  164.  
  165. /* Memory allocation and de-allocation for complex matrices and vectors */
  166.  
  167. #include    <stdio.h>
  168. #include    "zmatrix.h"
  169.  
  170. static    char    rcsid[] = "$Id: zmemory.c,v 1.2 1994/04/05 02:13:14 des Exp $";
  171.  
  172.  
  173.  
  174. /* zv_zero -- zeros all entries of a complex vector
  175.    -- uses __zzero__() */
  176. ZVEC    *zv_zero(x)
  177. ZVEC    *x;
  178. {
  179.    if ( ! x )
  180.      error(E_NULL,"zv_zero");
  181.    __zzero__(x->ve,x->dim);
  182.    
  183.    return x;
  184. }
  185.  
  186. /* zm_zero -- zeros all entries of a complex matrix
  187.    -- uses __zzero__() */
  188. ZMAT    *zm_zero(A)
  189. ZMAT    *A;
  190. {
  191.    int        i;
  192.    
  193.    if ( ! A )
  194.      error(E_NULL,"zm_zero");
  195.    for ( i = 0; i < A->m; i++ )
  196.      __zzero__(A->me[i],A->n);
  197.    
  198.    return A;
  199. }
  200.  
  201. /* zm_get -- gets an mxn complex matrix (in ZMAT form) */
  202. ZMAT    *zm_get(m,n)
  203. int    m,n;
  204. {
  205.    ZMAT    *matrix;
  206.    u_int    i;
  207.    
  208.    if (m < 0 || n < 0)
  209.      error(E_NEG,"zm_get");
  210.  
  211.    if ((matrix=NEW(ZMAT)) == (ZMAT *)NULL )
  212.      error(E_MEM,"zm_get");
  213.    else if (mem_info_is_on()) {
  214.       mem_bytes(TYPE_ZMAT,0,sizeof(ZMAT));
  215.       mem_numvar(TYPE_ZMAT,1);
  216.    }
  217.    
  218.    matrix->m = m;        matrix->n = matrix->max_n = n;
  219.    matrix->max_m = m;    matrix->max_size = m*n;
  220. #ifndef SEGMENTED
  221.    if ((matrix->base = NEW_A(m*n,complex)) == (complex *)NULL )
  222.    {
  223.       free(matrix);
  224.       error(E_MEM,"zm_get");
  225.    }
  226.    else if (mem_info_is_on()) {
  227.       mem_bytes(TYPE_ZMAT,0,m*n*sizeof(complex));
  228.    }
  229. #else
  230.    matrix->base = (complex *)NULL;
  231. #endif
  232.    if ((matrix->me = (complex **)calloc(m,sizeof(complex *))) == 
  233.        (complex **)NULL )
  234.    {    free(matrix->base);    free(matrix);
  235.     error(E_MEM,"zm_get");
  236.      }
  237.    else if (mem_info_is_on()) {
  238.       mem_bytes(TYPE_ZMAT,0,m*sizeof(complex *));
  239.    }
  240. #ifndef SEGMENTED
  241.    /* set up pointers */
  242.    for ( i=0; i<m; i++ )
  243.      matrix->me[i] = &(matrix->base[i*n]);
  244. #else
  245.    for ( i = 0; i < m; i++ )
  246.      if ( (matrix->me[i]=NEW_A(n,complex)) == (complex *)NULL )
  247.        error(E_MEM,"zm_get");
  248.      else if (mem_info_is_on()) {
  249.     mem_bytes(TYPE_ZMAT,0,n*sizeof(complex));
  250.      }
  251. #endif
  252.    
  253.    return (matrix);
  254. }
  255.  
  256.  
  257. /* zv_get -- gets a ZVEC of dimension 'dim'
  258.    -- Note: initialized to zero */
  259. ZVEC    *zv_get(size)
  260. int    size;
  261. {
  262.    ZVEC    *vector;
  263.  
  264.    if (size < 0)
  265.      error(E_NEG,"zv_get");
  266.  
  267.    if ((vector=NEW(ZVEC)) == (ZVEC *)NULL )
  268.      error(E_MEM,"zv_get");
  269.    else if (mem_info_is_on()) {
  270.       mem_bytes(TYPE_ZVEC,0,sizeof(ZVEC));
  271.       mem_numvar(TYPE_ZVEC,1);
  272.    }
  273.    vector->dim = vector->max_dim = size;
  274.    if ((vector->ve=NEW_A(size,complex)) == (complex *)NULL )
  275.    {
  276.       free(vector);
  277.       error(E_MEM,"zv_get");
  278.    }
  279.    else if (mem_info_is_on()) {
  280.       mem_bytes(TYPE_ZVEC,0,size*sizeof(complex));
  281.    }
  282.    return (vector);
  283. }
  284.  
  285. /* zm_free -- returns ZMAT & asoociated memory back to memory heap */
  286. int    zm_free(mat)
  287. ZMAT    *mat;
  288. {
  289. #ifdef SEGMENTED
  290.    int    i;
  291. #endif
  292.    
  293.    if ( mat==(ZMAT *)NULL || (int)(mat->m) < 0 ||
  294.        (int)(mat->n) < 0 )
  295.      /* don't trust it */
  296.      return (-1);
  297.    
  298. #ifndef SEGMENTED
  299.    if ( mat->base != (complex *)NULL ) {
  300.       if (mem_info_is_on()) {
  301.      mem_bytes(TYPE_ZMAT,mat->max_m*mat->max_n*sizeof(complex),0);
  302.       }       
  303.       free((char *)(mat->base));
  304.    }
  305. #else
  306.    for ( i = 0; i < mat->max_m; i++ )
  307.      if ( mat->me[i] != (complex *)NULL ) {
  308.     if (mem_info_is_on()) {
  309.        mem_bytes(TYPE_ZMAT,mat->max_n*sizeof(complex),0);
  310.     }
  311.     free((char *)(mat->me[i]));
  312.      }
  313. #endif
  314.    if ( mat->me != (complex **)NULL ) {
  315.       if (mem_info_is_on()) {
  316.      mem_bytes(TYPE_ZMAT,mat->max_m*sizeof(complex *),0);
  317.       }       
  318.       free((char *)(mat->me));
  319.    }
  320.    
  321.    if (mem_info_is_on()) {
  322.       mem_bytes(TYPE_ZMAT,sizeof(ZMAT),0);
  323.       mem_numvar(TYPE_ZMAT,-1);
  324.    }
  325.    free((char *)mat);
  326.    
  327.    return (0);
  328. }
  329.  
  330.  
  331. /* zv_free -- returns ZVEC & asoociated memory back to memory heap */
  332. int    zv_free(vec)
  333. ZVEC    *vec;
  334. {
  335.    if ( vec==(ZVEC *)NULL || (int)(vec->dim) < 0 )
  336.      /* don't trust it */
  337.      return (-1);
  338.    
  339.    if ( vec->ve == (complex *)NULL ) {
  340.       if (mem_info_is_on()) {
  341.      mem_bytes(TYPE_ZVEC,sizeof(ZVEC),0);
  342.      mem_numvar(TYPE_ZVEC,-1);
  343.       }
  344.       free((char *)vec);
  345.    }
  346.    else
  347.    {
  348.       if (mem_info_is_on()) {
  349.      mem_bytes(TYPE_ZVEC,vec->max_dim*sizeof(complex)+
  350.               sizeof(ZVEC),0);
  351.      mem_numvar(TYPE_ZVEC,-1);
  352.       }
  353.       
  354.       free((char *)vec->ve);
  355.       free((char *)vec);
  356.    }
  357.    
  358.    return (0);
  359. }
  360.  
  361.  
  362. /* zm_resize -- returns the matrix A of size new_m x new_n; A is zeroed
  363.    -- if A == NULL on entry then the effect is equivalent to m_get() */
  364. ZMAT    *zm_resize(A,new_m,new_n)
  365. ZMAT    *A;
  366. int    new_m, new_n;
  367. {
  368.    u_int    i, new_max_m, new_max_n, new_size, old_m, old_n;
  369.    
  370.    if (new_m < 0 || new_n < 0)
  371.      error(E_NEG,"zm_resize");
  372.  
  373.    if ( ! A )
  374.      return zm_get(new_m,new_n);
  375.    
  376.    if (new_m == A->m && new_n == A->n)
  377.      return A;
  378.  
  379.    old_m = A->m;    old_n = A->n;
  380.    if ( new_m > A->max_m )
  381.    {    /* re-allocate A->me */
  382.       if (mem_info_is_on()) {
  383.      mem_bytes(TYPE_ZMAT,A->max_m*sizeof(complex *),
  384.               new_m*sizeof(complex *));
  385.       }
  386.  
  387.       A->me = RENEW(A->me,new_m,complex *);
  388.       if ( ! A->me )
  389.     error(E_MEM,"zm_resize");
  390.    }
  391.    new_max_m = max(new_m,A->max_m);
  392.    new_max_n = max(new_n,A->max_n);
  393.    
  394. #ifndef SEGMENTED
  395.    new_size = new_max_m*new_max_n;
  396.    if ( new_size > A->max_size )
  397.    {    /* re-allocate A->base */
  398.       if (mem_info_is_on()) {
  399.      mem_bytes(TYPE_ZMAT,A->max_m*A->max_n*sizeof(complex),
  400.         new_size*sizeof(complex));      
  401.       }
  402.  
  403.       A->base = RENEW(A->base,new_size,complex);
  404.       if ( ! A->base )
  405.     error(E_MEM,"zm_resize");
  406.       A->max_size = new_size;
  407.    }
  408.    
  409.    /* now set up A->me[i] */
  410.    for ( i = 0; i < new_m; i++ )
  411.      A->me[i] = &(A->base[i*new_n]);
  412.    
  413.    /* now shift data in matrix */
  414.    if ( old_n > new_n )
  415.    {
  416.       for ( i = 1; i < min(old_m,new_m); i++ )
  417.     MEM_COPY((char *)&(A->base[i*old_n]),
  418.          (char *)&(A->base[i*new_n]),
  419.          sizeof(complex)*new_n);
  420.    }
  421.    else if ( old_n < new_n )
  422.    {
  423.       for ( i = min(old_m,new_m)-1; i > 0; i-- )
  424.       {   /* copy & then zero extra space */
  425.      MEM_COPY((char *)&(A->base[i*old_n]),
  426.           (char *)&(A->base[i*new_n]),
  427.           sizeof(complex)*old_n);
  428.      __zzero__(&(A->base[i*new_n+old_n]),(new_n-old_n));
  429.       }
  430.       __zzero__(&(A->base[old_n]),(new_n-old_n));
  431.       A->max_n = new_n;
  432.    }
  433.    /* zero out the new rows.. */
  434.    for ( i = old_m; i < new_m; i++ )
  435.      __zzero__(&(A->base[i*new_n]),new_n);
  436. #else
  437.    if ( A->max_n < new_n )
  438.    {
  439.       complex    *tmp;
  440.       
  441.       for ( i = 0; i < A->max_m; i++ )
  442.       {
  443.      if (mem_info_is_on()) {
  444.         mem_bytes(TYPE_ZMAT,A->max_n*sizeof(complex),
  445.              new_max_n*sizeof(complex));
  446.      }
  447.  
  448.      if ( (tmp = RENEW(A->me[i],new_max_n,complex)) == NULL )
  449.        error(E_MEM,"zm_resize");
  450.      else {
  451.         A->me[i] = tmp;
  452.      }
  453.       }
  454.       for ( i = A->max_m; i < new_max_m; i++ )
  455.       {
  456.      if ( (tmp = NEW_A(new_max_n,complex)) == NULL )
  457.        error(E_MEM,"zm_resize");
  458.      else {
  459.         A->me[i] = tmp;
  460.         if (mem_info_is_on()) {
  461.            mem_bytes(TYPE_ZMAT,0,new_max_n*sizeof(complex));
  462.         }
  463.      }
  464.       }
  465.    }
  466.    else if ( A->max_m < new_m )
  467.    {
  468.       for ( i = A->max_m; i < new_m; i++ )
  469.     if ( (A->me[i] = NEW_A(new_max_n,complex)) == NULL )
  470.       error(E_MEM,"zm_resize");
  471.     else if (mem_info_is_on()) {
  472.        mem_bytes(TYPE_ZMAT,0,new_max*sizeof(complex));
  473.     }
  474.       
  475.    }
  476.    
  477.    if ( old_n < new_n )
  478.    {
  479.       for ( i = 0; i < old_m; i++ )
  480.     __zzero__(&(A->me[i][old_n]),new_n-old_n);
  481.    }
  482.    
  483.    /* zero out the new rows.. */
  484.    for ( i = old_m; i < new_m; i++ )
  485.      __zzero__(A->me[i],new_n);
  486. #endif
  487.    
  488.    A->max_m = new_max_m;
  489.    A->max_n = new_max_n;
  490.    A->max_size = A->max_m*A->max_n;
  491.    A->m = new_m;    A->n = new_n;
  492.    
  493.    return A;
  494. }
  495.  
  496.  
  497. /* zv_resize -- returns the (complex) vector x with dim new_dim
  498.    -- x is set to the zero vector */
  499. ZVEC    *zv_resize(x,new_dim)
  500. ZVEC    *x;
  501. int    new_dim;
  502. {
  503.    if (new_dim < 0)
  504.      error(E_NEG,"zv_resize");
  505.  
  506.    if ( ! x )
  507.      return zv_get(new_dim);
  508.  
  509.    if (new_dim == x->dim)
  510.      return x;
  511.  
  512.    if ( x->max_dim == 0 )    /* assume that it's from sub_zvec */
  513.      return zv_get(new_dim);
  514.    
  515.    if ( new_dim > x->max_dim )
  516.    {
  517.       if (mem_info_is_on()) { 
  518.      mem_bytes(TYPE_ZVEC,x->max_dim*sizeof(complex),
  519.               new_dim*sizeof(complex));
  520.       }
  521.  
  522.       x->ve = RENEW(x->ve,new_dim,complex);
  523.       if ( ! x->ve )
  524.     error(E_MEM,"zv_resize");
  525.       x->max_dim = new_dim;
  526.    }
  527.    
  528.    if ( new_dim > x->dim )
  529.      __zzero__(&(x->ve[x->dim]),new_dim - x->dim);
  530.    x->dim = new_dim;
  531.    
  532.    return x;
  533. }
  534.  
  535.  
  536. /* varying arguments */
  537.  
  538. #ifdef ANSI_C
  539.  
  540. #include <stdarg.h>
  541.  
  542.  
  543. /* To allocate memory to many arguments. 
  544.    The function should be called:
  545.    zv_get_vars(dim,&x,&y,&z,...,NULL);
  546.    where 
  547.      int dim;
  548.      ZVEC *x, *y, *z,...;
  549.      The last argument should be NULL ! 
  550.      dim is the length of vectors x,y,z,...
  551.      returned value is equal to the number of allocated variables
  552.      Other gec_... functions are similar.
  553. */
  554.  
  555. int zv_get_vars(int dim,...) 
  556. {
  557.    va_list ap;
  558.    int i=0;
  559.    ZVEC **par;
  560.    
  561.    va_start(ap, dim);
  562.    while (par = va_arg(ap,ZVEC **)) {   /* NULL ends the list*/
  563.       *par = zv_get(dim);
  564.       i++;
  565.    } 
  566.  
  567.    va_end(ap);
  568.    return i;
  569. }
  570.  
  571.  
  572.  
  573. int zm_get_vars(int m,int n,...) 
  574. {
  575.    va_list ap;
  576.    int i=0;
  577.    ZMAT **par;
  578.    
  579.    va_start(ap, n);
  580.    while (par = va_arg(ap,ZMAT **)) {   /* NULL ends the list*/
  581.       *par = zm_get(m,n);
  582.       i++;
  583.    } 
  584.  
  585.    va_end(ap);
  586.    return i;
  587. }
  588.  
  589.  
  590.  
  591. /* To resize memory for many arguments. 
  592.    The function should be called:
  593.    v_resize_vars(new_dim,&x,&y,&z,...,NULL);
  594.    where 
  595.      int new_dim;
  596.      ZVEC *x, *y, *z,...;
  597.      The last argument should be NULL ! 
  598.      rdim is the resized length of vectors x,y,z,...
  599.      returned value is equal to the number of allocated variables.
  600.      If one of x,y,z,.. arguments is NULL then memory is allocated to this 
  601.      argument. 
  602.      Other *_resize_list() functions are similar.
  603. */
  604.  
  605. int zv_resize_vars(int new_dim,...)
  606. {
  607.    va_list ap;
  608.    int i=0;
  609.    ZVEC **par;
  610.    
  611.    va_start(ap, new_dim);
  612.    while (par = va_arg(ap,ZVEC **)) {   /* NULL ends the list*/
  613.       *par = zv_resize(*par,new_dim);
  614.       i++;
  615.    } 
  616.  
  617.    va_end(ap);
  618.    return i;
  619. }
  620.  
  621.  
  622.  
  623. int zm_resize_vars(int m,int n,...) 
  624. {
  625.    va_list ap;
  626.    int i=0;
  627.    ZMAT **par;
  628.    
  629.    va_start(ap, n);
  630.    while (par = va_arg(ap,ZMAT **)) {   /* NULL ends the list*/
  631.       *par = zm_resize(*par,m,n);
  632.       i++;
  633.    } 
  634.  
  635.    va_end(ap);
  636.    return i;
  637. }
  638.  
  639.  
  640. /* To deallocate memory for many arguments. 
  641.    The function should be called:
  642.    v_free_vars(&x,&y,&z,...,NULL);
  643.    where 
  644.      ZVEC *x, *y, *z,...;
  645.      The last argument should be NULL ! 
  646.      There must be at least one not NULL argument.
  647.      returned value is equal to the number of allocated variables.
  648.      Returned value of x,y,z,.. is VNULL.
  649.      Other *_free_list() functions are similar.
  650. */
  651.  
  652. int zv_free_vars(ZVEC **pv,...)
  653. {
  654.    va_list ap;
  655.    int i=1;
  656.    ZVEC **par;
  657.    
  658.    zv_free(*pv);
  659.    *pv = ZVNULL;
  660.    va_start(ap, pv);
  661.    while (par = va_arg(ap,ZVEC **)) {   /* NULL ends the list*/
  662.       zv_free(*par); 
  663.       *par = ZVNULL;
  664.       i++;
  665.    } 
  666.  
  667.    va_end(ap);
  668.    return i;
  669. }
  670.  
  671.  
  672.  
  673. int zm_free_vars(ZMAT **va,...)
  674. {
  675.    va_list ap;
  676.    int i=1;
  677.    ZMAT **par;
  678.    
  679.    zm_free(*va);
  680.    *va = ZMNULL;
  681.    va_start(ap, va);
  682.    while (par = va_arg(ap,ZMAT **)) {   /* NULL ends the list*/
  683.       zm_free(*par); 
  684.