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

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).
Hosted at Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads..