Edinburgh Speech Tools  2.1-release
vec_mat_aux_d.cc
Go to the documentation of this file.
1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1995,1996 */
6 /* All Rights Reserved. */
7 /* */
8 /* Permission is hereby granted, free of charge, to use and distribute */
9 /* this software and its documentation without restriction, including */
10 /* without limitation the rights to use, copy, modify, merge, publish, */
11 /* distribute, sublicense, and/or sell copies of this work, and to */
12 /* permit persons to whom this work is furnished to do so, subject to */
13 /* the following conditions: */
14 /* 1. The code must retain the above copyright notice, this list of */
15 /* conditions and the following disclaimer. */
16 /* 2. Any modifications must be clearly marked as such. */
17 /* 3. Original authors' names are not deleted. */
18 /* 4. The authors' names are not used to endorse or promote products */
19 /* derived from this software without specific prior written */
20 /* permission. */
21 /* */
22 /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23 /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24 /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25 /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26 /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27 /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28 /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29 /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30 /* THIS SOFTWARE. */
31 /* */
32 /*************************************************************************/
33 /* Author : Simon King */
34 /* Date : April 1995 */
35 /*-----------------------------------------------------------------------*/
36 /* EST_DMatrix Class auxiliary functions */
37 /* */
38 /*=======================================================================*/
39 #include <cstdlib>
40 #include "EST_DMatrix.h"
41 #include <climits>
42 #include "EST_math.h"
43 #include "EST_unix.h"
44 
45 using namespace std;
46 
48  EST_DVector &co_effs, int order)
49 {
50  EST_DVector weights;
51  weights.resize(x.n());
52  for(ssize_t i=0; i<x.n(); ++i)
53  weights[i] = 1.0;
54 
55  return polynomial_fit(x,y,co_effs,weights,order);
56 }
57 
59  EST_DVector &weights, int order)
60 {
61 
62  if(order == 0){
63  cerr << "polynomial_fit : order must be >= 1" << endl;
64  return false;
65  }
66 
67  if(x.n() != y.n()){
68  cerr << "polynomial_fit : x and y must have same dimension" << endl;
69  return false;
70  }
71 
72  if(weights.n() != y.n()){
73  cerr << "polynomial_fit : weights must have same dimension as x and y" << endl;
74  return false;
75  }
76 
77  if(x.n() <= order){
78  cerr << "polynomial_fit : x and y must have at least order+1 elements"
79  << endl;
80  return false;
81  }
82 
83 
84  // matrix of basis function values
85  EST_DMatrix A;
86  A.resize(x.n(),order+1);
87 
88  EST_DVector y1;
89  y1.resize(y.n());
90 
91  for(ssize_t row=0;row<y.n();row++)
92  {
93  y1[row] = y[row] * weights[row];
94  for(ssize_t col=0;col<=order;col++){
95  A(row,col) = pow(x[row],(double)col) * weights[row];
96 
97  }
98  }
99 
100  // could call pseudo_inverse, but save a bit by doing
101  // it here since we need transpose(A) anyway
102 
103  EST_DMatrix At, At_A, At_A_inv;
104  int singularity=-2;
105 
106  transpose(A,At);
107  multiply(At,A,At_A);
108 
109  // error check
110  if(!inverse(At_A,At_A_inv,singularity))
111  {
112  cerr << "polynomial_fit : inverse failed (";
113  if(singularity == -2)
114  cerr << "unspecified reason)" << endl;
115  else if(singularity == -1)
116  cerr << "non-square !!)" << endl;
117  else
118  {
119  cerr << "singularity at point : " << singularity;
120  cerr << " = " << x[singularity] << "," << y[singularity];
121  cerr << " )" << endl;
122  }
123  return false;
124  }
125 
126  EST_DVector At_y1 = At * y1;
127  co_effs = At_A_inv * At_y1;
128  return true;
129 
130 }
131 
132 double matrix_max(const EST_DMatrix &a)
133 {
134  ssize_t i, j;
135  double v = INT_MIN;
136 
137  for (i = 0; i < a.num_rows(); ++i)
138  for (j = 0; j < a.num_columns(); ++j)
139  if (a.a_no_check(i, j) > v)
140  v = a.a_no_check(i, j);
141 
142  return v;
143 }
144 
145 int square(const EST_DMatrix &a)
146 {
147  return a.num_rows() == a.num_columns();
148 }
149 // add all elements in matrix.
150 double sum(const EST_DMatrix &a)
151 {
152  ssize_t i, j;
153  double t = 0.0;
154  for (i = 0; i < a.num_rows(); ++i)
155  for (j = 0; j < a.num_columns(); ++j)
156  t += a.a_no_check(i, j);
157  return t;
158 }
159 
160 // set all elements not on the diagonal to zero.
162 {
163  ssize_t i;
164  EST_DMatrix b(a, 0); // initialise and fill b with zeros
165 
166  if (a.num_rows() != a.num_columns())
167  {
168  cerr << "diagonalise: non-square matrix ";
169  return b;
170  }
171 
172  for (i = 0; i < a.num_rows(); ++i)
173  b(i, i) = a.a_no_check(i, i);
174 
175  return b;
176 }
177 
178 // set all elements not on the diagonal to zero.
180 {
181  // NB - will work on non-square matrices without warning
182  ssize_t i,j;
183 
184  for (i = 0; i < a.num_rows(); ++i)
185  for (j = 0; j < a.num_columns(); ++j)
186  if(i != j)
187  a.a_no_check(i, j) = 0;
188 }
189 
191 {
192  ssize_t i, j, I, J;
193  ssize_t n = a.num_rows() - 1;
194  EST_DMatrix s(n, n);
195 
196  for (i = I = 0; i < n; ++i, ++I)
197  {
198  if (I == row)
199  ++I;
200  for (j = J = 0; j < n; ++j, ++J)
201  {
202  if (J == col)
203  ++J;
204  s(i, j) = a.a(I, J);
205  }
206  }
207 
208  // cout << "sub: row " << row << " col " << col << "\n" << s;
209 
210  return s;
211 }
212 
214 {
215  EST_DMatrix s(1, a.num_columns());
216  ssize_t i;
217 
218  for (i = 0; i < a.num_columns(); ++i)
219  s(0, i) = a.a(row, i);
220 
221  return s;
222 }
223 
225 {
226  EST_DMatrix s(a.num_rows(), 1);
227  ssize_t i;
228 
229  for (i = 0; i < a.num_rows(); ++i)
230  s(i, 0) = a.a(i, col);
231 
232  return s;
233 }
234 
236 {
237  EST_DMatrix b(a, 0);
238  ssize_t i, j;
239 
240  for (i = 0; i < a.num_rows(); ++i)
241  for (j = i; j < a.num_rows(); ++j)
242  b(j, i) = a.a(j, i);
243 
244  return b;
245 }
246 
248 {
249  ssize_t i, j;
250  b.resize(a.num_columns(), a.num_rows());
251 
252  for (i = 0; i < b.num_rows(); ++i)
253  for (j = 0; j < b.num_columns(); ++j)
254  b.a_no_check(i, j) = a.a_no_check(j, i);
255 }
256 
258 {
259  ssize_t i, j, n;
260  n = a.num_columns();
261  EST_DMatrix t(n, n);
262 
263  for (i = 0; i < n; ++i)
264  for (j = 0; j < n; ++j)
265  t(n - i - 1, n - j - 1) = a.a(i, j);
266 
267  return t;
268 }
269 
270 
271 // changed name from abs as it causes on at least on POSIX machine
272 // where int abs(int) is a macro
274 {
275  ssize_t i, j;
276  EST_DMatrix b(a, 0);
277 
278  for (i = 0; i < a.num_rows(); ++i)
279  for (j = 0; j < a.num_columns(); ++j)
280  b.a_no_check(i, j) = fabs(a.a_no_check(i, j));
281 
282  return b;
283 }
284 
285 static void row_swap(ssize_t from, ssize_t to, EST_DMatrix &a)
286 {
287  ssize_t i;
288  double f;
289 
290  if (from == to)
291  return;
292 
293  for (i=0; i < a.num_columns(); i++)
294  {
295  f = a.a_no_check(to,i);
296  a.a_no_check(to,i) = a.a_no_check(from,i);
297  a.a_no_check(from,i) = f;
298  }
299 }
300 
301 int inverse(const EST_DMatrix &a,EST_DMatrix &inv)
302 {
303  int singularity=0;
304  return inverse(a,inv,singularity);
305 }
306 
307 int inverse(const EST_DMatrix &a,EST_DMatrix &inv,int &singularity)
308 {
309 
310  // Used to use a function written by Richard Tobin (in C) but
311  // we no longer need C functionality any more. This algorithm
312  // follows that in "Introduction to Algorithms", Cormen, Leiserson
313  // and Rivest (p759) and the term Gauss-Jordon is used for some part,
314  // As well as looking back at Richard's.
315  // This also keeps a record of which rows are which from the original
316  // so that it can return which column actually has the singularity
317  // in it if it fails to find an inverse.
318  ssize_t i, j, k;
319  ssize_t n = a.num_rows();
320  EST_DMatrix b = a; // going to destructively manipulate b to get inv
321  EST_DMatrix pos; // the original position
322  double biggest,s;
323  ssize_t this_row;
324  int r=0,all_zeros;
325 
326  singularity = -1;
327  if (a.num_rows() != a.num_columns())
328  return FALSE;
329 
330  // Make the inverse the identity matrix.
331  inv.resize(n,n);
332  pos.resize(n,1);
333  for (i=0; i<n; i++)
334  for (j=0; j<n; j++)
335  inv.a_no_check(i,j) = 0.0;
336  for (i=0; i<n; i++)
337  {
338  inv.a_no_check(i,i) = 1.0;
339  pos.a_no_check(i,0) = (double)i;
340  }
341 
342  // Manipulate b to make it into the identity matrix, while performing
343  // the same manipulation on inv. Once b becomes the identity inv will
344  // be the inverse (unless theres a singularity)
345 
346  for (i=0; i<n; i++)
347  {
348  // Find the absolute largest val in this col as the next to
349  // manipulate.
350  biggest = 0.0;
351  r = 0;
352  for (j=i; j<n; j++)
353  {
354  if (fabs(b.a_no_check(j,i)) > biggest)
355  {
356  r = j;
357  biggest = fabs(b.a_no_check(j,i));
358  }
359  }
360 
361  if (biggest == 0.0) // oops found a singularity
362  {
363  singularity = (int)pos.a_no_check(i,0);
364  return FALSE;
365  }
366 
367  // Swap current with biggest
368  this_row = (ssize_t)pos.a_no_check(i,0); // in case we need this number
369  row_swap(r,i,b);
370  row_swap(r,i,inv);
371  row_swap(r,i,pos);
372 
373  // Make b(i,i) = 1
374  s = b(i,i);
375  for (k=0; k<n; k++)
376  {
377  b.a_no_check(i,k) /= s;
378  inv.a_no_check(i,k) /= s;
379  }
380 
381  // make rest in col(i) 0
382  for (j=0; j<n; j++)
383  {
384  if (j==i) continue;
385  s = b.a_no_check(j,i);
386  all_zeros = TRUE;
387  for (k=0; k<n; k++)
388  {
389  b.a_no_check(j,k) -= b.a_no_check(i,k) * s;
390  if (b.a_no_check(j,k) != 0)
391  all_zeros = FALSE;
392  inv.a_no_check(j,k) -= inv.a_no_check(i,k) * s;
393  }
394  if (all_zeros)
395  {
396  // printf("singularity between (internal) columns %d %d\n",
397  // this_row,j);
398  // always identify greater row so linear regression
399  // can preserve intercept in column 0
400  singularity = ((this_row > j) ? this_row : j);
401  return FALSE;
402  }
403  }
404  }
405 
406  return TRUE;
407 }
408 
410 {
411  int singularity=0;
412  return pseudo_inverse(a,inv,singularity);
413 }
414 
415 int pseudo_inverse(const EST_DMatrix &a, EST_DMatrix &inv,int &singularity)
416 {
417  // for non-square matrices
418  // useful for solving linear eqns
419  // (e.g. polynomial fitting)
420 
421  // is it square ?
422  if( a.num_rows() == a.num_columns() )
423  return inverse(a,inv,singularity);
424 
425  if( a.num_rows() < a.num_columns() )
426  return FALSE;
427 
428  EST_DMatrix a_trans,atrans_a,atrans_a_inverse;
429 
430  transpose(a,a_trans);
431  multiply(a_trans,a,atrans_a);
432  if (!inverse(atrans_a,atrans_a_inverse,singularity))
433  return FALSE;
434  multiply(atrans_a_inverse,a_trans,inv);
435 
436  return TRUE;
437 }
438 
439 
440 double determinant(const EST_DMatrix &a)
441 {
442  int i, j;
443  int n = a.num_rows();
444  double det;
445  if (!square(a))
446  {
447  cerr << "Tried to take determinant of non-square matrix\n";
448  return 0.0;
449  }
450 
451  EST_DVector A(n);
452 
453  if (n == 2) // special case of 2x2 determinant
454  return (a.a_no_check(0,0) * a.a_no_check(1,1)) -
455  (a.a_no_check(0,1) * a.a_no_check(1,0));
456 
457  double p;
458 
459  // create cofactor matrix
460  j = 1;
461  for (i = 0; i < n; ++i)
462  {
463  p = (double)(i + j + 2); // because i & j should start at 1
464  // cout << "power " <<p << endl;
465  A[i] = pow(-1.0, p) * determinant(sub(a, i, j));
466  }
467  // cout << "cofactor " << A;
468 
469  // sum confactor and original matrix
470  det = 0.0;
471  for (i = 0; i < n; ++i)
472  det += a.a_no_check(i, j) * A[i];
473 
474  return det;
475 }
476 
477 void eye(EST_DMatrix &a, const int n)
478 {
479  int i,j;
480  a.resize(n,n);
481  for (i=0; i<n; i++)
482  {
483  for (j=0; j<n; j++)
484  a.a_no_check(i,j) = 0.0;
485 
486  a.a_no_check(i,i) = 1.0;
487  }
488 }
489 
490 void eye(EST_DMatrix &a)
491 {
492  ssize_t i,n;
493  n=a.num_rows();
494  if(n != a.num_columns())
495  {
496  cerr << "Can't make non-square identity matrix !" << endl;
497  return;
498  }
499 
500  a.fill(0.0);
501  for (i=0; i<n; i++)
502  a.a_no_check(i,i) = 1.0;
503 }
504 
506 {
507  // a - b
508  EST_DVector *ans = new EST_DVector;
509  ssize_t i;
510 
511  if(a.length() != b.length())
512  {
513  cerr << "Can't subtract vectors of differing lengths !" << endl;
514  ans->resize(0);
515  return *ans;
516  };
517 
518  ans->resize(a.length());
519 
520  for(i=0;i<a.length();i++)
521  ans->a_no_check(i) = a.a_no_check(i) + b.a_no_check(i);
522 
523  return *ans;
524 }
525 
527 {
528  // a - b
529  EST_DVector *ans = new EST_DVector;
530  ssize_t i;
531 
532  if(a.length() != b.length())
533  {
534  cerr << "Can't subtract vectors of differing lengths !" << endl;
535  ans->resize(0);
536  return *ans;
537  };
538 
539  ans->resize(a.length());
540 
541  for(i=0;i<a.length();i++)
542  ans->a_no_check(i) = a.a_no_check(i) - b.a_no_check(i);
543 
544  return *ans;
545 }
546 
548 {
549 
550  EST_DVector ans;
551  if(a.num_rows() != a.num_columns())
552  {
553  cerr << "Can't extract diagonal of non-square matrix !" << endl;
554  return ans;
555  }
556  ssize_t i;
557  ans.resize(a.num_rows());
558  for(i=0;i<a.num_rows();i++)
559  ans.a_no_check(i) = a.a_no_check(i,i);
560 
561  return ans;
562 }
563 
564 double polynomial_value(const EST_DVector &coeffs, const double x)
565 {
566  double y=0;
567 
568  for(ssize_t i=0;i<coeffs.length();i++)
569  y += coeffs.a_no_check(i) * pow(x,(double)i);
570 
571  return y;
572 }
573 
575 {
576  // uses include enforcing symmetry
577  // of covariance matrices (to compensate
578  // for rounding errors)
579 
580  double f;
581 
582  if(a.num_columns() != a.num_rows())
583  {
584  cerr << "Can't symmetrize non-square matrix !" << endl;
585  return;
586  }
587 
588  // no need to look at entries on the diagonal !
589  for(ssize_t i=0;i<a.num_rows();i++)
590  for(ssize_t j=i+1;j<a.num_columns();j++)
591  {
592  f = 0.5 * (a.a_no_check(i,j) + a.a_no_check(j,i));
593  a.a_no_check(i,j) = a.a_no_check(j,i) = f;
594  }
595 }
596 
597 void
599 {
600  v.resize(M.num_rows() * M.num_columns());
601  ssize_t i,j,k=0;
602  for(i=0;i<M.num_rows();i++)
603  for(j=0;j<M.num_columns();j++)
604  v.a_no_check(k++) = M(i,j);
605 }
606 
607 
608 void
609 make_random_matrix(EST_DMatrix &M, const double scale)
610 {
611 
612  double r;
613  for(ssize_t row=0;row<M.num_rows();row++)
614  for(ssize_t col=0;col<M.num_columns();col++)
615  {
616  r = scale * ((double)rand()/(double)RAND_MAX);
617  M.a_no_check(row,col) = r;
618  }
619 }
620 
621 void
622 make_random_vector(EST_DVector &V, const double scale)
623 {
624 
625  double r;
626  for(ssize_t i=0;i<V.length();i++)
627  {
628  r = scale * ((double)rand()/(double)RAND_MAX);
629  V.a_no_check(i) = r;
630  }
631 }
632 
633 void
635 {
636  if(M.num_rows() != M.num_columns())
637  {
638  cerr << "Can't make non-square symmetric matrix !" << endl;
639  return;
640  }
641 
642  double r;
643 
644  for(ssize_t row=0;row<M.num_rows();row++)
645  for(ssize_t col=0;col<=row;col++)
646  {
647  r = scale * ((double)rand()/(double)RAND_MAX);
648  M.a_no_check(row,col) = r;
649  M.a_no_check(col,row) = r;
650  }
651 }
652 
653 void
655 {
656  if(M.num_rows() != M.num_columns())
657  {
658  cerr << "Can't make non-square symmetric matrix !" << endl;
659  return;
660  }
661 
662  M.fill(0.0);
663  for(ssize_t row=0;row<M.num_rows();row++)
664  M.a_no_check(row,row) = scale * ((double)rand()/(double)RAND_MAX);
665 
666 
667 }
668 
669 void
671 {
672  if(t.length() != T.num_rows())
673  {
674  cerr << "Can't make polynomial basis function : dimension mismatch !" << endl;
675  cerr << "t.length()=" << t.length();
676  cerr << " T.num_rows()=" << T.num_rows() << endl;
677  return;
678  }
679  for(ssize_t row=0;row<T.num_rows();row++)
680  for(ssize_t col=0;col<T.num_columns();col++)
681  T.a_no_check(row,col) = pow(t[row],(double)col);
682 
683 }
684 
685 int
686 floor_matrix(EST_DMatrix &M, const double floor)
687 {
688  ssize_t i,j,k=0;
689  for(i=0;i<M.num_rows();i++)
690  for(j=0;j<M.num_columns();j++)
691  if(M.a_no_check(i,j) < floor)
692  {
693  M.a_no_check(i,j) = floor;
694  k++;
695  }
696  return k;
697 }
698 
700 cov_prod(const EST_DVector &v1,const EST_DVector &v2)
701 {
702  // form matrix of vector product, e.g. for covariance
703  // treat first arg as a column vector and second as a row vector
704 
705  EST_DMatrix m;
706  m.resize(v1.length(),v2.length());
707 
708  for(ssize_t i=0;i<v1.length();i++)
709  for(ssize_t j=0;j<v2.length();j++)
710  m.a_no_check(i,j) = v1.a_no_check(i) * v2.a_no_check(j);
711 
712  return m;
713 }
int floor_matrix(EST_DMatrix &M, const double floor)
EST_DMatrix backwards(EST_DMatrix &a)
int inverse(const EST_DMatrix &a, EST_DMatrix &inv)
inverse
void stack_matrix(const EST_DMatrix &M, EST_DVector &v)
stack columns on top of each other to make a vector
void transpose(const EST_DMatrix &a, EST_DMatrix &b)
exchange rows and columns
ssize_t num_columns() const
return number of columns
Definition: EST_TMatrix.h:179
INLINE const T & a_no_check(ssize_t n) const
read-only const access operator: without bounds checking
Definition: EST_TVector.h:254
EST_DMatrix triangulate(const EST_DMatrix &a)
ssize_t num_rows() const
return number of rows
Definition: EST_TMatrix.h:177
int ssize_t
const T & a(ssize_t row, ssize_t col) const
Definition: EST_TMatrix.h:196
bool polynomial_fit(EST_DVector &x, EST_DVector &y, EST_DVector &co_effs, int order)
least squares fit
void inplace_diagonalise(EST_DMatrix &a)
inplace diagonalise
EST_DVector subtract(const EST_DVector &a, const EST_DVector &b)
elementwise subtract
void symmetrize(EST_DMatrix &a)
enforce symmetry
void fill(const T &v)
fill matrix with value v
Definition: EST_TMatrix.cc:314
INLINE ssize_t length() const
number of items in vector.
Definition: EST_TVector.h:249
EST_DVector diagonal(const EST_DMatrix &a)
extract leading diagonal as a vector
double polynomial_value(const EST_DVector &coeffs, const double x)
EST_DMatrix sub(const EST_DMatrix &a, ssize_t row, ssize_t col)
void make_poly_basis_function(EST_DMatrix &T, EST_DVector t)
double determinant(const EST_DMatrix &a)
EST_DMatrix cov_prod(const EST_DVector &v1, const EST_DVector &v2)
matrix product of two vectors (#rows = length of first vector, #cols = length of second vector) ...
void make_random_diagonal_matrix(EST_DMatrix &M, const double scale)
used for variance
#define RAND_MAX
Definition: EST_math.h:151
EST_DMatrix diagonalise(const EST_DMatrix &a)
extract leading diagonal as a matrix
void multiply(const EST_DMatrix &a, const EST_DMatrix &b, EST_DMatrix &ab)
Definition: EST_DMatrix.cc:293
#define FALSE
Definition: EST_bool.h:119
EST_DVector add(const EST_DVector &a, const EST_DVector &b)
elementwise add
void make_random_matrix(EST_DMatrix &M, const double scale)
all elements are randomised
A vector class for double precision floating point numbers. EST_DVector x should be used instead of f...
Definition: EST_DMatrix.h:122
f
Definition: EST_item_aux.cc:48
getString int
Definition: EST_item_aux.cc:50
void make_random_vector(EST_DVector &V, const double scale)
all elements are randomised
double matrix_max(const EST_DMatrix &a)
int square(const EST_DMatrix &a)
double sum(const EST_DMatrix &a)
sum of elements
INLINE const T & a_no_check(ssize_t row, ssize_t col) const
const access with no bounds check, care recommend
Definition: EST_TMatrix.h:182
void resize(int rows, int cols, int set=1)
resize matrix
#define TRUE
Definition: EST_bool.h:118
void eye(EST_DMatrix &a, const int n)
some useful matrix creators make an identity matrix of dimension n
INLINE ssize_t n() const
number of items in vector.
Definition: EST_TVector.h:251
EST_DMatrix row(const EST_DMatrix &a, ssize_t row)
void make_random_symmetric_matrix(EST_DMatrix &M, const double scale)
used for covariance
int pseudo_inverse(const EST_DMatrix &a, EST_DMatrix &inv)
pseudo inverse (for non-square matrices)
void resize(int n, int set=1)
resize vector
EST_DMatrix DMatrix_abs(const EST_DMatrix &a)
EST_DMatrix column(const EST_DMatrix &a, ssize_t col)