table.h
Go to the documentation of this file.
1 /*
2  -------------------------------------------------------------------
3 
4  Copyright (C) 2006-2018, Andrew W. Steiner
5 
6  This file is part of O2scl.
7 
8  O2scl is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version.
12 
13  O2scl is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with O2scl. If not, see <http://www.gnu.org/licenses/>.
20 
21  -------------------------------------------------------------------
22 */
23 #ifndef O2SCL_TABLE_H
24 #define O2SCL_TABLE_H
25 
26 /** \file table.h
27  \brief File defining \ref o2scl::table
28 */
29 
30 #include <iostream>
31 #include <fstream>
32 #include <string>
33 #include <cmath>
34 #include <sstream>
35 #include <map>
36 
37 #include <boost/numeric/ublas/vector.hpp>
38 #include <boost/numeric/ublas/matrix.hpp>
39 
40 #include <o2scl/misc.h>
41 #include <o2scl/interp.h>
42 
43 #include <o2scl/shunting_yard.h>
44 
45 #ifndef DOXYGEN_NO_O2NS
46 
47 // Forward definition of the table class for HDF I/O
48 namespace o2scl {
49  template<class vec_t> class table;
50 }
51 
52 // Forward definition of HDF I/O to extend friendship in table
53 namespace o2scl_hdf {
54  class hdf_file;
55  template<class vec_t>
56  void hdf_input(hdf_file &hf, o2scl::table<vec_t> &t, std::string name);
57  void hdf_output(hdf_file &hf,
58  o2scl::table<std::vector<double> > &t,
59  std::string name);
60  template<class vec_t>
62  void hdf_output_data(hdf_file &hf,
63  o2scl::table<std::vector<double> > &t);
64 }
65 
66 #endif
67 
68 #ifndef DOXYGEN_NO_O2NS
69 namespace o2scl {
70 #endif
71 
72  /** \brief Data \table class
73 
74  \b Summary \n
75 
76  A class to contain and manipulate several equally-sized columns
77  of data. The purpose of this class is to provide a structure
78  which allows one to refer to the columns using a name
79  represented by a string. Thus for a table object named \c t with
80  3 columns (named "colx", "coly" and "colz") and three rows, one
81  could do the following:
82  \include table_doc1.cpp
83  Note that the rows are numbered starting with 0 instead of
84  starting with 1.
85  To output all the rows of entire column, one can use
86  \include table_doc2.cpp
87  To output all the columns of an entire row (in the following
88  example it is the second row), labeled by their column name, one
89  can use:
90  \include table_doc3.cpp
91 
92  Methods are provided for interpolating columns, sorting
93  columns, finding data points, and several other manipulations
94  of the data.
95 
96  <B> Lookup, differentiation, integration, and
97  interpolation </b> \n
98 
99  Lookup, differentiation, integration, and interpolation are
100  automatically implemented using splines from the class \ref
101  interp_vec. A caching mechanism is implemented so that
102  successive interpolations, derivative evaluations or
103  integrations over the same two columns are fast.
104 
105  <B> Sorting </b>\n
106 
107  The columns are automatically sorted by name for speed, the
108  results can be accessed from \ref get_sorted_name(). Individual
109  columns can be sorted (\ref sort_column() ), or the entire table
110  can be sorted by one column (\ref sort_table() ).
111 
112  <B> Data representation </b> \n
113 
114  Each individual column is just a vector object.
115  The columns can be referred to in one of two ways:
116  - A numerical index from 0 to C-1 (where C is the number of
117  columns). For example, data can be accessed through \ref
118  table::get() and \ref table::set(size_t c, size_t r,
119  double val), or the overloaded [] operator, <tt>table[c][r]</tt>.
120  - A name of the column which is a string.
121  For example, data can be accessed with table::get(string cname,
122  int r) and table::set(string cname, int r, double val).
123 
124  The columns are organized in a both a <map> and a <vector>
125  structure so that finding a column by its index, using either of
126  \code
127  std::string table::get_column_name(size_t index);
128  ubvector &table::operator[](size_t index);
129  \endcode
130  takes only constant time, and finding a column by its name
131  using either of
132  \code
133  size_t lookup_column(std::string name) const;
134  const ubvector &get_column(std::string col) const;
135  \endcode
136  is O(log(C)). Insertion of a column ( \ref new_column() ) is
137  O(log(C)), but deletion ( \ref delete_column() ) is O(C). Adding
138  a row of data can be either O(1) or O(C), but row insertion and
139  deletion is slow, since the all of the rows must be shifted
140  accordingly.
141 
142  Because of the structure, this class is not suitable for the
143  matrix manipulation.
144 
145  <b>Vector types</b> \n
146 
147  The type <tt>vec_t</tt> can be any vector type with
148  <tt>operator[]</tt>, <tt>size()</tt> and <tt>resize()</tt>
149  methods. HDF5 I/O with vector types other than
150  <tt>std::vector<double> </tt> requires a copy. See the
151  the discussion in the sections \ref tensor_subsect
152  and \ref vec_io_cont_subsect of the user's guide for
153  more details.
154 
155  <b>Thread-safety</b> \n
156 
157  Generally, the member functions are only thread-safe
158  if they are <tt>const</tt> .
159 
160  \b I/O \b and \b command-line \b manipulation \n
161 
162  When data from an object of type \ref table is output to a file
163  through the <tt>hdf_output() function</tt> in \ref o2scl_hdf,
164  the table can be manipulated on the command-line through the \c
165  acol utility (see \ref acol_section).
166 
167  There is an example for the usage of this class given
168  in <tt>examples/ex_table.cpp</tt>.
169 
170  \future
171  - Create a sort_column_names() or a function to
172  arbitrarily rearrange the columns
173  - The present structure, \c
174  std::map<std::string,col,string_comp> atree and \c
175  std::vector<aiter> alist; could be replaced with \c
176  std::vector<col> list and \c std::map<std::string,int> tree
177  where the map just stores the index of the the column in the
178  list.
179  - Rewrite check_synchro into a full is_valid()-like
180  sanity check
181  */
182  template<class vec_t=std::vector<double> > class table {
183 
184  public:
185 
186  /// \name Constructors, destructors
187  //@{
188  /** \brief Create a new table with space for nlines<=cmaxlines.
189  */
190  table(size_t cmaxlines=0) {
191  nlines=0;
192  intp_set=false;
193  maxlines=cmaxlines;
194  itype=itp_cspline;
195  }
196 
197  /** \brief Table destructor
198  */
199  virtual ~table() {
200  if (intp_set==true) {
201  delete si;
202  }
203  }
204 
205  /// Copy constructor
206  table(const table &t) {
207 
208  // Copy constants
209  constants=t.constants;
210 
211  // Copy interpolation type
212  itype=t.itype;
213 
214  // Copy the columns and data
215  nlines=t.get_nlines();
216  maxlines=nlines;
217 
218  for(size_t i=0;i<t.get_ncolumns();i++) {
219 
220  // Column name
221  std::string cname=t.get_column_name(i);
222 
223  // Insert column into tree
224  col s;
225  s.dat.resize(nlines);
226  s.index=atree.size();
227  atree.insert(make_pair(cname,s));
228 
229  // Insert in iterator index
230  aiter it=atree.find(cname);
231  alist.push_back(it);
232 
233  // Fill the data
234  for(size_t j=0;j<t.get_nlines();j++) {
235  it->second.dat[j]=t.get(cname,j);
236  }
237 
238  }
239 
240  intp_set=false;
241 
242  is_valid();
243 
244  return;
245  }
246 
247  /// Copy constructor
248  table &operator=(const table &t) {
249 
250  if (this!=&t) {
251 
252  clear();
253 
254  // Copy constants
255  constants=t.constants;
256 
257  // Copy the columns and data
258  nlines=t.get_nlines();
259  maxlines=nlines;
260 
261  // Copy interpolation type
262  itype=t.itype;
263 
264  for(size_t i=0;i<t.get_ncolumns();i++) {
265 
266  // Column name
267  std::string cname=t.get_column_name(i);
268 
269  // Insert column into tree
270  col s;
271  s.dat.resize(nlines);
272  s.index=atree.size();
273  atree.insert(make_pair(cname,s));
274 
275  // Insert in iterator index
276  aiter it=atree.find(cname);
277  alist.push_back(it);
278 
279  // Fill the data
280  for(size_t j=0;j<t.get_nlines();j++) {
281  it->second.dat[j]=t.get(cname,j);
282  }
283 
284  }
285 
286  if (intp_set) {
287  intp_set=false;
288  delete si;
289  }
290 
291  }
292 
293  is_valid();
294 
295  return *this;
296  }
297  //@}
298 
299  // --------------------------------------------------------
300  /** \name Basic get and set methods */
301  //@{
302  /** \brief Set row \c row of column named \c col to value \c val .
303  \f$ {\cal O}(\log(C)) \f$
304 
305  This function calls the error handler if the row is beyond
306  the end of the table or if the specified column is not found.
307  */
308  void set(std::string scol, size_t row, double val) {
309 
310  if (row>=nlines) {
311  std::string str=((std::string)"Row ")+o2scl::szttos(row)+
312  " beyond end of table (nlines="+o2scl::szttos(nlines)+") in "+
313  "table::set(string,size_t,double).";
314  O2SCL_ERR(str.c_str(),exc_einval);
315  return;
316  }
317 
318  aiter it=atree.find(scol);
319  if (it==atree.end()) {
320  O2SCL_ERR((((std::string)"Column '")+scol+
321  "' not found in table::set(string,size_t,double).").c_str(),
322  exc_enotfound);
323  return;
324  }
325 
326  if ((intp_colx==scol || intp_coly==scol) && intp_set==true) {
327  delete si;
328  intp_set=false;
329  }
330 
331 #if !O2SCL_NO_RANGE_CHECK
332  if (row>=it->second.dat.size()) {
333  O2SCL_ERR("Vector size failure in table::set(string,size_t,double).",
334  exc_esanity);
335  }
336 #endif
337  it->second.dat[row]=val;
338 
339  return;
340  }
341 
342  /** \brief Set row \c row of column number \c icol to value \c val .
343  \f$ {\cal O}(1) \f$
344  */
345  void set(size_t icol, size_t row, double val) {
346 
347  if (row>=nlines) {
348  O2SCL_ERR2("Specified row beyond end of table in ",
349  "table::set(size_t,size_t,double).",exc_einval);
350  return;
351  }
352 
353  if (icol>=atree.size()) {
354  std::string err=((std::string)"Column index ")+szttos(icol)+
355  ">="+szttos(atree.size())+", in table::set(size_t,size_t,double).";
356  O2SCL_ERR(err.c_str(),exc_einval);
357  }
358 
359  std::string scol=get_column_name(icol);
360  if ((intp_colx==scol || intp_coly==scol) && intp_set==true) {
361  delete si;
362  intp_set=false;
363  }
364 
365 #if !O2SCL_NO_RANGE_CHECK
366  if (row>=alist[icol]->second.dat.size()) {
367  O2SCL_ERR("Vector size failure in table::set(size_t,size_t,double).",
368  exc_esanity);
369  }
370 #endif
371  alist[icol]->second.dat[row]=val;
372  return;
373  }
374 
375  /** \brief Set an entire row of data
376 
377  This function goes through \c v copying data until it runs out
378  of columns in the table or it runs out of entries in \c v,
379  whichever comes first.
380 
381  The type <tt>size_vec_t</tt> must be a type which has a
382  <tt>size()</tt> method.
383  */
384  template<class size_vec_t> void set_row(size_t row, size_vec_t &v) {
385  if (row>=get_nlines()) {
386  std::string err=((std::string)"Row out of range, ")+
387  szttos(row)+">="+szttos(get_nlines())+", in table::set_row().";
388  O2SCL_ERR(err.c_str(),exc_einval);
389  }
390  for(size_t i=0;i<get_ncolumns() && i<v.size();i++) {
391  alist[i]->second.dat[row]=v[i];
392  }
393  return;
394  }
395 
396  /** \brief Get value from row \c row of column named \c col.
397  \f$ {\cal O}(\log(C)) \f$
398  */
399  double get(std::string scol, size_t row) const {
400  double tmp;
401  aciter it=atree.find(scol);
402  if (it==atree.end()) {
403  O2SCL_ERR((((std::string)"Column '")+scol+
404  "' not found in table::get(string,size_t).").c_str(),
405  exc_enotfound);
406  return 0.0;
407  } else {
408  if (row>=nlines) {
409  std::string err=((std::string)"Row out of range, ")+
410  szttos(row)+">="+szttos(nlines)+", in table::get(string,size_t).";
411  O2SCL_ERR(err.c_str(),exc_einval);
412  }
413 #if !O2SCL_NO_RANGE_CHECK
414  if (row>=it->second.dat.size()) {
415  O2SCL_ERR("Vector size failure in table::get().",
416  exc_esanity);
417  }
418 #endif
419  tmp=it->second.dat[row];
420  }
421  return tmp;
422  }
423 
424  /** \brief Get value from row \c row of column number \c icol.
425  \f$ {\cal O}(1) \f$
426  */
427  double get(size_t icol, size_t row) const {
428  if (icol>=atree.size()) {
429  std::string err=((std::string)"Column out of range, ")+
430  szttos(icol)+">="+szttos(atree.size())+", in table::get(size_t,size_t).";
431  O2SCL_ERR(err.c_str(),exc_einval);
432  }
433  if (row>=nlines) {
434  std::string err=((std::string)"Row out of range, ")+
435  szttos(row)+">="+szttos(nlines)+", in table::get(size_t,size_t).";
436  O2SCL_ERR(err.c_str(),exc_einval);
437  }
438  return alist[icol]->second.dat[row];
439  }
440 
441  /** \brief Return the number of columns
442  */
443  size_t get_ncolumns() const {return atree.size();};
444  //@}
445 
446  // --------------------------------------------------------
447  /** \name Manipulate current and maximum number of rows */
448  //@{
449  /** \brief Return the number of lines
450  */
451  size_t get_nlines() const {return nlines;};
452 
453  /** \brief Set the number of lines
454 
455  This function is stingy about increasing the table memory
456  space and will only increase it enough to fit \c il lines.
457  Using it in succession to slowly increase the number of lines
458  in the table is likely to be inefficient compared to \ref
459  set_nlines_auto() in this case.
460  */
461  void set_nlines(size_t il) {
462 
463  // Try to increase the number of lines
464  if (il>maxlines) {
465  inc_maxlines(il-maxlines);
466  }
467 
468  // Now that maxlines is large enough, set the number of lines
469  nlines=il;
470 
471  // Reset the interpolation object for future interpolations
472  if (intp_set) {
473  intp_set=false;
474  delete si;
475  }
476 
477  return;
478  }
479 
480  /** \brief Return the maximum number of lines before a reallocation
481  is required
482  */
483  size_t get_maxlines() {return maxlines; };
484 
485  /** \brief Returns a copy of the row with value \c val in column
486  \c col. \f$ {\cal O}(R C) \f$
487 
488  This function searches the entire table for the row which has
489  the entry in column \c col which is closest to the value \c
490  val, and copies that row to the vector \c row.
491 
492  If the object \c row previously contains any data, it will be
493  lost.
494 
495  The type <tt>resize_vec_t</tt> must be a type which has
496  <tt>size()</tt> and <tt>resize()</tt> methods.
497  */
498  template<class resize_vec_t>
499  void get_row(std::string scol, double val, resize_vec_t &row) const {
500 
501  int irow=lookup(scol,val);
502  if (irow==exc_enotfound) {
503  O2SCL_ERR((((std::string)"Column '")+scol+"' not found in "+
504  "table::get_row(string,double,vec_t) const.").c_str(),
505  exc_enotfound);
506  return;
507  }
508  get_row(irow,row);
509  return;
510  }
511 
512  /** \brief Returns a copy of row number \c irow. \f$ {\cal O}(C) \f$
513 
514  This function returns a copy of row with index \c irow,
515  where \c irow ranges from 0 to <tt>get_nlines()-1</tt>,
516  inclusive.
517 
518  If the object \c row previously contains any data, it will be
519  lost.
520 
521  The type <tt>resize_vec_t</tt> must be a type which has
522  <tt>size()</tt> and <tt>resize()</tt> methods.
523  */
524  template<class resize_vec_t>
525  void get_row(size_t irow, resize_vec_t &row) const {
526 
527  if (irow+1>nlines) {
528  O2SCL_ERR((((std::string)"Row '")+ szttos(irow)+
529  "' not found in table::get_row(size_t,vec_t).").c_str(),
530  exc_enotfound);
531  return;
532  }
533 
534  int i;
535  aciter it;
536  row.resize(atree.size());
537  for(i=0,it=atree.begin();it!=atree.end();it++,i++) {
538  row[i]=(it->second.dat)[irow];
539  }
540  return;
541  }
542 
543  /** \brief Set the number of lines, increasing the size more
544  agressively
545 
546  This function is like set_nlines(), but doubles the maximum
547  column size if an increase in the maximum size is required
548  instead of simply making enough room for the current number of
549  lines. This function is used internally by \ref set() to
550  ensure that the cost of setting lines in sequence is linear
551  and not quadratic.
552  */
553  void set_nlines_auto(size_t il) {
554 
555  // Try to increase the number of lines
556  if (il>maxlines) {
557  size_t inc=il-maxlines;
558  if (inc<maxlines) inc=maxlines;
559  inc_maxlines(inc);
560  }
561 
562  // Now that maxlines is large enough, set the number of lines
563  nlines=il;
564 
565  // Reset the interpolation object for future interpolations
566  if (intp_set) {
567  intp_set=false;
568  delete si;
569  }
570 
571  return;
572  }
573 
574  /** \brief Manually increase the maximum number of lines
575  */
576  void inc_maxlines(size_t llines) {
577 
578  vec_t temp_col;
579 
580  // For the moment, we assume resizes are destructive, so
581  // we have to copy the data to a temporary and then
582  // copy it back
583  for(aiter it=atree.begin();it!=atree.end();it++) {
584 
585  // Copy data to temporary array
586  temp_col.resize(maxlines+llines);
587  for(size_t j=0;j<maxlines;j++) {
588  temp_col[j]=it->second.dat[j];
589  }
590 
591  // Resize
592  it->second.dat.resize(maxlines+llines);
593 
594  // Copy data back to resized array
595  for(size_t j=0;j<maxlines;j++) {
596  it->second.dat[j]=temp_col[j];
597  }
598 
599  }
600 
601  maxlines+=llines;
602 
603  return;
604  }
605 
606  /** \brief Manually set the maximum number of lines
607 
608  \note This function will call the error handler if
609  the argument <tt>llines</tt> is smaller than the
610  current number of lines in the table.
611  */
612  void set_maxlines(size_t llines) {
613 
614  if (llines==maxlines) return;
615  if (llines<nlines) {
616  O2SCL_ERR2("Cannot set maximum number of lines to be smaller ",
617  "than current size in table::set_maxlines().",
619 
620  }
621 
622  vec_t temp_col;
623 
624  // For the moment, we assume resizes are destructive, so
625  // we have to copy the data to a temporary and then
626  // copy it back
627  for(aiter it=atree.begin();it!=atree.end();it++) {
628 
629  // Copy data to temporary array
630  temp_col.resize(llines);
631  for(size_t j=0;j<nlines;j++) {
632  temp_col[j]=it->second.dat[j];
633  }
634 
635  // Resize
636  it->second.dat.resize(llines);
637 
638  // Copy data back to resized array
639  for(size_t j=0;j<nlines;j++) {
640  it->second.dat[j]=temp_col[j];
641  }
642 
643  }
644 
645  maxlines=llines;
646 
647  return;
648  }
649  //@}
650 
651  // --------------------------------------------------------
652  /** \name Column manipulation */
653  //@{
654  /** \brief Returns a reference to the column named \c col.
655  \f$ {\cal O}(\log(C)) \f$
656  */
657  const vec_t &get_column(std::string scol) const {
658  aciter it=atree.find(scol);
659  if (it==atree.end()) {
660  O2SCL_ERR((((std::string)"Column '")+scol+
661  "' not found in table::get_column() const.").c_str(),
662  exc_enotfound);
663  return empty_col;
664  }
665  return it->second.dat;
666  }
667 
668  /** \brief Returns the column of index \c icol (const
669  version). \f$ {\cal O}(1) \f$
670 
671  Note that several of the methods require reallocation of
672  memory and refereces previously returned by this function will
673  be incorrect.
674 
675  Unlike set(), this function will not automatically result in
676  an increase in the size of the table if the user attempts to
677  set an element beyond the current column range.
678 
679  This function will throw an exception if \c icol is out
680  of range unless <tt>O2SCL_NO_RANGE_CHECK</tt> is defined.
681  */
682  const vec_t &operator[] (size_t icol) const {
683 #if !O2SCL_NO_RANGE_CHECK
684  if (icol>=atree.size()) {
685  O2SCL_ERR((((std::string)"Array index ")+szttos(icol)+
686  " out of bounds"+
687  " in table::operator[size_t] const. Size: "+
688  szttos(atree.size())+
689  " (index should be less than size).").c_str(),exc_eindex);
690  return empty_col;
691  }
692 #endif
693  return (alist[icol]->second.dat);
694  }
695 
696  /** \brief Returns the column named \c scol (const version).
697  \f$ {\cal O}(\log(C)) \f$
698 
699  Note that several of the methods require reallocation of
700  memory and refereces previously returned by this function will
701  be incorrect.
702 
703  Unlike set(), this function will not automatically result in
704  an increase in the size of the table if the user attempts to
705  set an element beyond the current column range.
706 
707  This function will throw an exception if \c icol is out
708  of range unless <tt>O2SCL_NO_RANGE_CHECK</tt> is defined.
709  */
710  const vec_t &operator[](std::string scol) const {
711  aciter it=atree.find(scol);
712 #if !O2SCL_NO_RANGE_CHECK
713  if (it==atree.end()) {
714  O2SCL_ERR((((std::string)"Column '")+scol+"' not found in table::"+
715  "operator[string] const.").c_str(),exc_enotfound);
716  return empty_col;
717  }
718 #endif
719  return (it->second.dat);
720  }
721 
722  /** \brief Add a new column owned by the \table \f$ {\cal O}(\log(C)) \f$
723 
724  \note This function does not set all the column entries to
725  zero in the case that a new column is added to a table which
726  already contains data.
727  */
728  void new_column(std::string head) {
729  if (head.length()==0) {
730  O2SCL_ERR2("Cannot add column with empty name in ",
731  "table::new_column().",exc_einval);
732  }
733  if (is_column(head)==true) {
734  O2SCL_ERR((((std::string)"Column '")+head+
735  "' already present in table::new_column().").c_str(),
736  exc_einval);
737  }
738  for(int i=0;i<((int)head.size());i++) {
739  if (head[i]==' ' || head[i]=='\t' || head[i]=='\n' || head[i]=='\r'
740  || head[i]=='\v' || head[i]=='\f') {
741  O2SCL_ERR((((std::string)"Invalid column name '")+head+
742  "' in table::new_column().").c_str(),
743  exc_einval);
744  }
745  }
746  col s;
747  s.dat.resize(maxlines);
748  s.index=((int)atree.size());
749  atree.insert(make_pair(head,s));
750  aiter it=atree.find(head);
751  alist.push_back(it);
752  return;
753  }
754 
755  /** \brief Add a new column by copying data from another vector
756 
757  This function copies \c sz elements of vector \c v into the
758  table in a new column named \c name. If \c sz is larger than
759  the current number of lines (as given, e.g. in \ref
760  get_nlines() ), then only the first part of the vector \c v is
761  copied, up to the current number of lines.
762 
763  This function calls the error handler if \c sz is zero.
764 
765  The type <tt>vec2_t</tt> can be any type with an
766  <tt>operator[]</tt> method.
767  */
768  template<class vec2_t> int new_column(std::string name,
769  size_t sz, vec2_t &v) {
770 
771  if (sz==0) {
772  O2SCL_ERR2("Sent column of zero size in ",
773  "table::new_column(string,size_t,vec2_t)",
774  exc_einval);
775  }
776 
777  // Create the space
778  int ret=new_column(name);
779  if (ret!=0) return ret;
780 
781  // Copy the data over
782  size_t mxl=sz;
783  if (sz>get_nlines()) mxl=get_nlines();
784  for(size_t i=0;i<mxl;i++) {
785  set(name,i,v[i]);
786  }
787 
788  return 0;
789  }
790 
791  /** \brief Returns the name of column \c col \f$ {\cal O}(1) \f$
792 
793  This will throw if \c icol is larger than or equal to
794  the number of columns.
795  */
796  std::string get_column_name(size_t icol) const {
797  if (icol+1>atree.size()) {
798  O2SCL_ERR((((std::string)"Index '")+o2scl::szttos(icol)+
799  " larger than number of "+
800  "columns in table::get_column_name().").c_str(),
801  exc_enotfound);
802  }
803  return alist[icol]->first;
804  }
805 
806  /** \brief Swap the data in column \c scol with that in vector \c v
807 
808  This requires that the column \c v must have the correct size,
809  that returned by \ref get_maxlines().
810 
811  This function is useful, in part, because if objects of type
812  <tt>vec_t</tt> have <tt>std::move</tt> defined, then the swap
813  doesn't require a full copy.
814  */
815  virtual void swap_column_data(std::string scol, vec_t &v) {
816  aiter its=atree.find(scol);
817  if (its==atree.end()) {
818  O2SCL_ERR((((std::string)"Column '")+scol+
819  " not found in table::swap_column_data().").c_str(),
820  exc_enotfound);
821  return;
822  }
823  if (v.size()!=its->second.dat.size()) {
824  O2SCL_ERR2("Vector sizes not commensurate in ",
825  "table::swap_column_data().",exc_einval);
826  }
827  std::swap(its->second.dat,v);
828  return;
829  }
830 
831  /** \brief Rename column named \c src to \c dest
832  \f$ {\cal O}(C) \f$
833  */
834  virtual void rename_column(std::string src, std::string dest) {
835  aiter its=atree.find(src);
836  if (its==atree.end()) {
837  O2SCL_ERR((((std::string)"Column '")+src+
838  " not found in table::rename_column().").c_str(),
839  exc_enotfound);
840  return;
841  }
842  new_column(dest);
843  aiter itd=atree.find(dest);
844  std::swap(its->second.dat,itd->second.dat);
845  delete_column(src);
846  return;
847  }
848 
849  /** \brief Delete column named \c scol \f$ {\cal O}(C) \f$
850 
851  This is slow because the iterators in \ref alist are mangled
852  and we have to call \ref reset_list() to get them back.
853  */
854  virtual void delete_column(std::string scol) {
855 
856  // Find the tree iterator for the element we want to erase
857  aiter it=atree.find(scol);
858  if (it==atree.end()) {
859  O2SCL_ERR((((std::string)"Column '")+scol+
860  " not found in table::delete_column().").c_str(),
861  exc_enotfound);
862  return;
863  }
864 
865  // Find the corresponding list iterator
866  aviter vit=alist.begin();
867  vit+=it->second.index;
868 
869  // Find the last element in the list and it's corresponding table
870  // entry. Change it's index to the index of the column to be
871  // deleted.
872  alist[alist.size()-1]->second.index=it->second.index;
873 
874  // Erase the elements from the list and the tree
875  atree.erase(it);
876  alist.erase(vit);
877 
878  // Reset the list to reflect the proper iterators
879  reset_list();
880 
881  if ((intp_colx==scol || intp_coly==scol) && intp_set==true) {
882  delete si;
883  intp_set=false;
884  }
885 
886  return;
887  }
888 
889  /** \brief Returns the name of column \c col in sorted order.
890  \f$ {\cal O}(1) \f$
891  */
892  std::string get_sorted_name(size_t icol) const {
893  if (icol+1>atree.size()) {
894  return "";
895  }
896  aciter it=atree.begin();
897  for(size_t i=0;i<icol;i++) it++;
898  return it->first;
899  }
900 
901  /** \brief Initialize all values of column named \c scol to \c val
902  \f$ {\cal O}(R \log(C)) \f$
903 
904  Note that this does not initialize elements beyond nlines so
905  that if the number of rows is increased afterwards, the new
906  rows will have uninitialized values.
907  */
908  void init_column(std::string scol, double val) {
909  /*
910  if (!std::isfinite(val)) {
911  O2SCL_ERR((((std::string)"Value '")+dtos(val)+
912  "' not finite for column '"+
913  scol+"' in table::init_column()").c_str(),exc_einval);
914  return;
915  }
916  */
917  aiter it=atree.find(scol);
918  if (it==atree.end()) {
919  O2SCL_ERR((((std::string)"Column '")+scol+
920  "' not found in table::init_column()").c_str(),
921  exc_enotfound);
922  return;
923  }
924  for(size_t i=0;i<nlines;i++) {
925  it->second.dat[i]=val;
926  }
927  if (intp_set && (scol==intp_colx || scol==intp_coly)) {
928  intp_set=false;
929  delete si;
930  }
931  return;
932  }
933 
934  /** \brief Return true if \c scol is a column in the current \table
935 
936  This function does not call the error handler if the column is
937  not found, but just silently returns false.
938  */
939  bool is_column(std::string scol) const {
940  aciter it=atree.find(scol);
941  if (it==atree.end()) return false;
942  return true;
943  }
944 
945  /** \brief Find the index for column named \c name
946  \f$ {\cal O}(\log(C)) \f$
947 
948  If the column is not present, this function calls the error
949  handler.
950  */
951  size_t lookup_column(std::string lname) const {
952  aciter it=atree.find(lname);
953  if (it==atree.end()) {
954  O2SCL_ERR("Column not found in table::lookup_column().",
955  exc_enotfound);
956  }
957  return it->second.index;
958  }
959 
960  /** \brief Copy data from column named \c src to column
961  named \c dest, creating a new column if necessary
962  \f$ {\cal O}(R \log(C)) \f$
963  */
964  virtual void copy_column(std::string src, std::string dest) {
965  if (!is_column(dest)) new_column(dest);
966  aiter its=atree.find(src);
967  if (its==atree.end()) {
968  O2SCL_ERR((((std::string)"Column '")+src+
969  " not found in table::copy_column().").c_str(),
970  exc_enotfound);
971  return;
972  }
973  aiter itd=atree.find(dest);
974  if (itd==atree.end()) {
975  O2SCL_ERR((((std::string)"Destination column '")+dest+
976  " not found in table::copy_column().").c_str(),
977  exc_esanity);
978  return;
979  }
980  for(size_t i=0;i<nlines;i++) {
981  itd->second.dat[i]=its->second.dat[i];
982  }
983  return;
984  }
985 
986  /** \brief Copy a column to a generic vector object
987 
988  \note It is assumed that the vector type is one that can be
989  resized with <tt>resize()</tt>.
990  */
991  template<class resize_vec_t>
992  void column_to_vector(std::string scol, resize_vec_t &v) const {
993  v.resize(nlines);
994  for(size_t i=0;i<nlines;i++) {
995  v[i]=this->get(scol,i);
996  }
997  return;
998  }
999 
1000  /** \brief Copy to a column from a generic vector object
1001 
1002  The type <tt>vec2_t</tt> can be any type with an
1003  <tt>operator[]</tt> method.
1004  */
1005  template<class vec2_t>
1006  void copy_to_column(vec2_t &v, std::string scol) {
1007  for(size_t i=0;i<nlines;i++) {
1008  this->set(scol,i,v[i]);
1009  }
1010  return;
1011  }
1012 
1013  /** \brief Insert a column from a separate table, interpolating
1014  it into a new column
1015 
1016  Given a pair of columns ( \c src_index, \c src_col ) in a
1017  separate table (\c source), this creates a new column in the
1018  present table named \c src_col which interpolates \c loc_index
1019  into \c src_index. The interpolation objects from the \c
1020  source table will be used. If there is already a column in the
1021  present table named \c src_col, then this will fail.
1022  */
1023  template<class vec2_t>
1025  std::string src_index, std::string src_col,
1026  std::string dest_index, std::string dest_col="") {
1027 
1028  if (dest_col=="") dest_col=src_col;
1029 
1030  // Add the new column
1031  if (!is_column(dest_col)) new_column(dest_col);
1032 
1033  // Fill the new column
1034  for(size_t i=0;i<nlines;i++) {
1035  set(dest_col,i,source.interp(src_index,get(dest_index,i),src_col));
1036  }
1037 
1038  return;
1039  }
1040  //@}
1041 
1042  /** \brief Insert columns from a source table into the new
1043  table by interpolation (or extrapolation)
1044  */
1045  template<class vec2_t>
1046  void insert_table(table<vec2_t> &source, std::string src_index,
1047  bool allow_extrap=true, std::string dest_index="") {
1048 
1049  if (dest_index=="") dest_index=src_index;
1050 
1051  // Find limits to avoid extrapolation if necessary
1052  double min=source.min(src_index);
1053  double max=source.max(src_index);
1054  if (allow_extrap==false) {
1055  if (!std::isfinite(min) || !std::isfinite(max)) {
1056  O2SCL_ERR2("Minimum or maximum of source index not finite ",
1057  "in table::insert_table().",exc_einval);
1058  }
1059  }
1060 
1061  // Create list of columns to interpolate
1062  std::vector<std::string> col_list;
1063  for(size_t i=0;i<source.get_ncolumns();i++) {
1064  std::string col_name=source.get_column_name(i);
1065  if (col_name!=src_index && col_name!=dest_index &&
1066  is_column(col_name)==false) {
1067  col_list.push_back(col_name);
1068  }
1069  }
1070 
1071  // Create new columns and perform interpolation
1072  for(size_t i=0;i<col_list.size();i++) {
1073  new_column(col_list[i]);
1074  for(size_t j=0;j<get_nlines();j++) {
1075  double val=get(dest_index,j);
1076  if (allow_extrap || (val>=min && val<=max)) {
1077  set(col_list[i],j,source.interp(src_index,val,col_list[i]));
1078  }
1079  }
1080  }
1081 
1082  return;
1083  }
1084 
1085  // --------------------------------------------------------
1086  /** \name Row maninpulation and data input */
1087  //@{
1088 
1089  /** \brief Insert a row before row \c n
1090 
1091  Acceptable values for \c n are between 0 and
1092  <tt>get_nlines()</tt> inclusive, with the maximum value
1093  denoting the addition of a row after the last row presently in
1094  the table.
1095  */
1096  void new_row(size_t n) {
1097  if (nlines>=maxlines) inc_maxlines(maxlines);
1098 
1099  nlines++;
1100  for(int i=((int)nlines)-2;i>=((int)n);i--) {
1101  copy_row(i,i+1);
1102  }
1103 
1104  if (intp_set) {
1105  intp_set=false;
1106  delete si;
1107  }
1108 
1109  return;
1110  }
1111 
1112  /** \brief Copy the data in row \c src to row \c dest
1113 
1114  \comment
1115  AWS 4/12/18: No need to throw an exception here since get() and
1116  set() will take care of that already.
1117  \endcomment
1118  */
1119  void copy_row(size_t src, size_t dest) {
1120  for(int i=0;i<((int)atree.size());i++) {
1121  set(i,dest,get(i,src));
1122  }
1123  if (intp_set) {
1124  intp_set=false;
1125  delete si;
1126  }
1127  return;
1128  }
1129 
1130  /** \brief Delete the row with the entry closest to
1131  the value \c val in column \c scol \f$ {\cal O}(R C) \f$
1132  */
1133  void delete_row(std::string scol, double val) {
1134  // If lookup() fails, it will throw an exception,
1135  // so there's no need to double-check it here
1136  size_t irow=lookup(scol,val);
1137  delete_row(irow);
1138  return;
1139  }
1140 
1141  /** \brief Delete the row of index \c irow \f$ {\cal O}(R C) \f$
1142  */
1143  void delete_row(size_t irow) {
1144  if (nlines==0) {
1145  O2SCL_ERR2("No lines in table in ",
1146  "table::delete_row(size_t).",o2scl::exc_einval);
1147  }
1148  if (irow>=nlines) {
1149  std::string str=((std::string)"Cannot delete row ")+
1150  o2scl::szttos(irow)+" since there are only "+
1151  o2scl::szttos(nlines)+" lines in the table in "+
1152  "table::delete_row(size_t).";
1153  O2SCL_ERR(str.c_str(),o2scl::exc_einval);
1154  }
1155  for(aiter it=atree.begin();it!=atree.end();it++) {
1156  // Can't do size_t because we have to compare to nlines-1
1157  for(int i=((int)irow);i<((int)nlines)-1;i++) {
1158  it->second.dat[i]=it->second.dat[i+1];
1159  }
1160  }
1161  nlines--;
1162  if (intp_set==true) {
1163  delete si;
1164  intp_set=false;
1165  }
1166  return;
1167  }
1168 
1169  /** \brief Delete all rows where \c func evaluates to a number greater
1170  than 0.5 \f$ {\cal O}(R C) \f$
1171 
1172  If no rows match the delete condition, this function silently
1173  performs no changes to the table.
1174  */
1175  void delete_rows_func(std::string func) {
1176  size_t new_nlines=0;
1177  for(size_t i=0;i<nlines;i++) {
1178  double val=row_function(func,i);
1179  if (val<0.5) {
1180  // If val<0.5, then the function was evaluated to false and
1181  // we want to keep the row, but if i==new_nlines, then
1182  // we don't need to copy because the row is already in
1183  // the correct place.
1184  if (i!=new_nlines) {
1185  for(aiter it=atree.begin();it!=atree.end();it++) {
1186  it->second.dat[new_nlines]=it->second.dat[i];
1187  }
1188  }
1189  new_nlines++;
1190  }
1191  }
1192  nlines=new_nlines;
1193  if (intp_set==true) {
1194  delete si;
1195  intp_set=false;
1196  }
1197  return;
1198  }
1199 
1200  /** \brief Copy all rows matching a particular condition to
1201  a new table
1202 
1203  This function begins by ensuring that all columns in the current
1204  table are present in \c dest, creating new columns in \c dest if
1205  necessary. It then copies all rows where \c func evaluates to a
1206  number greater than 0.5 to table \c dest by adding rows at
1207  the end of the table.
1208  */
1209  template<class vec2_t>
1210  void copy_rows(std::string func, table<vec2_t> &dest) {
1211 
1212  // Set up columns
1213  for(size_t i=0;i<get_ncolumns();i++) {
1214  std::string cname=get_column_name(i);
1215  if (dest.is_column(cname)==false) {
1216  dest.new_column(cname);
1217  }
1218  }
1219 
1220  size_t new_lines=dest.get_nlines();
1221  for(size_t i=0;i<nlines;i++) {
1222  double val=row_function(func,i);
1223  if (val>0.5) {
1224  dest.set_nlines_auto(new_lines+1);
1225  for(size_t j=0;j<get_ncolumns();j++) {
1226  std::string cname=get_column_name(j);
1227  dest.set(cname,new_lines);
1228  }
1229  new_lines++;
1230  }
1231  }
1232 
1233  return;
1234  }
1235 
1236  /** \brief Delete all rows between \c row_start and \c row_end
1237  \f$ {\cal O}(R C) \f$
1238 
1239  If <tt>row_start</tt> is less or equal to <tt>row_end</tt>,
1240  then all rows beginnning with <tt>row_start</tt> and
1241  ending with <tt>row_end</tt> are deleted (inclusive). If
1242  <tt>row_start</tt> is greater than <tt>row_end</tt>, then
1243  rows from the start of the table until <tt>row_end</tt> are
1244  deleted, as well as all rows from <tt>row_start</tt>
1245  through the end of the table.
1246 
1247  If either <tt>row_start</tt> or <tt>row_end</tt> are beyond the
1248  end of the table (greater than or equal to the value given by
1249  \ref get_nlines() ), an exception is thrown.
1250  */
1251  void delete_rows_ends(size_t row_start, size_t row_end) {
1252  if (row_start>=nlines || row_end>=nlines) {
1253  O2SCL_ERR2("Row specifications beyond end of table in ",
1254  "table::delete_rows_ends(size_t,size_t).",exc_einval);
1255  }
1256  size_t new_nlines=0;
1257  for(size_t i=0;i<nlines;i++) {
1258  if ((row_start<=row_end && (i<row_start || i>row_end)) ||
1259  (row_start>row_end && (i<row_start && i>row_end))) {
1260  for(aiter it=atree.begin();it!=atree.end();it++) {
1261  it->second.dat[new_nlines]=it->second.dat[i];
1262  }
1263  new_nlines++;
1264  }
1265  }
1266  nlines=new_nlines;
1267  if (intp_set==true) {
1268  delete si;
1269  intp_set=false;
1270  }
1271  return;
1272  }
1273 
1274  /** \brief Delete all rows in a specified list
1275 
1276  Given a list of rows in \c row_list, this function deletes all
1277  of the specified rows. If a row beyond the end of the table is
1278  in the list, the error handler is called.
1279 
1280  \note This function will proceed normally if a row is specified
1281  more than once in <tt>row_list</tt>.
1282  */
1283  template<class vec_size_t>
1284  void delete_rows_list(vec_size_t &row_list) {
1285 
1286  // First, check that they're all valid rows
1287  for(size_t j=0;j<row_list.size();j++) {
1288  if (row_list[j]>nlines) {
1289  O2SCL_ERR("Invalid row in table<>::delete_rows_list(vec_size_t &)",
1291  }
1292  }
1293 
1294  // Copy the data over, ensuring rows which are to be
1295  // deleted are skipped
1296  size_t new_nlines=0;
1297  for(size_t i=0;i<nlines;i++) {
1298  bool found=false;
1299  for(size_t j=0;j<row_list.size();j++) {
1300  if (row_list[j]==i) found=true;
1301  }
1302  if (found==false) {
1303  for(aiter it=atree.begin();it!=atree.end();it++) {
1304  it->second.dat[new_nlines]=it->second.dat[i];
1305  }
1306  new_nlines++;
1307  }
1308  }
1309 
1310  // Set the new line number and reset the interpolator
1311  nlines=new_nlines;
1312  if (intp_set==true) {
1313  delete si;
1314  intp_set=false;
1315  }
1316 
1317  return;
1318  }
1319 
1320  /** \brief Exaustively search for groups of rows which match within a
1321  specified tolerance and remove all but one of each group
1322 
1323  This function returns the number of rows deleted.
1324  */
1325  size_t delete_rows_tolerance(double tol_rel=1.0e-12,
1326  double tol_abs=1.0e-20,
1327  int verbose=0) {
1328  std::vector<size_t> list;
1329  for(size_t i=0;i<nlines;i++) {
1330  for(size_t j=i+1;j<nlines;j++) {
1331  bool match=true;
1332  if (i<nlines && j<nlines && j>i) {
1333  for(aiter it=atree.begin();it!=atree.end() && match==true;it++) {
1334  if (fabs(it->second.dat[i])>tol_abs ||
1335  fabs(it->second.dat[j])>tol_abs) {
1336  if (fabs(it->second.dat[i]-it->second.dat[j])/
1337  fabs(it->second.dat[i]+it->second.dat[j])>tol_rel) {
1338  match=false;
1339  }
1340  }
1341  }
1342  }
1343  if (match==true) {
1344  list.push_back(j);
1345  if (verbose>0) {
1346  std::cout << "Match between rows " << i << " and " << j
1347  << std::endl;
1348  if (verbose>1) {
1349  for(size_t k=0;k<get_ncolumns();k++) {
1350  std::cout << k << " " << get(k,i) << " " << get(k,j)
1351  << std::endl;
1352  }
1353  }
1354  }
1355  }
1356  }
1357  }
1358  if (list.size()>0) {
1359  delete_rows_list(list);
1360  } else if (verbose>0) {
1361  std::cout << "No matches found." << std::endl;
1362  }
1363  return list.size();
1364  }
1365 
1366  /** \brief Delete all rows which are identical to
1367  adjacent rows
1368 
1369  This function does silently does nothing if there are
1370  less than 2 rows in the table.
1371  */
1373  if (nlines>=2) {
1374  // Find duplicate rows
1375  std::vector<size_t> row_list;
1376  for(size_t i=0;i<nlines-1;i++) {
1377  bool match=true;
1378  for(aiter it=atree.begin();it!=atree.end() && match==true;it++) {
1379  if (it->second.dat[i+1]!=it->second.dat[i]) match=false;
1380  }
1381  if (match) row_list.push_back(i+1);
1382  }
1383  // Delete duplicates
1384  delete_rows_list(row_list);
1385  }
1386  return;
1387  }
1388 
1389  /** \brief Read a new set of names from \c newheads
1390 
1391  This function reads a set of white-space delimited column
1392  names from the string \c newheads, and creates a new column
1393  for each name which is specified.
1394 
1395  For example
1396  \code
1397  table t;
1398  t.line_of_names("position velocity acceleration");
1399  \endcode
1400  will create three new columns with the names "position",
1401  "velocity", and "acceleration".
1402  */
1403  void line_of_names(std::string newheads) {
1404  int ret=0;
1405  std::string head;
1406 
1407  std::istringstream is(newheads);
1408  while(is >> head) {
1409  new_column(head);
1410  }
1411 
1412  if (ret!=0) {
1413  O2SCL_ERR2("At least one new column failed in ",
1414  "table::line_of_names().",exc_efailed);
1415  }
1416 
1417  return;
1418  }
1419 
1420  /** \brief Read a line of data from the first \c nv entries in
1421  a vector and store as a new row in the table
1422 
1423  The type <tt>vec2_t</tt> can be any type with an
1424  <tt>operator[]</tt> method. Note that this function does not
1425  verify that \c nv is equal to the number of columns, so some of
1426  the columns may be uninitialized in the new row which is
1427  created.
1428 
1429  Similar to <tt>std::vector</tt>'s <tt>push_back()</tt> method,
1430  this function now internally increases the maximum table size
1431  geometrically to help avoid excessive memory rearrangements.
1432  */
1433  template<class vec2_t> void line_of_data(size_t nv, const vec2_t &v) {
1434  if (maxlines==0) inc_maxlines(1);
1435  if (nlines>=maxlines) inc_maxlines(maxlines);
1436 
1437  if (intp_set) {
1438  intp_set=false;
1439  delete si;
1440  }
1441 
1442  if (nlines<maxlines && nv<=(atree.size())) {
1443 
1444  set_nlines_auto(nlines+1);
1445  for(size_t i=0;i<nv;i++) {
1446  (*this).set(i,nlines-1,v[i]);
1447  }
1448 
1449  return;
1450  }
1451 
1452  O2SCL_ERR("Not enough lines or columns in line_of_data().",exc_einval);
1453  return;
1454  }
1455 
1456  /** \brief Read a line of data and store in a new row of the
1457  table
1458 
1459  The type <tt>vec2_t</tt> can be any type with an
1460  <tt>operator[]</tt> method. Note that this function does not
1461  verify that the vector size is equal to the number of columns,
1462  so some of the columns may be uninitialized in the new row which
1463  is created.
1464  */
1465  template<class vec2_t> void line_of_data(const vec2_t &v) {
1466  line_of_data(v.size(),v);
1467  return;
1468  }
1469  //@}
1470 
1471  // --------------------------------------------------------
1472  /** \name Lookup and search methods */
1473  //@{
1474 
1475  /** \brief Look for a value in an ordered column
1476  \f$ {\cal O}(\log(C) \log(R)) \f$
1477 
1478  This uses the function search_vec::ordered_lookup(), which
1479  offers caching and assumes the vector is monotonic. If you
1480  don't have monotonic data, you can still use the
1481  table::lookup() function, which is more general.
1482  */
1483  size_t ordered_lookup(std::string scol, double val) const {
1484  int ret;
1485  if (!std::isfinite(val)) {
1486  O2SCL_ERR((((std::string)"Value '")+dtos(val)+
1487  "' not finite for column '"+
1488  scol+"' in table::ordered_lookup()").c_str(),exc_einval);
1489  return exc_einval;
1490  }
1491  aciter it=atree.find(scol);
1492  if (it==atree.end()) {
1493  O2SCL_ERR((((std::string)"Column '")+scol+
1494  " not found in table::ordered_lookup().").c_str(),
1495  exc_enotfound);
1496  return exc_enotfound;
1497  }
1498 
1499  search_vec<vec_t> se(nlines,it->second.dat);
1500  ret=se.ordered_lookup(val);
1501  return ret;
1502  }
1503 
1504  /** \brief Exhaustively search column \c col for the value \c val
1505  \f$ {\cal O}(R \log(C)) \f$
1506  */
1507  size_t lookup(std::string scol, double val) const {
1508  if (!std::isfinite(val)) {
1509  O2SCL_ERR((((std::string)"Value '")+dtos(val)+
1510  "' not finite for column '"+
1511  scol+"' in table::lookup()").c_str(),exc_einval);
1512  return exc_einval;
1513  }
1514  aciter it=atree.find(scol);
1515  if (it==atree.end()) {
1516  O2SCL_ERR((((std::string)"Column '")+scol+" not found in "+
1517  "table::lookup().").c_str(),exc_enotfound);
1518  return exc_enotfound;
1519 
1520  }
1521 
1522  // Note that we cannot use the vector lookup() method here, because
1523  // the vector size may be larger than the actual table size.
1524 
1525  const vec_t &ov=it->second.dat;
1526  size_t row=0, i=0;
1527 
1528  // Find first finite row
1529  while(!std::isfinite(ov[i]) && i<nlines-1) i++;
1530  if (i==nlines-1) {
1531  O2SCL_ERR2("Entire array not finite in ",
1532  "table::lookup()",exc_einval);
1533  return 0;
1534  }
1535 
1536  // Beginning with that row, look for the closest value
1537  double bdiff=fabs(ov[i]-val);
1538  for(;i<nlines;i++) {
1539  if (std::isfinite(ov[i]) && fabs(ov[i]-val)<bdiff) {
1540  row=i;
1541  bdiff=fabs(ov[i]-val);
1542  }
1543  }
1544 
1545  return row;
1546  }
1547 
1548  /// Search column \c col for the value \c val and return value in \c col2
1549  double lookup_val(std::string scol, double val, std::string scol2) const {
1550  int i, indx=0;
1551  if (!std::isfinite(val)) {
1552  O2SCL_ERR((((std::string)"Value '")+dtos(val)+
1553  "' not finite for column '"+
1554  scol+"' in table::lookup_val()").c_str(),exc_einval);
1555  return exc_einval;
1556  }
1557  aciter it=atree.find(scol);
1558  if (it==atree.end()) {
1559  O2SCL_ERR((((std::string)"Column '")+scol+" not found in "+
1560  "table::lookup().").c_str(),exc_enotfound);
1561  return exc_enotfound;
1562  }
1563  return get(scol2,it->second.dat->lookup(val));
1564  }
1565 
1566  /** \brief Exhaustively search column \c col for the value \c val
1567  \f$ {\cal O}(R \log(C)) \f$
1568  */
1569  size_t lookup(int icol, double val) const {
1570  return lookup(get_column_name(icol),val);
1571  }
1572 
1573  /** \brief Exhaustively search column \c col for many occurences
1574  of \c val \f$ {\cal O}(R \log(C)) \f$
1575  */
1576  size_t mlookup(std::string scol, double val, std::vector<size_t> &results,
1577  double threshold=0.0) const {
1578  size_t i;
1579  if (!std::isfinite(val)) {
1580  O2SCL_ERR((((std::string)"Value '")+dtos(val)+
1581  "' not finite for column '"+
1582  scol+"' in table::mlookup()").c_str(),exc_einval);
1583  return exc_einval;
1584  }
1585  aciter it=atree.find(scol);
1586  if (it==atree.end()) {
1587  O2SCL_ERR((((std::string)"Column '")+scol+" not found in "+
1588  "table::mlookup().").c_str(),exc_enotfound);
1589  return exc_enotfound;
1590  }
1591  if (threshold==0.0) {
1592  for(i=0;i<nlines;i++) {
1593  if (it->second.dat[i]==val) {
1594  results.push_back(i);
1595  }
1596  }
1597  } else {
1598  for(i=0;i<nlines;i++) {
1599  if (fabs(it->second.dat[i]-val)<threshold) {
1600  results.push_back(i);
1601  }
1602  }
1603  }
1604  return results.size();
1605  }
1606  //@}
1607 
1608  // --------------------------------------------------------
1609  /** \name Interpolation, differentiation, integration, max, min */
1610  //@{
1611 
1612  /// Set the base interpolation objects
1613  void set_interp_type(size_t interp_type) {
1614  itype=interp_type;
1615  if (intp_set) {
1616  delete si;
1617  intp_set=false;
1618  }
1619  return;
1620  }
1621 
1622  /** \brief Get the interpolation type
1623  */
1624  size_t get_interp_type() const {
1625  return itype;
1626  }
1627 
1628  /** \brief Interpolate value \c x0 from column named \c sx
1629  into column named \c sy
1630 
1631  This function is \f$ {\cal O}(\log(R) \log(C)) \f$
1632  but can be as bad as \f$ {\cal O}(C \log(R) \f$ if the
1633  relevant columns are not well ordered.
1634  */
1635  double interp(std::string sx, double x0, std::string sy) {
1636  double ret;
1637  aiter itx=atree.find(sx), ity=atree.find(sy);
1638  if (itx==atree.end() || ity==atree.end()) {
1639  O2SCL_ERR((((std::string)"Columns '")+sx+"' or '"+sy+
1640  "' not found in table::interp().").c_str(),
1641  exc_enotfound);
1642  return 0.0;
1643  }
1644  if (!std::isfinite(x0)) {
1645  O2SCL_ERR("x0 not finite in table::interp().",exc_einval);
1646  return exc_einval;
1647  }
1648  if (intp_set==false || sx!=intp_colx || sy!=intp_coly) {
1649  if (intp_set==true) {
1650  delete si;
1651  } else {
1652  intp_set=true;
1653  }
1654  si=new interp_vec<vec_t>(nlines,itx->second.dat,
1655  ity->second.dat,itype);
1656  intp_colx=sx;
1657  intp_coly=sy;
1658  }
1659  ret=si->eval(x0);
1660  return ret;
1661  }
1662 
1663  /** \brief Interpolate value \c x0 from column named \c sx
1664  into column named \c sy (const version)
1665 
1666  This function is \f$ {\cal O}(\log(R) \log(C)) \f$
1667  but can be as bad as \f$ {\cal O}(C \log(R) \f$ if the
1668  relevant columns are not well ordered.
1669  */
1670  double interp_const(std::string sx, double x0, std::string sy) const {
1671  double ret;
1672  aciter itx=atree.find(sx), ity=atree.find(sy);
1673  if (itx==atree.end() || ity==atree.end()) {
1674  O2SCL_ERR((((std::string)"Columns '")+sx+"' or '"+sy+
1675  "' not found in table::interp_const().").c_str(),
1676  exc_enotfound);
1677  return 0.0;
1678  }
1679  if (!std::isfinite(x0)) {
1680  O2SCL_ERR("x0 not finite in table::interp_const().",exc_einval);
1681  return exc_einval;
1682  }
1683  interp_vec<vec_t> sic(nlines,itx->second.dat,ity->second.dat,itype);
1684 
1685  ret=sic.interp(x0);
1686  return ret;
1687  }
1688 
1689  /** \brief Interpolate value \c x0 from column with index
1690  \c ix into column with index \c iy
1691  \f$ {\cal O}(\log(R)) \f$
1692  */
1693  double interp(size_t ix, double x0, size_t iy) {
1694  return interp(get_column_name(ix),x0,get_column_name(iy));
1695  }
1696 
1697  /** \brief Interpolate value \c x0 from column with index \c ix
1698  into column with index \c iy \f$ {\cal O}(\log(R)) \f$
1699  */
1700  double interp_const(size_t ix, double x0, size_t iy) const {
1701  return interp_const(get_column_name(ix),x0,get_column_name(iy));
1702  }
1703 
1704  /** \brief Make a new column named \c yp which is the
1705  derivative \f$ y^{\prime}(x) \f$ formed from columns
1706  named \c x and \c y \f$ {\cal O}(R \log(C)) \f$
1707  */
1708  void deriv(std::string x, std::string y, std::string yp) {
1709  aiter itx, ity, ityp;
1710  new_column(yp);
1711 
1712  itx=atree.find(x);
1713  ity=atree.find(y);
1714  ityp=atree.find(yp);
1715 
1716  if (itx==atree.end() || ity==atree.end() || ityp==atree.end()) {
1717  O2SCL_ERR("Column not found in table::deriv(string,string,string).",
1718  exc_enotfound);
1719  return;
1720  }
1721 
1722  size_t ix=lookup_column(x);
1723  size_t iy=lookup_column(y);
1724  for(int i=0;i<((int)nlines);i++) {
1725  ityp->second.dat[i]=deriv(ix,(itx->second.dat)[i],iy);
1726  }
1727 
1728  return;
1729  }
1730 
1731  /** \brief Compute the first derivative of the function defined
1732  by x-values stored in column named \c sx and y-values stored
1733  in column named \c sy at the value \c x0
1734 
1735  This function is O(log(C)*log(R)) but can be as bad as
1736  O(log(C)*R) if the relevant columns are not well ordered.
1737  */
1738  double deriv(std::string sx, double x0, std::string sy) {
1739  double ret;
1740  aiter itx=atree.find(sx), ity=atree.find(sy);
1741  if (itx==atree.end() || ity==atree.end()) {
1742  O2SCL_ERR((((std::string)"Columns '")+sx+"' or '"+sy+
1743  "' not found in table::deriv(string,double,string).").c_str(),
1744  exc_enotfound);
1745  return 0.0;
1746  }
1747  if (!std::isfinite(x0)) {
1748  O2SCL_ERR("x0 not finite in table::deriv(string,double,string).",
1749  exc_einval);
1750  return exc_einval;
1751  }
1752  if (intp_set==false || sx!=intp_colx || sy!=intp_coly) {
1753  if (intp_set==true) {
1754  delete si;
1755  } else {
1756  intp_set=true;
1757  }
1758  si=new interp_vec<vec_t>
1759  (nlines,itx->second.dat,ity->second.dat,itype);
1760 
1761  intp_colx=sx;
1762  intp_coly=sy;
1763  }
1764  ret=si->deriv(x0);
1765  return ret;
1766  }
1767 
1768  /** \brief Compute the first derivative of the function defined
1769  by x-values stored in column named \c sx and y-values stored
1770  in column named \c sy at the value \c x0 (const version)
1771 
1772  O(log(C)*log(R)) but can be as bad as O(log(C)*R) if
1773  the relevant columns are not well ordered.
1774  */
1775  double deriv_const(std::string sx, double x0, std::string sy) const {
1776  double ret;
1777  aciter itx=atree.find(sx), ity=atree.find(sy);
1778  if (itx==atree.end() || ity==atree.end()) {
1779  O2SCL_ERR((((std::string)"Columns '")+sx+"' or '"+sy+
1780  "' not found in table::deriv_const().").c_str(),
1781  exc_enotfound);
1782  return 0.0;
1783  }
1784  if (!std::isfinite(x0)) {
1785  O2SCL_ERR("x0 not finite in table::deriv_const().",exc_einval);
1786  return exc_einval;
1787  }
1788  interp_vec<vec_t> sic
1789  (nlines,itx->second.dat,ity->second.dat,itype);
1790  ret=sic.deriv(x0);
1791  return ret;
1792  }
1793 
1794  /** \brief Compute the first derivative of the function defined
1795  by x-values stored in column with index \c ix and y-values stored
1796  in column with index \c iy at the value \c x0
1797 
1798  O(log(R)) but can be as bad as O(R) if the relevant columns
1799  are not well ordered.
1800  */
1801  double deriv(size_t ix, double x0, size_t iy) {
1802  return deriv(get_column_name(ix),x0,get_column_name(iy));
1803  }
1804 
1805  /** \brief Compute the first derivative of the function defined
1806  by x-values stored in column with index \c ix and y-values stored
1807  in column with index \c iy at the value \c x0 (const version)
1808 
1809  O(log(R)) but can be as bad as O(R) if
1810  the relevant columns are not well ordered.
1811  */
1812  double deriv_const(size_t ix, double x0, size_t iy) const {
1813  return deriv_const(get_column_name(ix),x0,get_column_name(iy));
1814  }
1815 
1816  /** \brief Create a new column named \c yp which is
1817  equal to the second derivative of the function defined by
1818  x-values stored in column named \c x and y-values
1819  stored in column named \c y, i.e.
1820  \f$ y^{\prime \prime}(x) \f$ - O(log(C)*R).
1821  */
1822  void deriv2(std::string x, std::string y, std::string yp) {
1823  aiter itx, ity, ityp;
1824  new_column(yp);
1825 
1826  itx=atree.find(x);
1827  ity=atree.find(y);
1828  ityp=atree.find(yp);
1829 
1830  if (itx==atree.end() || ity==atree.end() || ityp==atree.end()) {
1831  O2SCL_ERR("Column not found in table::deriv2(string,string,string).",
1832  exc_enotfound);
1833  return;
1834  }
1835 
1836  size_t ix=lookup_column(x);
1837  size_t iy=lookup_column(y);
1838  for(int i=0;i<((int)nlines);i++) {
1839  ityp->second.dat[i]=deriv2(ix,itx->second.dat[i],iy);
1840  }
1841 
1842  return;
1843  }
1844 
1845  /** \brief Compute the second derivative of the function defined
1846  by x-values stored in column named \c sx and y-values stored
1847  in column named \c sy at the value \c x0
1848 
1849  O(log(C)*log(R)) but can be as bad as O(log(C)*R) if
1850  the relevant columns are not well ordered.
1851  */
1852  double deriv2(std::string sx, double x0, std::string sy) {
1853  double ret;
1854  aiter itx=atree.find(sx), ity=atree.find(sy);
1855  if (itx==atree.end() || ity==atree.end()) {
1856  O2SCL_ERR((((std::string)"Columns '")+sx+"' or '"+sy+
1857  "' not found in table::deriv2(string,double,string).").c_str(),
1858  exc_enotfound);
1859  return 0.0;
1860  }
1861  if (!std::isfinite(x0)) {
1862  O2SCL_ERR("x0 not finite in table::deriv2(string,double,string).",
1863  exc_einval);
1864  return exc_einval;
1865  }
1866  if (intp_set==false || sx!=intp_colx || sy!=intp_coly) {
1867  if (intp_set==true) {
1868  delete si;
1869  } else {
1870  intp_set=true;
1871  }
1872  si=new interp_vec<vec_t>
1873  (nlines,itx->second.dat,ity->second.dat,itype);
1874 
1875  intp_colx=sx;
1876  intp_coly=sy;
1877  }
1878  ret=si->deriv2(x0);
1879  return ret;
1880  }
1881 
1882  /** \brief The Compute the second derivative of the function defined
1883  by x-values stored in column named \c sx and y-values stored
1884  in column named \c sy at the value \c x0 (const version)
1885 
1886  O(log(C)*log(R)) but can be as bad as O(log(C)*R) if
1887  the relevant columns are not well ordered.
1888  */
1889  double deriv2_const(std::string sx, double x0, std::string sy) const {
1890  double ret;
1891  aciter itx=atree.find(sx), ity=atree.find(sy);
1892  if (itx==atree.end() || ity==atree.end()) {
1893  O2SCL_ERR((((std::string)"Columns '")+sx+"' or '"+sy+
1894  "' not found in table::deriv2_const().").c_str(),
1895  exc_enotfound);
1896  return 0.0;
1897  }
1898  if (!std::isfinite(x0)) {
1899  O2SCL_ERR("x0 not finite in table::deriv2_const().",exc_einval);
1900  return exc_einval;
1901  }
1902  interp_vec<vec_t> sic
1903  (nlines,itx->second.dat,ity->second.dat,itype);
1904  ret=sic.deriv2(x0);
1905  return ret;
1906  }
1907 
1908  /** \brief Compute the second derivative of the function defined
1909  by x-values stored in column with index \c ix and y-values stored
1910  in column with index \c iy at the value \c x0
1911 
1912  O(log(R)) but can be as bad as O(R) if
1913  the relevant columns are not well ordered.
1914  */
1915  double deriv2(size_t ix, double x0, size_t iy) {
1916  return deriv2(get_column_name(ix),x0,get_column_name(iy));
1917  }
1918 
1919  /** \brief Compute the second derivative of the function defined
1920  by x-values stored in column with index \c ix and y-values stored
1921  in column with index \c iy at the value \c x0 (const version)
1922 
1923  O(log(R)) but can be as bad as O(R) if
1924  the relevant columns are not well ordered.
1925  */
1926  double deriv2_const(size_t ix, double x0, size_t iy) const {
1927  return deriv2_const(get_column_name(ix),x0,get_column_name(iy));
1928  }
1929 
1930  /** \brief Compute the integral of the function defined
1931  by x-values stored in column named \c sx and y-values stored
1932  in column named \c sy between the values \c x1 and \c x2
1933 
1934  O(log(C)*log(R)) but can be as bad as O(log(C)*R) if
1935  the relevant columns are not well ordered.
1936  */
1937  double integ(std::string sx, double x1, double x2, std::string sy) {
1938  double ret;
1939  aiter itx=atree.find(sx), ity=atree.find(sy);
1940  if (itx==atree.end() || ity==atree.end()) {
1941  O2SCL_ERR((((std::string)"Columns '")+sx+"' or '"+sy+
1942  "' not found in table::integ"+
1943  "(string,double,double,string).").c_str(),
1944  exc_enotfound);
1945  return 0.0;
1946  }
1947  if (!std::isfinite(x1) || !std::isfinite(x2)) {
1948  std::string msg=((std::string)"Value x1=")+dtos(x1)+" or x2="+
1949  dtos(x2)+" not finite in table.integ(string,double,double,string).";
1950  O2SCL_ERR(msg.c_str(),exc_einval);
1951  }
1952  if (intp_set==false || sx!=intp_colx || sy!=intp_coly) {
1953  if (intp_set==true) {
1954  delete si;
1955  } else {
1956  intp_set=true;
1957  }
1958  si=new interp_vec<vec_t>
1959  (nlines,itx->second.dat,ity->second.dat,itype);
1960 
1961  intp_colx=sx;
1962  intp_coly=sy;
1963  }
1964  ret=si->integ(x1,x2);
1965  return ret;
1966  }
1967 
1968  /** \brief Compute the integral of the function defined
1969  by x-values stored in column named \c sx and y-values stored
1970  in column named \c sy between the values \c x1 and \c x2
1971  (const version)
1972 
1973  O(log(C)*log(R)) but can be as bad as O(log(C)*R) if
1974  the relevant columns are not well ordered.
1975  */
1976  double integ_const(std::string sx, double x1, double x2,
1977  std::string sy) const {
1978  double ret;
1979  aciter itx=atree.find(sx), ity=atree.find(sy);
1980  if (itx==atree.end() || ity==atree.end()) {
1981  O2SCL_ERR((((std::string)"Columns '")+sx+"' or '"+sy+
1982  "' not found in table::integ_const().").c_str(),
1983  exc_enotfound);
1984  return 0.0;
1985  }
1986  if (!std::isfinite(x1) || !std::isfinite(x2)) {
1987  O2SCL_ERR("x1 or x2 not finite in table::integ_const().",exc_einval);
1988  return exc_einval;
1989  }
1990  interp_vec<vec_t> sic
1991  (nlines,itx->second.dat,ity->second.dat,itype);
1992  ret=sic.integ(x1,x2);
1993  return ret;
1994  }
1995 
1996  /** \brief Compute the integral of the function defined
1997  by x-values stored in column with index \c ix and y-values stored
1998  in column with index \c iy between the values \c x1 and \c x2
1999 
2000  O(log(R)) but can be as bad as O(R) if
2001  the relevant columns are not well ordered.
2002  */
2003  double integ(size_t ix, double x1, double x2, size_t iy) {
2004  return integ(get_column_name(ix),x1,x2,
2005  get_column_name(iy));
2006  }
2007 
2008  /** \brief Compute the integral of the function defined
2009  by x-values stored in column with index \c ix and y-values stored
2010  in column with index \c iy between the values \c x1 and \c x2
2011  (const version)
2012 
2013  O(log(R)) but can be as bad as O(R) if
2014  the relevant columns are not well ordered.
2015  */
2016  double integ_const(size_t ix, double x1, double x2, size_t iy) const {
2017  return integ_const(get_column_name(ix),x1,x2,
2018  get_column_name(iy));
2019  }
2020 
2021  /** \brief Create a new column named \c ynew which is
2022  equal to the integral of the function defined by
2023  x-values stored in column named \c x and y-values
2024  stored in column named \c y
2025 
2026  This function is O(log(R)) but can be as bad as O(R) if the
2027  relevant columns are not well ordered.
2028  */
2029  void integ(std::string x, std::string y, std::string ynew) {
2030  aiter itx, ity, itynew;
2031  new_column(ynew);
2032 
2033  itx=atree.find(x);
2034  ity=atree.find(y);
2035  itynew=atree.find(ynew);
2036 
2037  if (itx==atree.end() || ity==atree.end() || itynew==atree.end()) {
2038  O2SCL_ERR("Column not found in table::integ(string,string,string).",
2039  exc_enotfound);
2040  return;
2041  }
2042 
2043  size_t ix=lookup_column(x);
2044  size_t iy=lookup_column(y);
2045  for(size_t i=0;i<nlines;i++) {
2046  itynew->second.dat[i]=integ(ix,(itx->second.dat)[0],
2047  (itx->second.dat)[i],iy);
2048  }
2049 
2050  return;
2051  }
2052 
2053  /** \brief Return column maximum. Makes no assumptions about
2054  ordering, \f$ {\cal O}(R) \f$
2055  */
2056  double max(std::string scol) const {
2057  double ret=0.0;
2058  int i;
2059  if (is_column(scol)==false) {
2060  O2SCL_ERR((((std::string)"Column '")+scol+
2061  "' not found in table::max().").c_str(),exc_enotfound);
2062  return 0.0;
2063  }
2064  const vec_t &dcol=get_column(scol);
2065  bool setb=false;
2066  for(i=0;i<((int)nlines);i++) {
2067  if (std::isfinite(dcol[i])) {
2068  if (setb==false) {
2069  ret=dcol[i];
2070  setb=true;
2071  } else if (dcol[i]>ret) {
2072  ret=dcol[i];
2073  }
2074  }
2075  }
2076  if (setb==false) {
2077  O2SCL_ERR((((std::string)"No finite values in column '")+scol+
2078  "' in table::max().").c_str(),exc_efailed);
2079  return 0.0;
2080  }
2081  return ret;
2082  }
2083 
2084  /** \brief Return column minimum. Makes no assumptions about
2085  ordering, \f$ {\cal O}(R) \f$
2086  */
2087  double min(std::string scol) const {
2088  double ret=0.0;
2089  int i;
2090  if (is_column(scol)==false) {
2091  O2SCL_ERR((((std::string)"Column '")+scol+
2092  "' not found in table::min().").c_str(),exc_enotfound);
2093  return 0.0;
2094  }
2095  const vec_t &dcol=get_column(scol);
2096  bool setb=false;
2097  for(i=0;i<((int)nlines);i++) {
2098  if (std::isfinite(dcol[i])) {
2099  if (setb==false) {
2100  ret=dcol[i];
2101  setb=true;
2102  } else if (dcol[i]<ret) {
2103  ret=dcol[i];
2104  }
2105  }
2106  }
2107  if (setb==false) {
2108  O2SCL_ERR((((std::string)"No finite values in column '")+scol+
2109  "' in table::min().").c_str(),exc_efailed);
2110  return 0.0;
2111  }
2112  return ret;
2113  }
2114  //@}
2115 
2116  // --------------------------------------------------------
2117  /** \name Subtable method */
2118  //@{
2119 
2120  /** \brief Make a subtable
2121 
2122  Uses the columns specified in \c list from the row \c top
2123  to the row of index \c bottom to generate a new table
2124  which is a copy of part of the original.
2125  */
2126  void subtable(std::string list, size_t top,
2127  size_t bottom, table<vec_t> &tnew) const {
2128 
2129  tnew.clear_all();
2130  int sublines, i;
2131  std::string head;
2132  aciter it;
2133 
2134  if (top>bottom) {
2135  size_t tmp=bottom;
2136  bottom=top;
2137  top=tmp;
2138  }
2139  sublines=bottom-top+1;
2140  if (nlines==0) {
2141  O2SCL_ERR2("Can't make a subtable of an empty table. ",
2142  "Returning 0 in table::subtable().",
2143  exc_einval);
2144  return;
2145  }
2146  if (bottom+1>nlines) {
2147  O2SCL_ERR2("Requested row beyond nlines. Adjusting ",
2148  "and continuing in table::subtable().",exc_einval);
2149  bottom=nlines-1;
2150  }
2151 
2152  std::istringstream is(list);
2153 
2154  tnew.set_nlines(sublines);
2155  while(is >> head) {
2156  it=atree.find(head);
2157  if (it==atree.end()) {
2158  O2SCL_ERR
2159  ((((std::string)"Couldn't find column named ")+head+
2160  " in table::subtable(). Returning 0.").c_str(),
2161  exc_einval);
2162  }
2163  tnew.new_column(head);
2164  vec_t &dcol=tnew.get_column(head);
2165  for(i=0;i<sublines;i++) {
2166  dcol[i]=it->second.dat[i+top];
2167  }
2168  }
2169  if (tnew.get_ncolumns()==0) {
2170  O2SCL_ERR("Subtable has no columns in table::subtable().",
2171  exc_einval);
2172  }
2173  //}
2174  tnew.nlines=sublines;
2175 
2176  return;
2177  }
2178  //@}
2179 
2180  // --------------------------------------------------------
2181  /** \name Clear methods */
2182  //@{
2183 
2184  /** \brief Zero the data entries but keep the column names
2185  and nlines fixed
2186  */
2187  void zero_table() {
2188  aiter it;
2189  for(it=atree.begin();it!=atree.end();it++) {
2190  for(int j=0;j<((int)nlines);j++) {
2191  it->second.dat[j]=0.0;
2192  }
2193  }
2194 
2195  if (intp_set) {
2196  intp_set=false;
2197  delete si;
2198  }
2199 
2200  return;
2201  }
2202 
2203  /** \brief Clear everything
2204  */
2205  virtual void clear() {
2206  clear_table();
2207  clear_constants();
2208  return;
2209  }
2210 
2211  /** \brief Clear the table and the column names (but leave constants)
2212  */
2213  virtual void clear_table() {
2214  atree.clear();
2215  alist.clear();
2216  nlines=0;
2217  if (intp_set==true) {
2218  delete si;
2219  intp_set=false;
2220  }
2221  return;
2222  }
2223 
2224  /** \brief Remove all of the data by setting the number
2225  of lines to zero
2226 
2227  This leaves the column names intact and does not remove
2228  the constants.
2229  */
2230  void clear_data() {
2231  nlines=0;
2232  if (intp_set==true) {
2233  delete si;
2234  intp_set=false;
2235  }
2236  return;
2237  }
2238 
2239  /// CLear all constants
2241  constants.clear();
2242  return;
2243  }
2244  //@}
2245 
2246  // --------------------------------------------------------
2247  /** \name Sorting methods */
2248  //@{
2249 
2250  /** \brief Sort the entire table by the column \c scol
2251 
2252  \note This function works by allocating space for an entirely
2253  new chunk of memory for the data in the table.
2254  */
2255  void sort_table(std::string scol) {
2256 
2257  size_t ncols=get_ncolumns(), nlins=get_nlines();
2258 
2259  // Make a copy of the table
2260  boost::numeric::ublas::matrix<double> data_copy(ncols,nlins);
2261  for(size_t i=0;i<ncols;i++) {
2262  for(size_t j=0;j<nlins;j++) {
2263  data_copy(i,j)=get(i,j);
2264  }
2265  }
2266 
2267  permutation order(nlins);
2268  aiter it=atree.find(scol);
2269  vec_t &data=it->second.dat;
2270  vector_sort_index(nlins,data,order);
2271  for(size_t i=0;i<ncols;i++) {
2272  for(size_t j=0;j<nlins;j++) {
2273  set(i,j,data_copy(i,order[j]));
2274  }
2275  }
2276 
2277  if (intp_set) {
2278  intp_set=false;
2279  delete si;
2280  }
2281 
2282  return;
2283  }
2284 
2285  /** \brief Individually sort the column \c scol
2286  */
2287  void sort_column(std::string scol) {
2288  int i;
2289  aiter it=atree.find(scol);
2290  if (it==atree.end()) {
2291  O2SCL_ERR((((std::string)"Column '")+scol+
2292  " not found in table::sort_column().").c_str(),
2293  exc_enotfound);
2294  return;
2295  }
2296 
2297  vector_sort_double(nlines,it->second.dat);
2298 
2299  if (intp_set && (scol==intp_colx || scol==intp_coly)) {
2300  intp_set=false;
2301  delete si;
2302  }
2303 
2304  return;
2305  }
2306  //@}
2307 
2308  // --------------------------------------------------------
2309  /** \name Summary method */
2310  //@{
2311  /** \brief Output a summary of the information stored
2312 
2313  Outputs the number of constants, the number of columns,
2314  a list of the column names, and the number of lines of
2315  data.
2316  */
2317  virtual void summary(std::ostream *out, size_t ncol=79) const {
2318 
2319  if (constants.size()==1) {
2320  (*out) << "1 constant:" << std::endl;
2321  } else {
2322  (*out) << constants.size() << " constants:" << std::endl;
2323  }
2324  std::map<std::string,double>::const_iterator mit;
2325  for(mit=constants.begin();mit!=constants.end();mit++) {
2326  (*out) << mit->first << " " << mit->second << std::endl;
2327  }
2328 
2329  // Output number of columns and preprend column numbers
2330  size_t nh=get_ncolumns(), nh2;
2331 
2332  if (nh==0) {
2333 
2334  (*out) << "No columns." << std::endl;
2335 
2336  } else {
2337 
2338  if (nh==1) {
2339  (*out) << "1 column: " << std::endl;
2340  } else {
2341  (*out) << nh << " columns: " << std::endl;
2342  }
2343  std::vector<std::string> h(nh);
2344  for(size_t i=0;i<nh;i++) {
2345  h[i]=szttos(i)+". "+get_column_name(i);
2346  }
2347 
2348  std::vector<std::string> h2;
2349  // Convert to string with width 'ncol'
2350  screenify(nh,h,h2,ncol);
2351  nh2=h2.size();
2352 
2353  // Output column names
2354  for(size_t i=0;i<nh2;i++) {
2355  (*out) << h2[i] << std::endl;
2356  }
2357 
2358  }
2359 
2360  if (get_nlines()==0) (*out) << "No lines of data." << std::endl;
2361  else if (get_nlines()==1) (*out) << "One line of data." << std::endl;
2362  (*out) << get_nlines() << " lines of data." << std::endl;
2363 
2364  return;
2365  }
2366  //@}
2367 
2368  /// \name Constant manipulation
2369  //@{
2370  /** \brief Add a constant, or if the constant already exists, change
2371  its value
2372  */
2373  virtual void add_constant(std::string name, double val) {
2374  if (constants.find(name)!=constants.end()) {
2375  constants.find(name)->second=val;
2376  return;
2377  }
2378  constants.insert(make_pair(name,val));
2379  return;
2380  }
2381 
2382  /** \brief Set a constant equal to a value, but don't add it if
2383  not already present
2384 
2385  If \c err_on_notfound is <tt>true</tt> (the default), then
2386  this function throws an exception if a constant with
2387  name \c name is not found. If \c err_on_notfound is
2388  <tt>false</tt>, then if a constant with name \c name
2389  is not found this function just silently returns
2390  \ref o2scl::exc_enotfound.
2391  */
2392  virtual int set_constant(std::string name, double val,
2393  bool err_on_notfound=true) {
2394  if (constants.find(name)!=constants.end()) {
2395  constants.find(name)->second=val;
2396  return 0;
2397  }
2398  if (err_on_notfound) {
2399  std::string err=((std::string)"No constant with name '")+name+
2400  "' in table::set_constant().";
2401  O2SCL_ERR(err.c_str(),exc_enotfound);
2402  }
2403  return exc_enotfound;
2404  }
2405 
2406  /// Test if \c name is a constant
2407  virtual bool is_constant(std::string name) const {
2408  if (constants.find(name)==constants.end()) {
2409  return false;
2410  }
2411  return true;
2412  }
2413 
2414  /// Get a constant
2415  virtual double get_constant(std::string name) const {
2416  if (constants.find(name)==constants.end()) {
2417  std::string err=((std::string)"No constant with name '")+name+
2418  "' in table::get_constant(string).";
2419  O2SCL_ERR(err.c_str(),exc_einval);
2420  }
2421  return constants.find(name)->second;
2422  }
2423 
2424  /// Get the number of constants
2425  virtual size_t get_nconsts() const {
2426  return constants.size();
2427  }
2428 
2429  /// Get a constant by index
2430  virtual void get_constant(size_t ix, std::string &name, double &val) const {
2431  if (ix<constants.size()) {
2432  std::map<std::string,double>::const_iterator cit=constants.begin();
2433  for(size_t i=0;i<ix;i++) cit++;
2434  name=cit->first;
2435  val=cit->second;
2436  return;
2437  }
2438  O2SCL_ERR("Index too large in table::get_constant(size_t,string,double).",
2439  exc_eindex);
2440  return;
2441  }
2442 
2443  /// Remove a constant
2444  virtual void remove_constant(std::string name) {
2445  if (constants.find(name)==constants.end()) {
2446  O2SCL_ERR2("Constant not present in ",
2447  "table::remove_constant().",o2scl::exc_einval);
2448  }
2449  constants.erase(name);
2450  return;
2451  }
2452  //@}
2453 
2454  /// \name Miscellaneous methods
2455  //@{
2456  /// Clear the current table and read from a generic data file
2457  virtual int read_generic(std::istream &fin, int verbose=0) {
2458 
2459  double data;
2460  std::string line;
2461  std::string cname;
2462 
2463  // Read first line and into list
2464  std::vector<std::string> onames, nnames;
2465  getline(fin,line);
2466  std::istringstream is(line);
2467  while (is >> cname) {
2468  onames.push_back(cname);
2469  if (verbose>2) {
2470  std::cout << "Read possible column name: " << cname << std::endl;
2471  }
2472  }
2473 
2474  // Count number of likely numbers in the first row
2475  size_t n_nums=0;
2476  for(size_t i=0;i<onames.size();i++) {
2477  if (is_number(onames[i])) n_nums++;
2478  }
2479 
2480  int irow=0;
2481 
2482  if (n_nums==onames.size()) {
2483 
2484  if (verbose>0) {
2485  std::cout << "First row looks like it contains numerical values."
2486  << std::endl;
2487  std::cout << "Creating generic column names: ";
2488  }
2489 
2490  for(size_t i=0;i<onames.size();i++) {
2491  nnames.push_back(((std::string)"c")+szttos(i+1));
2492  if (verbose>0) std::cout << nnames[i] << " ";
2493 
2494  }
2495  if (verbose>0) std::cout << std::endl;
2496 
2497  // Make columns
2498  for(size_t i=0;i<nnames.size();i++) {
2499  new_column(nnames[i]);
2500  }
2501 
2502  // Add first row of data
2503  set_nlines_auto(irow+1);
2504  for(size_t i=0;i<onames.size();i++) {
2505  set(i,irow,o2scl::stod(onames[i]));
2506  }
2507  irow++;
2508 
2509  } else {
2510 
2511  // Ensure good column names
2512  for(size_t i=0;i<onames.size();i++) {
2513  std::string temps=onames[i];
2514  make_fp_varname(temps);
2515  make_unique_name(temps,nnames);
2516  nnames.push_back(temps);
2517  if (temps!=onames[i] && verbose>0) {
2518  std::cout << "Converted column named '" << onames[i] << "' to '"
2519  << temps << "'." << std::endl;
2520  }
2521  }
2522 
2523  // Make columns
2524  for(size_t i=0;i<nnames.size();i++) {
2525  new_column(nnames[i]);
2526  }
2527 
2528  }
2529 
2530  // Read remaining rows
2531  while ((fin) >> data) {
2532  set_nlines_auto(irow+1);
2533  set(0,irow,data);
2534  for(size_t i=1;i<get_ncolumns();i++) {
2535  (fin) >> data;
2536  set(i,irow,data);
2537  }
2538  irow++;
2539  }
2540 
2541  if (intp_set) {
2542  intp_set=false;
2543  delete si;
2544  }
2545 
2546  return 0;
2547  }
2548 
2549  /** \brief Check if the tree and list are properly synchronized
2550  */
2551  void check_synchro() const {
2552  if (atree.size()!=alist.size()) {
2553  O2SCL_ERR2("Size of table and list do not match in ",
2554  "table::check_synchro().",exc_esanity);
2555  return;
2556  }
2557  for(aciter it=atree.begin();it!=atree.end();it++) {
2558  if (it->second.index!=alist[it->second.index]->second.index) {
2559  O2SCL_ERR((((std::string)"Problem with iterator for entry '")+
2560  it->first+"' in list in table::check_synchro().").c_str(),
2561  exc_esanity);
2562  }
2563  }
2564  for(int i=0;i<((int)atree.size());i++) {
2565  if (alist[i]->second.index!=i) {
2566  O2SCL_ERR((((std::string)"Problem with index of entry ")+
2567  itos(i)+" in list in table::check_synchro().").c_str(),
2568  exc_esanity);
2569  return;
2570  }
2571  }
2572  return;
2573  }
2574 
2575  /** \brief Check if the table object appears to be valid
2576  */
2577  void is_valid() const {
2578  if (maxlines<nlines) {
2579  O2SCL_ERR2("Value of maxlines smaller than nlines ",
2580  "in table::is_valid().",exc_esanity);
2581  }
2582  if (atree.size()!=alist.size()) {
2583  O2SCL_ERR2("Size of table and list do not match in ",
2584  "table::is_valid().",exc_esanity);
2585  return;
2586  }
2587  for(aciter it=atree.begin();it!=atree.end();it++) {
2588  if (it->second.dat.size()!=maxlines) {
2589  O2SCL_ERR2("Vector with size different than maxlines ",
2590  "in table::is_valid().",exc_esanity);
2591  }
2592  if (it->second.index!=alist[it->second.index]->second.index) {
2593  O2SCL_ERR((((std::string)"Problem with iterator for entry '")+
2594  it->first+"' in list in table::is_valid().").c_str(),
2595  exc_esanity);
2596  }
2597  }
2598  for(int i=0;i<((int)atree.size());i++) {
2599  if (alist[i]->second.index!=i) {
2600  O2SCL_ERR((((std::string)"Problem with index of entry ")+
2601  itos(i)+" in list in table::is_valid().").c_str(),
2602  exc_esanity);
2603  return;
2604  }
2605  }
2606  return;
2607  }
2608 
2609  /// Return the type, \c "table".
2610  virtual const char *type() { return "table"; }
2611  //@}
2612 
2613  /** \name Parsing mathematical functions specified as strings
2614  */
2615  //@{
2616  /** \brief Create new columns or recompute from a list of functions
2617 
2618  The list should be a space-delimited list of entries of the
2619  form <tt>name=function</tt> where <tt>name</tt> is the
2620  column name and <tt>function</tt> the function specifing the
2621  values for the column. If a column named <tt>name</tt> is
2622  already present, it is overwritten. Otherwise, a new column
2623  is created.
2624 
2625  \comment
2626  The formulas in \c list may depend on any of the column names
2627  that will be defined later in \c list. For example, for a
2628  table initially containing two columns, \c x and \c y, the
2629  calls
2630  \code
2631  function_columns("a=2*z z=x+y");
2632  \endcode
2633  \code
2634  function_columns("z=x+y a=2*z");
2635  \endcode
2636  both work.
2637  Circular dependencies do not work, for example
2638  \code
2639  function_columns("a=2*z z=a*3");
2640  \endcode
2641  will cause the error handler to be thrown.
2642  \endcomment
2643  */
2644  void functions_columns(std::string list) {
2645 
2646  // Separate the list into names and functions
2647  std::vector<std::string> funcs, names;
2648  {
2649  std::string stemp;
2650  std::istringstream is(list);
2651  while(is >> stemp) funcs.push_back(stemp);
2652  for(size_t i=0;i<(funcs.size());i++) {
2653  names.push_back(funcs[i].substr(0,funcs[i].find("=")));
2654  funcs[i]=funcs[i].substr(funcs[i].find("=")+1,
2655  funcs[i].length()-funcs[i].find("=")-1);
2656  if (names[i].length()==0 || funcs[i].length()==0) {
2657  O2SCL_ERR2("Name or function blank in ",
2658  "table::functions_columns().",exc_einval);
2659  }
2660  }
2661  }
2662 
2663  std::map<std::string,double> vars;
2664  std::map<std::string,double>::const_iterator mit;
2665  for(mit=constants.begin();mit!=constants.end();mit++) {
2666  vars[mit->first]=mit->second;
2667  }
2668 
2669  std::vector<calculator> calcs(funcs.size());
2670  std::vector<vec_t> newcols(funcs.size());
2671 
2672  for(size_t j=0;j<funcs.size();j++) {
2673  calcs[j].compile(funcs[j].c_str(),&vars);
2674  newcols[j].resize(maxlines);
2675  }
2676 
2677  // Calculate all of the columns in the newcols list:
2678  for(size_t i=0;i<nlines;i++) {
2679 
2680  // Record the values of the variables for this line:
2681  for(size_t j=0;j<atree.size();j++) {
2682  vars[get_column_name(j)]=(*this)[j][i];
2683  }
2684 
2685  // Evaluate the new columns
2686  for(size_t j=0;j<funcs.size();j++) {
2687  newcols[j][i]=calcs[j].eval(&vars);
2688  }
2689  }
2690 
2691  for(size_t j=0;j<funcs.size();j++) {
2692  if (!is_column(names[j])) {
2693  new_column(names[j]);
2694  }
2695  swap_column_data(names[j],newcols[j]);
2696  }
2697 
2698  return;
2699  }
2700 
2701  /** \brief Make a column from the function specified in
2702  <tt>function</tt> and add it to the table.
2703 
2704  If a column named \c scol already exists, the data already
2705  present is overwritten with the result. Otherwise, a new
2706  column is created and filled with the result.
2707  */
2708  void function_column(std::string function, std::string scol) {
2709  int ret, i, j;
2710  std::string vlist;
2711  aiter it;
2712 
2713  // Create new column if necessary
2714  if (!is_column(scol)) {
2715  new_column(scol);
2716  }
2717 
2718  // Find vector reference
2719  aiter it2=atree.find(scol);
2720  vec_t &colp=it2->second.dat;
2721 
2722  // Fill vector with result of function
2723  function_vector(function,colp);
2724 
2725  return;
2726  }
2727 
2728  /** \brief Compute a column from a function specified
2729  in a string
2730 
2731  The type \c resize_vec_t must have <tt>resize()</tt> and
2732  <tt>size()</tt> methods. If \c vec does not have enough space to
2733  hold the number of entries given by \ref get_nlines(), it is
2734  resized.
2735 
2736  \comment
2737  This function must return an int rather than void because
2738  of the presence of the 'throw_on_err' mechanism
2739  \endcomment
2740  */
2741  template<class resize_vec_t>
2742  int function_vector(std::string function, resize_vec_t &vec,
2743  bool throw_on_err=true) {
2744 
2745  // Parse function
2746  calculator calc;
2747  std::map<std::string,double> vars;
2748  std::map<std::string,double>::const_iterator mit;
2749  for(mit=constants.begin();mit!=constants.end();mit++) {
2750  vars[mit->first]=mit->second;
2751  }
2752  calc.compile(function.c_str(),&vars);
2753 
2754  // Resize vector if necessary
2755  if (vec.size()<nlines) vec.resize(nlines);
2756 
2757  // Create space for column values
2758  std::vector<double> vals(atree.size());
2759 
2760  // Create column from function
2761  for(size_t j=0;j<nlines;j++) {
2762  for(aciter it=atree.begin();it!=atree.end();it++) {
2763  vars[it->first]=it->second.dat[j];
2764  }
2765  vec[j]=calc.eval(&vars);
2766  }
2767 
2768  return 0;
2769  }
2770 
2771  /** \brief Compute a value by applying a function to a row
2772  */
2773  double row_function(std::string function, size_t row) const {
2774 
2775  // Parse function
2776  calculator calc;
2777  std::map<std::string,double> vars;
2778  std::map<std::string,double>::const_iterator mit;
2779  for(mit=constants.begin();mit!=constants.end();mit++) {
2780  vars[mit->first]=mit->second;
2781  }
2782  calc.compile(function.c_str(),&vars);
2783 
2784  for(aciter it=atree.begin();it!=atree.end();it++) {
2785  vars[it->first]=it->second.dat[row];
2786  }
2787 
2788  double dret=calc.eval(&vars);
2789  return dret;
2790  }
2791 
2792  /** \brief Find a row which maximizes a function
2793  */
2794  size_t function_find_row(std::string function) const {
2795 
2796  // Parse function
2797  calculator calc;
2798  std::map<std::string,double> vars;
2799  std::map<std::string,double>::const_iterator mit;
2800  for(mit=constants.begin();mit!=constants.end();mit++) {
2801  vars[mit->first]=mit->second;
2802  }
2803  calc.compile(function.c_str(),&vars);
2804 
2805  double best_val=0.0;
2806  size_t best_row=0;
2807  for(size_t row=0;row<nlines-1;row++) {
2808  for(aciter it=atree.begin();it!=atree.end();it++) {
2809  vars[it->first]=it->second.dat[row];
2810  }
2811  double dtemp=calc.eval(&vars);
2812  if (row==0) {
2813  best_val=dtemp;
2814  } else {
2815  if (dtemp>best_val) {
2816  best_val=dtemp;
2817  best_row=row;
2818  }
2819  }
2820  }
2821 
2822  return best_row;
2823  }
2824  //@}
2825 
2826  // ---------
2827  // Allow HDF I/O functions to access table data
2828  friend void o2scl_hdf::hdf_output
2829  (o2scl_hdf::hdf_file &hf, table<> &t, std::string name);
2830 
2831  template<class vecf_t> friend void o2scl_hdf::hdf_input
2832  (o2scl_hdf::hdf_file &hf, table<vecf_t> &t, std::string name);
2833 
2834  friend void o2scl_hdf::hdf_output_data
2835  (o2scl_hdf::hdf_file &hf, table<> &t);
2836 
2837  template<class vecf_t> friend void o2scl_hdf::hdf_input_data
2839 
2840  // ---------
2841 
2842 #ifndef DOXYGEN_INTERNAL
2843 
2844  protected:
2845 
2846  /** \brief Set the elements of alist with the appropriate
2847  iterators from atree. \f$ {\cal O}(C) \f$
2848 
2849  Generally, the end-user shouldn't need this method. It is
2850  only used in delete_column() to rearrange the list when
2851  a column is deleted from the tree.
2852  */
2853  void reset_list() {
2854  aiter it;
2855  for(it=atree.begin();it!=atree.end();it++) {
2856  alist[it->second.index]=it;
2857  }
2858  return;
2859  }
2860 
2861  /** \brief Ensure a variable name does not match a function or contain
2862  non-alphanumeric characters
2863  */
2864  void make_fp_varname(std::string &s) {
2865  if (s=="abs" || s=="acos" || s=="acosh" || s=="asin" ||
2866  s=="asinh" || s=="atan" || s=="atan2" || s=="atanh" ||
2867  s=="ceil" || s=="cos" || s=="cosh" || s=="cot" || s=="csc" ||
2868  s=="eval" || s=="exp" || s=="floor" || s=="if" || s=="int" ||
2869  s=="log" || s=="log10" || s=="max" || s=="min" || s=="sec" ||
2870  s=="sin" || s=="sinh" || s=="sqrt" || s=="tan" || s=="tanh") {
2871  s=((std::string)"v_")+s;
2872  } else if (s[0]>='0' && s[0]<='9') {
2873  s=((std::string)"v_")+s;
2874  }
2875 
2876  for(size_t i=0;i<s.length();i++) {
2877  if (!isalpha(s[i]) && !isdigit(s[i]) && s[i]!='_') s[i]='_';
2878  }
2879 
2880  return;
2881  }
2882 
2883  /// Make sure a name is unique
2884  void make_unique_name(std::string &colx, std::vector<std::string> &cnames) {
2885  bool done;
2886 
2887  do {
2888  done=true;
2889  for(size_t i=0;i<cnames.size();i++) {
2890  if (colx==cnames[i]) {
2891  done=false;
2892  i=cnames.size();
2893  }
2894  }
2895  if (done==false) {
2896  colx+='_';
2897  }
2898  } while (done==false);
2899 
2900  return;
2901  }
2902 
2903  /** \brief The list of constants
2904  */
2905  std::map<std::string,double> constants;
2906 
2907  /** \brief Column structure for \ref table [protected]
2908 
2909  This struct is used internally by \ref table to organize the
2910  columns and need not be instantiated by the casual end-user.
2911  */
2912  class col {
2913  public:
2914  /// Pointer to column
2915  vec_t dat;
2916  /// Column index
2917  int index;
2918  col() {
2919  }
2920  /** \brief Copy constructor
2921  */
2922  col(const col &c) {
2923  dat=c.dat;
2924  index=c.index;
2925  }
2926  /** \brief Copy constructor for assignment operator
2927  */
2928  col &operator=(const col &c) {
2929  if (this!=&c) {
2930  dat=c.dat;
2931  index=c.index;
2932  }
2933  return *this;
2934  }
2935  };
2936 
2937  /// \name Iterator types
2938  //@{
2939  /// Map iterator type
2940  typedef typename std::map<std::string,col,
2941  std::greater<std::string> >::iterator aiter;
2942  /// Const map iterator type
2943  typedef typename std::map<std::string,col,
2944  std::greater<std::string> >::const_iterator
2946  /// Vector iterator type
2947  typedef typename std::vector<aiter>::iterator aviter;
2948  //@}
2949 
2950  /// \name Actual data
2951  //@{
2952  /// The size of allocated memory
2953  size_t maxlines;
2954  /// The size of presently used memory
2955  size_t nlines;
2956  /// The tree of columns
2957  std::map<std::string,col,std::greater<std::string> > atree;
2958  /// The list of tree iterators
2959  std::vector<aiter> alist;
2960  //@}
2961 
2962  /// \name Column manipulation methods
2963  //@{
2964  /// Return the iterator for a column
2965  aiter get_iterator(std::string lname) {
2966  aiter it=atree.find(lname);
2967  if (it==atree.end()) {
2968  O2SCL_ERR((((std::string)"Column '")+lname+
2969  " not found in table::get_iterator().").c_str(),
2970  exc_enotfound);
2971  }
2972  return it;
2973  }
2974  /// Return the column structure for a column
2975  col *get_col_struct(std::string lname) {
2976  aiter it=atree.find(lname);
2977  if (it==atree.end()) {
2978  O2SCL_ERR((((std::string)"Column '")+lname+
2979  " not found in table::get_col_struct().").c_str(),
2980  exc_enotfound);
2981  return 0;
2982  }
2983  return &(it->second);
2984  }
2985  /// Return the beginning of the column tree
2986  aiter begin() { return atree.begin(); }
2987  /// Return the end of the column tree
2988  aiter end() { return atree.end(); }
2989  //@}
2990 
2991  /// An empty vector for get_column()
2992  vec_t empty_col;
2993 
2994  /// \name Interpolation
2995  //@{
2996  /// True if the interpolation object is up-to-date
2997  bool intp_set;
2998 
2999  /// Current interpolation type
3000  size_t itype;
3001 
3002  /// Interpolation object
3004 
3005  /// The last x-column interpolated
3006  std::string intp_colx;
3007 
3008  /// The last y-column interpolated
3009  std::string intp_coly;
3010  //@}
3011 
3012 #endif
3013 
3014  };
3015 
3016  /** \brief View a o2scl::table object as a matrix
3017 
3018  \note This stores a pointer to the table and the user must ensure
3019  that the pointer is valid with the matrix view is accessed.
3020  */
3021  template<class vec_t=std::vector<double> >
3023 
3024  protected:
3025 
3026  /// The number of columns
3027  size_t nc;
3028  /// Pointers to each column
3029  std::vector<const vec_t *> col_ptrs;
3030  /// Pointer to the table
3032 
3033  public:
3034 
3035  /** \brief Create a matrix view object from the specified
3036  table and list of columns
3037  */
3039  nc=0;
3040  tp=0;
3041  }
3042 
3043  /** \brief Create a matrix view object from the specified
3044  table and list of columns
3045  */
3047  std::vector<std::string> cols) {
3048  set(t,cols);
3049  }
3050 
3051  /** \brief Create a matrix view object from the specified
3052  table and list of columns
3053  */
3054  void set(o2scl::table<vec_t> &t,
3055  std::vector<std::string> cols) {
3056  nc=cols.size();
3057  col_ptrs.resize(nc);
3058  for(size_t i=0;i<nc;i++) {
3059  col_ptrs[i]=&t[cols[i]];
3060  }
3061  tp=&t;
3062  }
3063 
3064  /** \brief Return the number of rows
3065  */
3066  size_t size1() {
3067  if (nc!=0) {
3068  return tp->get_nlines();
3069  }
3070  return 0;
3071  }
3072 
3073  /** \brief Return the number of columns
3074  */
3075  size_t size2() {
3076  return nc;
3077  }
3078 
3079  /** \brief Return a reference to the element at row \c row
3080  and column \c col
3081  */
3082  const double &operator()(size_t row, size_t col) const {
3083  if (row>=tp->get_nlines()) {
3084  O2SCL_ERR("Row exceeds max in matrix_view_table::operator().",
3086  }
3087  if (col>=nc) {
3088  O2SCL_ERR("Column exceeds max in matrix_view_table::operator().",
3090  }
3091  const vec_t *cp=col_ptrs[col];
3092  return (*cp)[row];
3093  }
3094 
3095  };
3096 
3097 #ifndef DOXYGEN_NO_O2NS
3098 }
3099 #endif
3100 
3101 #endif
size_t mlookup(std::string scol, double val, std::vector< size_t > &results, double threshold=0.0) const
Exhaustively search column col for many occurences of val .
Definition: table.h:1576
virtual void delete_column(std::string scol)
Delete column named scol .
Definition: table.h:854
size_t nlines
The size of presently used memory.
Definition: table.h:2955
aiter begin()
Return the beginning of the column tree.
Definition: table.h:2986
void deriv(std::string x, std::string y, std::string yp)
Make a new column named yp which is the derivative formed from columns named x and y ...
Definition: table.h:1708
double max(std::string scol) const
Return column maximum. Makes no assumptions about ordering, .
Definition: table.h:2056
size_t size2()
Return the number of columns.
Definition: table.h:3075
const vec_t & operator[](std::string scol) const
Returns the column named scol (const version). .
Definition: table.h:710
void line_of_data(const vec2_t &v)
Read a line of data and store in a new row of the table.
Definition: table.h:1465
void copy_to_column(vec2_t &v, std::string scol)
Copy to a column from a generic vector object.
Definition: table.h:1006
The main O<span style=&#39;position: relative; top: 0.3em; font-size: 0.8em&#39;>2</span>scl O$_2$scl names...
Definition: anneal.h:42
void is_valid() const
Check if the table object appears to be valid.
Definition: table.h:2577
std::string intp_coly
The last y-column interpolated.
Definition: table.h:3009
size_t get_nlines() const
Return the number of lines.
Definition: table.h:451
double integ(size_t ix, double x1, double x2, size_t iy)
Compute the integral of the function defined by x-values stored in column with index ix and y-values ...
Definition: table.h:2003
interp_vec< vec_t > * si
Interpolation object.
Definition: table.h:3003
double min(std::string scol) const
Return column minimum. Makes no assumptions about ordering, .
Definition: table.h:2087
double deriv(std::string sx, double x0, std::string sy)
Compute the first derivative of the function defined by x-values stored in column named sx and y-valu...
Definition: table.h:1738
virtual void clear()
Clear everything.
Definition: table.h:2205
double integ_const(size_t ix, double x1, double x2, size_t iy) const
Compute the integral of the function defined by x-values stored in column with index ix and y-values ...
Definition: table.h:2016
void hdf_input_data(hdf_file &hf, o2scl::table< vec_t > &t)
Internal function for inputting a o2scl::table object.
Definition: hdf_io.h:184
void compile(const char *expr, std::map< std::string, double > *vars=0, bool debug=false, std::map< std::string, int > opPrec=opPrecedence)
Compile expression expr using variables specified in vars.
void copy_rows(std::string func, table< vec2_t > &dest)
Copy all rows matching a particular condition to a new table.
Definition: table.h:1210
virtual double deriv2(const double x0) const
Give the value of the second derivative .
Definition: interp.h:1949
void subtable(std::string list, size_t top, size_t bottom, table< vec_t > &tnew) const
Make a subtable.
Definition: table.h:2126
void zero_table()
Zero the data entries but keep the column names and nlines fixed.
Definition: table.h:2187
Data table table class.
Definition: table.h:49
void set_nlines(size_t il)
Set the number of lines.
Definition: table.h:461
void functions_columns(std::string list)
Create new columns or recompute from a list of functions.
Definition: table.h:2644
void new_row(size_t n)
Insert a row before row n.
Definition: table.h:1096
sanity check failed - shouldn&#39;t happen
Definition: err_hnd.h:65
int function_vector(std::string function, resize_vec_t &vec, bool throw_on_err=true)
Compute a column from a function specified in a string.
Definition: table.h:2742
aiter get_iterator(std::string lname)
Return the iterator for a column.
Definition: table.h:2965
double deriv_const(std::string sx, double x0, std::string sy) const
Compute the first derivative of the function defined by x-values stored in column named sx and y-valu...
Definition: table.h:1775
invalid argument supplied by user
Definition: err_hnd.h:59
A simple matrix view object.
Definition: vector.h:2569
matrix_view_table(o2scl::table< vec_t > &t, std::vector< std::string > cols)
Create a matrix view object from the specified table and list of columns.
Definition: table.h:3046
void deriv2(std::string x, std::string y, std::string yp)
Create a new column named yp which is equal to the second derivative of the function defined by x-val...
Definition: table.h:1822
virtual int set_constant(std::string name, double val, bool err_on_notfound=true)
Set a constant equal to a value, but don&#39;t add it if not already present.
Definition: table.h:2392
void set_nlines_auto(size_t il)
Set the number of lines, increasing the size more agressively.
Definition: table.h:553
double deriv(size_t ix, double x0, size_t iy)
Compute the first derivative of the function defined by x-values stored in column with index ix and y...
Definition: table.h:1801
std::string intp_colx
The last x-column interpolated.
Definition: table.h:3006
virtual void remove_constant(std::string name)
Remove a constant.
Definition: table.h:2444
double integ_const(std::string sx, double x1, double x2, std::string sy) const
Compute the integral of the function defined by x-values stored in column named sx and y-values store...
Definition: table.h:1976
A class for representing permutations.
Definition: permutation.h:70
virtual ~table()
Table destructor.
Definition: table.h:199
void make_fp_varname(std::string &s)
Ensure a variable name does not match a function or contain non-alphanumeric characters.
Definition: table.h:2864
void delete_idadj_rows()
Delete all rows which are identical to adjacent rows.
Definition: table.h:1372
double interp_const(size_t ix, double x0, size_t iy) const
Interpolate value x0 from column with index ix into column with index iy .
Definition: table.h:1700
virtual double deriv(const double x0) const
Give the value of the derivative .
Definition: interp.h:1938
int new_column(std::string name, size_t sz, vec2_t &v)
Add a new column by copying data from another vector.
Definition: table.h:768
virtual size_t get_nconsts() const
Get the number of constants.
Definition: table.h:2425
table & operator=(const table &t)
Copy constructor.
Definition: table.h:248
double interp_const(std::string sx, double x0, std::string sy) const
Interpolate value x0 from column named sx into column named sy (const version)
Definition: table.h:1670
std::map< std::string, col, std::greater< std::string > >::const_iterator aciter
Const map iterator type.
Definition: table.h:2945
void check_synchro() const
Check if the tree and list are properly synchronized.
Definition: table.h:2551
Generic "not found" result.
Definition: err_hnd.h:117
void insert_table(table< vec2_t > &source, std::string src_index, bool allow_extrap=true, std::string dest_index="")
Insert columns from a source table into the new table by interpolation (or extrapolation) ...
Definition: table.h:1046
vec_t empty_col
An empty vector for get_column()
Definition: table.h:2992
generic failure
Definition: err_hnd.h:61
std::vector< aiter > alist
The list of tree iterators.
Definition: table.h:2959
const vec_t & get_column(std::string scol) const
Returns a reference to the column named col. .
Definition: table.h:657
size_t get_interp_type() const
Get the interpolation type.
Definition: table.h:1624
double integ(std::string sx, double x1, double x2, std::string sy)
Compute the integral of the function defined by x-values stored in column named sx and y-values store...
Definition: table.h:1937
virtual double get_constant(std::string name) const
Get a constant.
Definition: table.h:2415
virtual void clear_table()
Clear the table and the column names (but leave constants)
Definition: table.h:2213
void clear_data()
Remove all of the data by setting the number of lines to zero.
Definition: table.h:2230
void reset_list()
Set the elements of alist with the appropriate iterators from atree. .
Definition: table.h:2853
std::map< std::string, double > constants
The list of constants.
Definition: table.h:2905
void vector_sort_index(size_t n, const vec_t &data, vec_size_t &order)
Create a permutation which sorts the first n elements of a vector (in increasing order) ...
Definition: vector.h:803
size_t get_maxlines()
Return the maximum number of lines before a reallocation is required.
Definition: table.h:483
View a o2scl::table object as a matrix.
Definition: table.h:3022
Cubic spline for natural boundary conditions.
Definition: interp.h:73
double interp(std::string sx, double x0, std::string sy)
Interpolate value x0 from column named sx into column named sy.
Definition: table.h:1635
o2scl::table< vec_t > * tp
Pointer to the table.
Definition: table.h:3031
size_t maxlines
The size of allocated memory.
Definition: table.h:2953
void sort_column(std::string scol)
Individually sort the column scol.
Definition: table.h:2287
double lookup_val(std::string scol, double val, std::string scol2) const
Search column col for the value val and return value in col2.
Definition: table.h:1549
void line_of_names(std::string newheads)
Read a new set of names from newheads.
Definition: table.h:1403
void init_column(std::string scol, double val)
Initialize all values of column named scol to val .
Definition: table.h:908
#define O2SCL_ERR2(d, d2, n)
Set an error, two-string version.
Definition: err_hnd.h:281
Column structure for table [protected].
Definition: table.h:2912
The O<span style=&#39;position: relative; top: 0.3em; font-size: 0.8em&#39;>2</span>scl O$_2$scl namespace ...
Definition: table.h:53
std::string dtos(double x, int prec=6, bool auto_prec=false)
Convert a double to a string.
double deriv2(std::string sx, double x0, std::string sy)
Compute the second derivative of the function defined by x-values stored in column named sx and y-val...
Definition: table.h:1852
size_t ordered_lookup(std::string scol, double val) const
Look for a value in an ordered column .
Definition: table.h:1483
virtual double integ(const double x1, const double x2) const
Give the value of the integral .
Definition: interp.h:1958
virtual void copy_column(std::string src, std::string dest)
Copy data from column named src to column named dest, creating a new column if necessary ...
Definition: table.h:964
col * get_col_struct(std::string lname)
Return the column structure for a column.
Definition: table.h:2975
double interp(size_t ix, double x0, size_t iy)
Interpolate value x0 from column with index ix into column with index iy .
Definition: table.h:1693
void get_row(std::string scol, double val, resize_vec_t &row) const
Returns a copy of the row with value val in column col. .
Definition: table.h:499
table(const table &t)
Copy constructor.
Definition: table.h:206
virtual const char * type()
Return the type, "table".
Definition: table.h:2610
void screenify(size_t nin, const string_arr_t &in_cols, std::vector< std::string > &out_cols, size_t max_size=80)
Reformat the columns for output of width size.
Definition: misc.h:127
double eval(std::map< std::string, double > *vars=0)
Evalate the previously compiled expression using variables specified in vars.
#define O2SCL_ERR(d, n)
Set an error with message d and code n.
Definition: err_hnd.h:273
void make_unique_name(std::string &colx, std::vector< std::string > &cnames)
Make sure a name is unique.
Definition: table.h:2884
std::vector< const vec_t * > col_ptrs
Pointers to each column.
Definition: table.h:3029
const double & operator()(size_t row, size_t col) const
Return a reference to the element at row row and column col.
Definition: table.h:3082
void line_of_data(size_t nv, const vec2_t &v)
Read a line of data from the first nv entries in a vector and store as a new row in the table...
Definition: table.h:1433
col & operator=(const col &c)
Copy constructor for assignment operator.
Definition: table.h:2928
size_t delete_rows_tolerance(double tol_rel=1.0e-12, double tol_abs=1.0e-20, int verbose=0)
Exaustively search for groups of rows which match within a specified tolerance and remove all but one...
Definition: table.h:1325
void copy_row(size_t src, size_t dest)
Copy the data in row src to row dest.
Definition: table.h:1119
virtual void add_constant(std::string name, double val)
Add a constant, or if the constant already exists, change its value.
Definition: table.h:2373
void delete_row(std::string scol, double val)
Delete the row with the entry closest to the value val in column scol .
Definition: table.h:1133
void set_interp_type(size_t interp_type)
Set the base interpolation objects.
Definition: table.h:1613
bool is_number(std::string s)
Return true if the string s is likely a integral or floating point number.
size_t ordered_lookup(const double x0) const
Find the index of x0 in the ordered array x.
Definition: search_vec.h:242
Evaluate a mathematical expression in a string.
double deriv2(size_t ix, double x0, size_t iy)
Compute the second derivative of the function defined by x-values stored in column with index ix and ...
Definition: table.h:1915
double deriv2_const(size_t ix, double x0, size_t iy) const
Compute the second derivative of the function defined by x-values stored in column with index ix and ...
Definition: table.h:1926
void delete_row(size_t irow)
Delete the row of index irow .
Definition: table.h:1143
size_t get_ncolumns() const
Return the number of columns.
Definition: table.h:443
double stod(std::string s)
Convert a string to a double.
virtual bool is_constant(std::string name) const
Test if name is a constant.
Definition: table.h:2407
void new_column(std::string head)
Add a new column owned by the table table .
Definition: table.h:728
virtual void summary(std::ostream *out, size_t ncol=79) const
Output a summary of the information stored.
Definition: table.h:2317
aiter end()
Return the end of the column tree.
Definition: table.h:2988
void set_maxlines(size_t llines)
Manually set the maximum number of lines.
Definition: table.h:612
void column_to_vector(std::string scol, resize_vec_t &v) const
Copy a column to a generic vector object.
Definition: table.h:992
void function_column(std::string function, std::string scol)
Make a column from the function specified in function and add it to the table.
Definition: table.h:2708
void integ(std::string x, std::string y, std::string ynew)
Create a new column named ynew which is equal to the integral of the function defined by x-values sto...
Definition: table.h:2029
bool is_column(std::string scol) const
Return true if scol is a column in the current table table .
Definition: table.h:939
size_t size1()
Return the number of rows.
Definition: table.h:3066
void delete_rows_func(std::string func)
Delete all rows where func evaluates to a number greater than 0.5 .
Definition: table.h:1175
Searching class for monotonic data with caching.
Definition: search_vec.h:74
size_t lookup(int icol, double val) const
Exhaustively search column col for the value val .
Definition: table.h:1569
std::map< std::string, col, std::greater< std::string > >::iterator aiter
Map iterator type.
Definition: table.h:2941
virtual void get_constant(size_t ix, std::string &name, double &val) const
Get a constant by index.
Definition: table.h:2430
Store data in an O<span style=&#39;position: relative; top: 0.3em; font-size: 0.8em&#39;>2</span>scl O$_2$sc...
Definition: hdf_file.h:101
void set_row(size_t row, size_vec_t &v)
Set an entire row of data.
Definition: table.h:384
table(size_t cmaxlines=0)
Create a new table with space for nlines<=cmaxlines.
Definition: table.h:190
bool intp_set
True if the interpolation object is up-to-date.
Definition: table.h:2997
double row_function(std::string function, size_t row) const
Compute a value by applying a function to a row.
Definition: table.h:2773
std::map< std::string, col, std::greater< std::string > > atree
The tree of columns.
Definition: table.h:2957
void get_row(size_t irow, resize_vec_t &row) const
Returns a copy of row number irow. .
Definition: table.h:525
size_t function_find_row(std::string function) const
Find a row which maximizes a function.
Definition: table.h:2794
Invalid index for array or matrix.
Definition: err_hnd.h:123
col(const col &c)
Copy constructor.
Definition: table.h:2922
size_t itype
Current interpolation type.
Definition: table.h:3000
void delete_rows_list(vec_size_t &row_list)
Delete all rows in a specified list.
Definition: table.h:1284
virtual int read_generic(std::istream &fin, int verbose=0)
Clear the current table and read from a generic data file.
Definition: table.h:2457
void add_col_from_table(table< vec2_t > &source, std::string src_index, std::string src_col, std::string dest_index, std::string dest_col="")
Insert a column from a separate table, interpolating it into a new column.
Definition: table.h:1024
std::string itos(int x)
Convert an integer to a string.
static const double x2[5]
Definition: inte_qng_gsl.h:66
matrix_view_table()
Create a matrix view object from the specified table and list of columns.
Definition: table.h:3038
virtual double eval(const double x0) const
Give the value of the function .
Definition: interp.h:1920
std::string get_column_name(size_t icol) const
Returns the name of column col .
Definition: table.h:796
static const double x1[5]
Definition: inte_qng_gsl.h:48
std::string szttos(size_t x)
Convert a size_t to a string.
void hdf_input(hdf_file &hf, o2scl::table< vec_t > &t, std::string name)
Input a o2scl::table object from a hdf_file.
Definition: hdf_io.h:146
vec_t dat
Pointer to column.
Definition: table.h:2915
std::vector< aiter >::iterator aviter
Vector iterator type.
Definition: table.h:2947
int index
Column index.
Definition: table.h:2917
void clear_constants()
CLear all constants.
Definition: table.h:2240
void vector_sort_double(size_t n, vec_t &data)
Sort a vector of doubles (in increasing order)
Definition: vector.h:898
double deriv2_const(std::string sx, double x0, std::string sy) const
The Compute the second derivative of the function defined by x-values stored in column named sx and y...
Definition: table.h:1889
double deriv_const(size_t ix, double x0, size_t iy) const
Compute the first derivative of the function defined by x-values stored in column with index ix and y...
Definition: table.h:1812
size_t lookup_column(std::string lname) const
Find the index for column named name .
Definition: table.h:951
size_t lookup(std::string scol, double val) const
Exhaustively search column col for the value val .
Definition: table.h:1507
Interpolation class for general vectors.
Definition: interp.h:1654
void inc_maxlines(size_t llines)
Manually increase the maximum number of lines.
Definition: table.h:576
virtual void swap_column_data(std::string scol, vec_t &v)
Swap the data in column scol with that in vector v.
Definition: table.h:815
std::string get_sorted_name(size_t icol) const
Returns the name of column col in sorted order. .
Definition: table.h:892
size_t nc
The number of columns.
Definition: table.h:3027
void delete_rows_ends(size_t row_start, size_t row_end)
Delete all rows between row_start and row_end .
Definition: table.h:1251
void sort_table(std::string scol)
Sort the entire table by the column scol.
Definition: table.h:2255
virtual void rename_column(std::string src, std::string dest)
Rename column named src to dest .
Definition: table.h:834

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).