1 /* Copyright (C) 2011 LinBox
2  * Written by Brice Boyer (briceboyer) <boyer.brice@gmail.com>
3  *
4  *
5  *
6  * ========LICENCE========
7  * This file is part of the library LinBox.
8  *
9  * LinBox is free software: you can redistribute it and/or modify
10  * it under the terms of the  GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  * ========LICENCE========
23  */
24 
25 /*! @file   benchmarks/benchmark.h
26  * @ingroup benchmarks
27  * @brief   Common header to ease benchmarking routines.
28  * We provide a class to easily populate and plot files that represent
29  * benchmarks.
30  *
31  * We use <a href="http://www.gnuplot.info/">gnuplot</a> for the plotting part
32  * or LaTeX to provide tables.  A minimum knowledge of \c Gnuplot is a plus but
33  * the \c benchmark-* files should provide enough examples for creating
34  * standard (not too fancy) plots.
35  *
36  * We fall back to plain latex tabulars when gnuplot is not available. We plot
37  * graphs in files whose name is extended by a random 8-char string to avoid
38  * écraser files.
39  *
40  */
41 
42 #ifndef __LINBOX_benchmarks_benchmark_H
43 #define __LINBOX_benchmarks_benchmark_H
44 // here classes TimeWatcher, PlotStyle, PlotData are declared
45 
46 #include "linbox/linbox-config.h"
47 #include <stdlib.h>
48 #include "linbox/integer.h"
49 #include "linbox/util/debug.h"
50 #include "tests/test-common.h"
51 #include "linbox/util/timer.h"
52 #include <string>
53 #include <fstream>
54 #include <iomanip> // setprecision
55 
56 #include <sys/utsname.h>
57 #include <ctime>
58 #ifdef __LINBOX_HAVE_TINYXML2
59 #include <tinyxml2.h>
60 #endif
61 
62 #include "benchmark-utils.h"
63 #include "benchmark-metadata.h"
64 
65 
66 //
67 // TimeWatcher
68 //
69 
70 namespace LinBox {
71 	/*! Helper.
72 	 * This helper has several functions :
73 	 *   - Records the timings
74 	 *   - predict the execution time for the next experiment
75 	 *   - helps producing enough experiments (but not too much and not too time consuming) for producing a valid measure.
76 	 *   .
77 	 *   @warning if the timings are too short, this may not be accurate.
78 	 *
79 	 *   See member function help for more information.
80 	 */
81 	class TimeWatcher  {
82 	private :
83 		dvector_t  *    Points_; //!< Points data. If <code>Points_[i] = x</code>, then <code>Values_[i]=f(x)<code>.
84 		dvector_t  *    Values_; //!< Time data. See \p Points_ .
85 
86 		size_t       MaxRepet_; //!< Maximum number of repetitions of timings
87 		size_t       MinRepet_; //!< Minimum number of repetitions of timings
88 		double         MaxTime_; //!< Maximum time to be spent on repetitions (after MinRepet_ iters have been done)
89 		double       AbortTime_; //!< Time to abort a series of computation.
90 		bool           aborted_; //!< abort any subsequent computation
91 
92 
93 	public:
94 		/*! constructor.
95 		 * Inits the time watcher with a pair of points/values
96 		 * @param pts vector of points
97 		 * @param vals vector of times
98 		 */
99 		TimeWatcher (dvector_t & pts, dvector_t & vals) ;
100 
101 		//! Null Constructor. The pointers are intialised to NULL
102 		TimeWatcher () ;
103 
104 		void init(dvector_t & pts, dvector_t & vals);
105 
106 		//! returns the vector of abscissa (points)
107 		dvector_t & refX() ;
108 
109 		//! returns the vector of ordiantes (values)
110 		dvector_t & refY() ;
111 
112 		/** Prediction for the next experiment time.
113 		 * It is assumed that \c predict(0)=0. If Curent_<3, a linear,
114 		 * then quadratic fit is done. Other wise, a cubic fit is
115 		 * performed.
116 		 * @param x the next evaluation point.
117 		 * @return f(x) where f tries to fit the points : \f$ f(\mathtt{Data\_}[0][0..\mathtt{Current\_}-1]) \approx  refY()[0..\mathtt{Current\_}-1]\f$
118 		 */
119 		double predict(double x) ;
120 
121 		/*! @brief Watches a timer and a number and repet and signals if over.
122 		 *
123 		 * We want at least 2 repetions but not more than maxtime spent on timing.
124 		 *
125 		 * @param repet number of previous repetitions. Should be 0 on the first time \c keepon is called.
126 		 * @param tim timer to watch
127 		 * @param maxtime maximum time (in seconds) until \c watchon tells stop.
128 		 * @return \c true if we conditions are not met to stop, \c false otherwise.
129 		 * @pre \c tim should have been started previously !
130 		 *
131 		 */
132 		bool keepon(size_t & repet, double tim, bool usePrediction = false) ;
133 
134 		//! size
135 		size_t size() const;
136 
137 		//! clear the pointers (not the settings)
138 		void clear();
139 
140 	} ; // TimeWatcher
141 } // LinBox
142 
143 //
144 // DataSeries
145 //
146 
147 namespace LinBox {
148 	/** @brief this structure holds a bunch of timings.
149 	 * It collects the points, the time spent at each point and a measure
150 	 * (for instance mflops).
151 	 * @todo Times and Values could be dmatrix_t (and mergeable)
152 	 */
153 	struct DataSeries {
154 		svector_t   PointLabels ; //!< points abscisa, values for the x axis. Used in legend for the X axis.
155 		dvector_t   Points      ; //!< points abscisa, values for the x axis. Used in TimeWatcher (for instance, if PointLabels are the names of sparse matrices, Points would be their number of non zeros, or 1,2,3,... or whatever relevant for predicting time)
156 		dvector_t   Times       ; //!< actual computation times.
157 		dvector_t   Values      ; //!< actual data to be plotted (for instance mflops)
158 		svector_t   UID         ; //!< unique id of a point.
159 
160 		//! Constructor
161 		DataSeries() ;
162 
163 		~DataSeries() ;
164 
165 #if 0
166 		/** @brief resize
167 		 * @param n new size
168 		 * @pre the size before was n-1
169 		 */
170 		void resize(const size_t & n);
171 #endif
172 
173 		//! Size of the series of measurements.
174 		size_t size() const;
175 
176 		//! add some new data.
177 		void push_back(const std::string & nam, const double & val, const double & x = NAN, const double &y = NAN);
178 
179 		// use it but change time
180 		// void useMetadata(const MetaData & m) ;
181 	}; // DataSeries
182 
183 } // LinBox
184 
185 /* ********************** */
186 /*    Plot structures     */
187 /* ********************** */
188 
189 //
190 // PlotStyle
191 //
192 
193 namespace LinBox {
194 
195 	/*! @brief Represents a table of values to plot (2D).
196 	 * list of values are reprensented by vectors.  the table is a vector
197 	 * of these vectors.
198 	 *
199 	 * @warning NaN, inf are used as missing data. More genenally
200 	 * we could store data in strings.
201 	 * @todo Allow for 'speed up against col X' style
202 	 * @todo make depend on PlotData
203 	 */
204 	//!@todo setUsingSeries(const svector_t &)
205 	class PlotStyle {
206 	public:
207 		//! What format the plot should be in?
208 		struct Term {
209 			//! Term type
210 			enum Type {
211 				png  = 100, //!< png. Portable Network Graphics file.
212 				pdf  = 101, //!< pdf. Portable Document Format actually, this is eps converted to pdf.
213 				eps  = 102, //!< eps. Encapsulated PostScript. Cool for inclusion in LaTex files. This is the default.
214 				epstex  = 107, //!< epslatex. Encapsulated PostScript. Cool for inclusion in LaTex files with latex formulas.
215 				svg  = 103, //!< sgv. Scalable Vector Graphics.
216 				tex  = 104, //!< tex. Simple tabular.
217 				html = 105, //!< html. HTML table.
218 				other= 106 //!< don't know yet...
219 			} ;
220 		};
221 
222 		// enum NoType { other = 0 } ;
223 		//! What style of graphic : histogram ? graph ?
224 		struct Plot {
225 			//! Plot type
226 			enum Type {
227 				histo = 200, //! histogram plot. This is the default. x ticks are evenly spaced, whatever there value and are labelled with their value.
228 				graph = 201, //! standard plot. Plots y_i=f(x) with x in the first colum and y_i in ith column. x-ticks are well spaced. This will not work if the X are not numbers (but strings).
229 				other = 202  //! other (ie user supplied).
230 			} ;
231 		};
232 
233 		struct Line {
234 			enum Type {
235 				lines      = 300,  //! lines.
236 				histogram  = 301,  //! histogram (boxes).
237 				linespoints= 302,  //! lines with points. (default)
238 				points     = 303,  //! only the points.
239 				other      = 304   //! rien.
240 			} ;
241 		};
242 
243 		struct Options {
244 			enum Type {
245 				oblique = 400,
246 				other   = 401
247 			};
248 		};
249 
250 		/*! @brief Constructor.
251 		 * By default, creates an histogram representing the data in an eps plot.
252 		 */
253 		PlotStyle() ;
254 
255 		/*! @brief sets the titles in the graph.
256 		 * @param titre Title of the graph
257 		 * @param titre_y Title of the y-axis (series)
258 		 * @param titre_x Title of the x-axis (data points)
259 		 */
260 		void setTitle ( const std::string  &  titre
261 				, const std::string  & titre_y
262 				, const std::string  & titre_x);
263 
264 		/*! @brief Gets the title of the graph.
265 		 * @return a gnuplot command to set the title of the graph.
266 		 */
267 		std::string  getTitle() const ;
268 
269 		/*! @brief Gets the title of points abscissa.
270 		 * @return a gnuplot command to set the title of the abscissa.
271 		 */
272 		std::string getTitleX() const ;
273 
274 		/*! @brief Gets the title of the series.
275 		 * @return a gnuplot command to set the title of the ordinate (series).
276 		 */
277 		std::string getTitleY() const ;
278 
279 		/*! @brief get the title string.
280 		 * @param index can be (0,1,2)
281 		 */
282 		std::string getRawTitle(int index=0) const ;
283 
284 		/*! @brief Sets the output format.
285 		 * @sa TermType
286 		 * @param term type
287 		 */
288 		void setTerm( enum Term::Type term) ;
289 
290 
291 		/*! @brief Gets the output format.
292 		 * @return string for setting the expected output format in gnuplot.
293 		 * @warning noenhanced allows underscores while enhanced does subscripts.
294 		 * if we add a (no) enhanced option, we'll have to add a safeFormat(std::string) that replaces \c _ with <code>\_</code> .
295 		 * This is tricky and can be done at "post production" stage :-)
296 		 */
297 		std::string getTerm() const ;
298 
299 		/*! @brief Gets the graph output extension.
300 		 * By default, this is ".eps".
301 		 * @return a string for this extension, including the sepatating dot.
302 		 *
303 		 */
304 		std::string getExt() const ;
305 
306 #if 0
307 		/*! @brief gets the style of the graph.
308 		 * This is very user-tweakable !!
309 		 * @return the style for gnuplot.
310 		 */
311 		const std::string & getStyle()
312 		{
313 			return "#style\n"+_styleopts_ ;
314 		}
315 
316 		/*! @brief sets the style of the graph.
317 		 * This is very user-tweakable !!
318 		 * @param style the style for gnuplot as a gnuplot command.
319 		 */
320 		void setStyle(const std::string & style)
321 		{
322 			_styleopts_ = style ;
323 		}
324 #endif
325 
326 		/*! @brief sets the legend position.
327 		 * @param keypos the arguments to key (where the legend should be put)
328 		 * can be :
329 		 * <code>
330 		 *      set key {on|off} {default}
331 		 *              {{inside | outside} | {lmargin | rmargin | tmargin | bmargin} | {at <position>}}
332 		 *              {left | right | center} {top | bottom | center}
333 		 *              {vertical | horizontal} {Left | Right}
334 		 *              {{no}reverse} {{no}invert}
335 		 *              {samplen <sample_length>} {spacing <vertical_spacing>}
336 		 *              {width <width_increment>}
337 		 *              {height <height_increment>}
338 		 *              {{no}autotitle {columnheader}}
339 		 *              {title "<text>"} {{no}enhanced}
340 		 *              {{no}box { {linestyle | ls <line_style>} | {linetype | lt <line_type>} {linewidth | lw <line_width>}}}
341 		 * </code>
342 		 */
343 		void setKeyPos(const std::string & keypos) ;
344 
345 
346 		/*! @brief Gets the legend position.
347 		 * by default, it is "under".
348 		 */
349 		std::string getKeyPos() const ;
350 
351 		/*! @brief sets the  position of the labels on the X absciss.
352 		 * @param opt
353 		 * @param more more stuff
354 		 */
355 		void setXtics ( enum Options::Type opt, const std::string & more="") ;
356 
357 		/*! @brief Gets the legend position.
358 		 * by default, it is 45° inclined (use in on long tics legends).
359 		 */
360 		const std::string & getXtics() const ;
361 
362 		/*! @brief Gets the name of the output graph.
363 		 * @param basnam the raw name for the output.
364 		 * @return basnam+extenstion.
365 		 */
366 		std::string getOutput(const std::string & basnam) const ;
367 
368 		/*! @brief Sets the type of plot.
369 		 * @param type the type.
370 		 * @sa PlotType
371 		 *
372 		 */
373 		void setPlotType(enum Plot::Type type) ;
374 
375 		/*! @brief Sets the way dots are linked.
376 		 * @sa LineType
377 		 * @param type type
378 		 */
379 		void setLineType( enum Line::Type type) ;
380 
381 		/*! @brief Gets the type of plot.
382 		 * default is histogram, or if graph is supplied, then the default is linespoints.
383 		 * Can be totally customized.
384 		 * @return a string for gnuplot to set the plot type.
385 		 * @sa PlotType
386 		 *
387 		 */
388 		std::string getPlotType(const std::string & extraargs ="") ;
389 
390 		/*! @brief adds some style line to the graph.
391 		 * This is very user-tweakable !!
392 		 * @param style a style line for gnuplot as a gnuplot command.
393 		 */
394 		void addPlotType(const std::string & style) ;
395 
396 		/*! @brief tells which columns to use.
397 		 * @param col a column to use.
398 		 * @param moreargs more stuff
399 		 */
400 		void setUsingSeries(size_t col, const std::string &  moreargs= "") ;
401 
402 		/*! @brief adds a column to use
403 		 * @param col a  column to use.
404 		 * @param moreargs more stuff
405 		 * @pre \p _usingcols_ is not empty, ie \c setUsingSeries has already been called.
406 		 */
407 		void addUsingSeries(size_t col, const std::string &  moreargs= "") ;
408 
409 		/*! @brief tells which columns to use.
410 		 * @param cols a list of column to use.
411 		 * @param moreargs more stuff
412 		 */
413 		void setUsingSeries(std::list<size_t> cols, const std::string & moreargs= "") ;
414 
415 		/*! @brief adds a set of columns to use.
416 		 * @param cols a list of column to use.
417 		 * @param moreargs more stuff
418 		 * @pre \p _usingcols_ is not empty, ie \c setUsingSeries has already been called.
419 		 */
420 		void addUsingSeries(std::list<size_t> cols, const std::string & moreargs= "") ;
421 
422 		/*! @brief tells which columns to use.
423 		 * @param cols all colums between \c cols.first and \c cols.second (included)
424 		 * will be used.
425 		 * @param moreargs more stuff
426 		 *
427 		 */
428 		void setUsingSeries(std::pair<size_t,size_t> cols, const std::string & moreargs= "") ;
429 
430 		/*! @brief adds contiguous columns to use.
431 		 * @param cols all colums between \c cols.first and \c
432 		 * cols.second will be used.
433 		 * @param moreargs more stuff
434 		 * @pre \p _usingcols_ is not empty, ie \c setUsingSeries has
435 		 * already been called.
436 		 *
437 		 */
438 		void addUsingSeries(std::pair<size_t,size_t> cols, const std::string & moreargs= "") ;
439 
440 		const std::string & getUsingSeries() const ;
441 
442 	private :
443 		// int                                 _precision_ ;   //!< precision of the output. by default 2.
444 		/* Legend. */
445 		std::string                         _legend_pos_;   //!< legend position
446 		/*  titles */
447 		std::string                         _title_     ;   //!< name of the graph
448 		std::string                         _title_x_   ;   //!< title for the points
449 		std::string                         _title_y_   ;   //!< title for the series
450 		std::string                         _xtics_     ;   //!< format for the x tics.
451 		/*  units */
452 		// std::string                      _unit_      ;
453 		/*  terminal output */
454 		enum Term::Type                     _term_      ; //!< output data format.
455 		// std::string                      _termopts_  ;
456 		/*  plotting style */
457 		enum Plot::Type                     _plot_type_ ; //!< histogram/graph style
458 		// std::string                         _plot_extra_; //!< extra specification for the plot style. default empty.
459 		enum Line::Type                     _line_type_ ; //!< style for the representation of points
460 		std::string                         _styleopts_ ; //!< gp style command.
461 		/*  columns to use */
462 		std::string                         _usingcols_ ; //!< columns to be used (gp command)
463 
464 
465 	} ; // PlotStyle
466 
467 } // LinBox
468 
469 //
470 // PlotData
471 //
472 
473 namespace LinBox {
474 
475 		struct Point {
476 			//! x
477 			struct Labels {
478 				typedef std::string type;
479 			};
480 
481 			//! y
482 			struct Values {
483 				typedef double type;
484 			} ;
485 
486 			//! numerical value for x
487 			struct Points {
488 				typedef double type;
489 			};
490 
491 			//! y time
492 			struct Times  {
493 				typedef double type;
494 			};
495 		} ;
496 
497 	/*! @brief The raw data to plot.
498 	 * Represents  the labels for the points (X axis) and the values for
499 	 * each series of measures (Y axis).
500 	 *
501 	 * Members that set/get are named as follows :
502 	 * - getX(nom,j) return the j'th element of series named nom
503 	 * - getX(i,j) return the j'th element of series number i
504 	 * - getCurrentSeriesX(j) return the j'th element of current series
505 	 * - getCurrentEntryX() return the current element of current series (ie the last one)
506 	 * - .
507 	 *
508 	 * Members are also named as follows :
509 	 * - getXXX is a const member
510 	 * - selectXXX is non const and may create/update stuff
511 	 * - refXXX returns a reference
512 	 * - setXXX sets something
513 	 *
514 	 * @internal The internal representation is a
515 	 * vector of vector, each series of point being a vector of double.
516 	 *
517 	 * @tparam Xkind the X axis is parametrised by \p Xkind (string, int, double...)
518 	 * The Y axis is always represented by double.
519 	 * @todo put the legend (title, x, y) in there
520 	 */
521 	class PlotData {
522 	private :
523 		std::vector<DataSeries >      _tableau_  ;   //!< data. \c _tableau_[i] represents a series of measurements. A data series is augmented only via the \c push_back method. A series may be accessed by its name, its number or it is the current working series.
524 		svector_t                  _series_label_ ;   //!< label for each series of measures. Used in the legend of the plots/tables of points.
525 		mutable size_t            _curr_series_  ;   //!< index of the current series of measurements.
526 		mutable TimeWatcher        _time_watch_  ;   //!< time predictor, helper. See \c TimeWatcher.
527 		MetaData                     _plot_data_ ;   //!< information abouth the benchmark
528 		MetaDataSeries               _meta_data_ ;   //!< information about each point
529 	private:
530 
531 #ifdef __LINBOX_HAVE_TINYXML2
532 		//! @internal data part of the XML output
533 		tinyxml2::XMLElement * saveData(tinyxml2::XMLDocument & doc) ;
534 #endif
535 
536 		/** Finds the index of a series by its name.
537 		 * @param nom name of the series
538 		 * @return its index
539 		 */
540 		size_t getIndex(const std::string & nom) const ;
541 
542 		/** Finds the index of a series by its name.
543 		 * @param nom name of the series
544 		 * @return its index
545 		 */
546 		size_t selectIndex(const std::string & nom) ;
547 
548 	public :
549 
550 		/*! Returns the ith series of measurements.
551 		 * @param i ith series to be returned
552 		 */
553 		const DataSeries & getSeries(const size_t  &i) const ;
554 
555 		/*! Returns the ith series of measurements.
556 		 * @param i ith series to be returned
557 		 */
558 		const DataSeries & selectSeries(const size_t  &i) ;
559 
560 		/*! Returns the series of measurements after its name.
561 		 * @param nom name of series to be returned
562 		 */
563 		const DataSeries & selectSeries(const std::string &name) ;
564 
565 		/*! Returns the current series of measurements.
566 		*/
567 		const DataSeries & getCurrentSeries() const;
568 
569 		/*! Returns the ith series of measurements.
570 		 * @param i ith series to be returned
571 		 */
572 		DataSeries & refSeries(const size_t  &i) ;
573 
574 		/*! Returns the ith series of measurements.
575 		 * @param i ith series to be returned
576 		 */
577 		DataSeries & refSeries(const std::string  & nom) ;
578 
579 		/*! Returns the current series of measurements.
580 		*/
581 		DataSeries & refCurrentSeries() ;
582 
583 		/*! Inits a plot with series of data.
584 		 * @param nb_pts number of points in each series.
585 		 * @param nb_srs number of series of points. Default is 1.
586 		 */
587 		PlotData() ;
588 		/*! destructor.
589 		*/
590 		~PlotData()  ;
591 
592 		/*! copy constructor.
593 		 * @param PD a PlotData to copy.
594 		 */
595 		PlotData(const PlotData & PD);
596 
597 		/** @brief initialize to empty
598 		*/
599 		void clear() ;
600 
601 		/*! merges another plot data to the current one.
602 		 * (just adds to the end, does not merge series by name yet)
603 		 */
604 		void merge(const PlotData &PD) ;
605 
606 		/*! @brief get the number of series.
607 		 * @return number of series.
608 		 */
609 		size_t size() const ;
610 
611 		/** @brief gets the current series number.
612 		*/
613 		size_t getCurrentSeriesNumber() const ;
614 
615 		/*! @brief Sets the name of a series.
616 		 * @param i index of the series
617 		 * @param nom name of the series
618 		 */
619 		void setSeriesName(const size_t & i, const std::string & nom) ;
620 
621 		// ref  Series
622 
623 		template<class Pt>
624 		std::vector<typename Pt::type> & refSeries(const size_t & i,  Pt kind) ;
625 
626 		template<class Pt>
refSeries(const std::string & name,Pt kind)627 		std::vector<typename Pt::type> & refSeries(const std::string & name,  Pt kind)
628 		{
629 			return refSeries(getIndex(name ), kind );
630 		}
631 
632 		// get Series
633 
634 		template<class Pt>
635 		const std::vector<typename Pt::type> & getSeries(const size_t & i,  Pt kind) const ;
636 
637 		template<class Pt>
getSeries(const std::string & name,Pt kind)638 		const std::vector<typename Pt::type> & getSeries(const std::string & name,  Pt kind) const
639 		{
640 			return getSeries(getIndex(name),kind);
641 		}
642 
643 		template<class Pt>
getCurrentSeries(Pt kind)644 		const std::vector<typename Pt::type> & getCurrentSeries( Pt kind) const
645 		{
646 			return getSeries(_curr_series_, kind);
647 		}
648 
649 		template<class Pt>
getSeriesEntry(const size_t & i,const size_t & j,Pt kind)650 		const typename Pt::type & getSeriesEntry(const size_t & i, const size_t & j, Pt kind) const
651 		{
652 			linbox_check(j<getSeriesSize(i));
653 			return (getSeries(i,kind)[j]) ;
654 		}
655 
656 		template<class Pt>
getSeriesEntry(const std::string & name,const size_t & j,Pt kind)657 		const typename Pt::type & getSeriesEntry(const std::string & name, const size_t & j, Pt kind) const
658 		{
659 			return getSeriesEntry(getIndex(name),j,kind);
660 		}
661 
662 		template<class Pt>
getSeriesEntry(const size_t & i,Pt kind)663 		const typename Pt::type & getSeriesEntry(const size_t & i,  Pt kind) const
664 		{
665 			return ( getSeries(i,kind).back() ) ;
666 		}
667 
668 		template<class Pt>
getSeriesEntry(const std::string & name,Pt kind)669 		const typename Pt::type & getSeriesEntry(const std::string & name,  Pt kind) const
670 		{
671 			return getSeriesEntry(getIndex(name),kind);
672 		}
673 
674 		template<class Pt>
getCurrentSeriesEntry(const size_t & j,Pt kind)675 		const typename Pt::type & getCurrentSeriesEntry(const size_t & j, Pt kind) const
676 		{
677 			return getSeriesEntry(_curr_series_, j, kind);
678 		}
679 
680 		template<class Pt>
getCurrentSeriesEntry(Pt kind)681 		const typename Pt::type & getCurrentSeriesEntry( Pt kind) const
682 		{
683 			return getSeriesEntry(_curr_series_, kind);
684 		}
685 
686 
687 		// set Series
688 
689 		/** Gets the name of a series.
690 		 * @param i index of the series
691 		 */
692 		const std::string &  getSeriesName(const size_t & i) const ;
693 
694 		/** Gets the name of the current series.
695 		*/
696 		const std::string &  getCurrentSeriesName() const ;
697 
698 		/*! @brief Sets the name of the current series.
699 		 * @param nom name of the series
700 		 */
701 		void setCurrentSeriesName(const std::string & nom) ;
702 
703 		/** Inits the watch on a series
704 		 * @param i index of a series
705 		 */
706 		void initWatch ( const size_t & i) ;
707 
708 		/** Inits the watch to current series
709 		*/
710 		void initCurrentSeriesWatch () ;
711 
712 		/** Creates a new series.
713 		 * It is created after the last series.
714 		 * \c getCurrentSeries() points to it.
715 		 * @param nom name of the new series
716 		 */
717 		void newSeries(const std::string & nom = "") ;
718 
719 		/** Finish a series of measurements.
720 		 * Nothing is done for the moment.
721 		 */
722 		void finishSeries() ;
723 
724 		/** @brief size of a series.
725 		 * @param i index of the series
726 		 */
727 		size_t getSeriesSize(const size_t & i) const ;
728 
729 		/** @brief size of the current series.
730 		*/
731 		size_t getCurrentSeriesSize() const ;
732 
733 		/*! goes to the next series of points
734 		*/
735 		bool selectNextSeries() ;
736 
737 		/** selects the first series
738 		 */
739 		void selectFirstSeries() ;
740 
741 		/*! @brief Sets the name of a point.
742 		 * @param i series number
743 		 * @param j index for the the point
744 		 * @param nom name of the point
745 		 */
746 		template<class T>
setSeriesPointLabel(const size_t & i,const size_t & j,const T & nom)747 		void setSeriesPointLabel(const size_t & i, const size_t & j, const T & nom)
748 		{
749 			std::string nom_s = fortifyString(toString(nom));
750 			linbox_check(j<getSeriesSize(i) );
751 			refSeries(i).PointLabels[j] = nom_s ;
752 
753 			return;
754 		}
755 
756 		/*! @brief Sets the name of a point.
757 		 * @param j index for the the point
758 		 * @param nom name of the point
759 		 */
760 		void setCurrentSeriesPointLabel(const size_t & j, const std::string & nom) ;
761 
762 
763 
764 		/*! @brief gets the name of a series.
765 		 * Defaults to \c "series.i"
766 		 * @param i its index.
767 		 * @return its name.
768 		 */
769 		std::string getSeriesLabel(const size_t & i) const ;
770 
771 		/*! @brief gets the name of a series.
772 		 * Defaults to \c "series.i"
773 		 * @param i its index.
774 		 * @return its name.
775 		 */
776 		std::string  getCurrentSeriesLabel() const;
777 
778 		/*! @brief gets all the names in the series.
779 		 * @return a vector of names.
780 		 */
781 		const svector_t  & getSeriesLabels() const ;
782 
783 
784 
785 
786 
787 		/*! @brief sets a new entry.
788 		 * @param i index of the series
789 		 * @param j index of the point
790 		 * @param nam name of the point (eg size of the matrix, name of a sparse matrix,...)
791 		 * @param val value to be inserted (eg mflops, sec,...).
792 		 * @param xval x value of the point (eg size of the matrix, of a sparse matrix,...)
793 		 * @param yval time for this computation (seconds)
794 		 */
795 		void setSeriesEntry(const size_t &i, const std::string & nam, const double & val
796 				    , const double & xval = NAN, const double & yval = NAN) ;
797 
798 		/*! @brief sets a new entry.
799 		 * @param name name of the series
800 		 * @param j index of the point
801 		 * @param nam name of the point (eg size of the matrix, name of a sparse matrix,...)
802 		 * @param val value to be inserted (eg mflops, sec,...).
803 		 * @param xval x value of the point (eg size of the matrix, of a sparse matrix,...)
804 		 * @param yval time for this computation (seconds)
805 		 */
806 		void setSeriesEntry(const std::string & nom, const std::string & nam, const double & val
807 			      , const double & xval = NAN, const double & yval = NAN) ;
808 
809 		/*! @brief sets a new entry.
810 		 * @param j index of the point
811 		 * @param nam name of the point (eg size of the matrix, name of a sparse matrix,...)
812 		 * @param val value to be inserted (eg mflops, sec,...).
813 		 */
814 		template<class T>
815 		void setCurrentSeriesEntry(const T & nam, const double & val
816 					   , const double & xval = NAN, const double & yval = NAN)
817 		{
818 			std::string nam_s = fortifyString(toString(nam));
819 			return setSeriesEntry(_curr_series_,nam_s,val,xval,yval) ;
820 		}
821 
822 
823 
824 		/*! gets a reference to the array of data.
825 		 * @return a reference to the member \c _tableau_ representing the data.
826 		 */
827 		const std::vector<DataSeries > & getTable() const ;
828 
829 		/*! gets a reference to the array of data.
830 		 * @return a reference to the member \c _tableau_ representing the data.
831 		 */
832 		std::vector<DataSeries > & refTable() ;
833 
834 
835 		/** @brief Continue for another time measure ?
836 		 * @see TimeWatcher::keepon
837 		 * @param repet  current number of repetitions for this new measure
838 		 * @param tim    time previously spent on the measures.
839 		 * @return true if one more measure can be done
840 		 */
841 		bool keepon(size_t & repet, double tim, bool usePrediction=false) ;
842 
843 		void load( const std::string & filename) ;
844 
845 		/** @brief saves the data in XML format.
846 		 * @param filename file name
847 		 * @param title titles of the data
848 		 * @param xtitle legend of the X axis
849 		 * @param ytitle legend of the Y axis.
850 		 */
851 		void save( const std::string & filename
852 			   , const std::string & title = ""
853 			   , const std::string & xtitle = ""
854 			   , const std::string & ytitle = "") ;
855 
addCurrentEntryMetaData(const MetaData & m)856 		void addCurrentEntryMetaData(const MetaData & m)
857 		{
858 			_meta_data_.push_back(getCurrentEntryId(),m);
859 		}
860 
861 		/** returns the unique ID of the current series last entry
862 		 */
getCurrentEntryId()863 		const std::string & getCurrentEntryId() const
864 		{
865 			return (getCurrentSeries().UID).back();
866 		}
867 
868 		/** @brief returns the unique ID of the current series j'th entry.
869 		 * @param j index of the entry.
870 		 */
getCurrentSeriesId(const size_t & j)871 		const std::string & getCurrentSeriesId(const size_t & j) const
872 		{
873 			return   (getCurrentSeries().UID[j]);
874 		}
875 
876 		/** @brief returns the unique ID of the i'th series j'th entry.
877 		 * @param i index of the series.
878 		 * @param j index of the entry.
879 		 */
getId(const size_t & i,const size_t & j)880 		const std::string & getId(const size_t & i, const size_t & j)
881 		{
882 			return   (selectSeries(i).UID[j]);
883 		}
884 
885 		/** @brief returns the unique ID of the i'th series j'th entry.
886 		 * @param i index of the series.
887 		 * @param j index of the entry.
888 		 */
getId(const std::string & name,const size_t & j)889 		const std::string & getId(const std::string & name, const size_t & j)
890 		{
891 			return   (selectSeries(name).UID[j]);
892 		}
893 
894 	}; // PlotData
895 
896 } // LinBox
897 
898 //
899 // PlotGraph
900 //
901 
902 namespace LinBox {
903 
904 	/*! @brief The graph (2D).
905 	 * This class joins a PlotStyle and a PlotData to build up a graph.  A
906 	 * filename should be provided as well, indicating where the output
907 	 * graph and scripts will be generated.
908 	 *
909 	 * @warning the filename will get a random suffix before the extension
910 	 * so as not to overwrite files "par inadvertance".
911 	 * @warning don't name anything else than a folder "data" in your working directory. You've been warned.
912 	 * @todo make depend on PlotStyle (that owns data)
913 	 */
914 	//!@todo use getUsingSeries in latex/html/csv/xml
915 	class PlotGraph {
916 	private :
917 		PlotData              & _data_ ;   //!< reference to the data points
918 		PlotStyle            & _style_ ;   //!< reference to a plotting style
919 		std::string         _filename_ ;   //!< name for the output file (without extension). a random \c _XXXXXX suffix will be added to make it unique.
920 		std::string        _printname_ ;   //!< name for the output file (without extension) to be printed. a random \c _XXXXXX suffix makes it unique.
921 		dmatrix_t         _merge_data_ ;
922 		svector_t       _merge_points_ ;
923 
924 	private :
925 
926 		/*! @internal
927 		 * @brief Appends random suffix.
928 		 * Appends to \p _filename_ a random string constituted of an
929 		 * underscore followed by 8 random alnum chars.
930 		 * @return the concatenation of \c _filename_ and this suffix.
931 		 */
932 		void _randomName();
933 
934 		//! @internal returns the file name (without extension and uid)
935 		const std::string & getFileName()  ;
936 
937 		//! @bug this supposes the two series have unique measurements for one point.
938 		void mergeTwoSeries( svector_t & merge_points
939 				     , dmatrix_t & merge_data
940 				     , const svector_t & pts
941 				     , const dvector_t & dat
942 				     , const size_t & idx) const ;
943 
944 		//! merge all series of points into a vector of absissa points  and a vector of vector of data points
945 		void mergeSeries();
946 
947 		void print_csv();
948 
949 		void print_dat();
950 
951 		void print_xml();
952 
953 		void print_html() ;
954 
955 		/*! @brief Prints data in a latex tabular.
956 		*/
957 		void print_latex();
958 
959 		/*!@brief Plots the data with gnuplot.
960 		 * Produces data in a .dat file, creates a .gp gnuplot script and
961 		 * outputs a graph calling gnuplot.
962 		 * @warning If gnuplot is not available, fall back to the latex method.
963 		 */
964 		void print_gnuplot(bool only_data=false);
965 
966 	public :
967 
968 		/*! @brief Sets a new data structure.
969 		 * @param data a reference to a PlotData class.
970 		 */
971 		void setData( PlotData & data );
972 
973 		/*! @brief Gets the data.
974 		 * @param[in,out] data a reference to a PlotData class.
975 		 */
976 		PlotData & refData( PlotData & data);
977 
978 		/*! @brief Sets a new style structure.
979 		 * @param style a reference to a PlotStyle class.
980 		 */
981 		void setStyle( PlotStyle & style ) ;
982 
983 		/*! @brief Gets the style.
984 		 * @param[in,out] style a reference to a PlotStyle class.
985 		 */
986 		PlotStyle & refStyle( PlotStyle & style) ;
987 
refStyle()988 		PlotStyle & refStyle( )
989 		{ return _style_ ; }
990 
991 
992 		// not implemented yet
993 		void sortSeries()  ;
994 
995 		// not implemented yet
996 		void unique() ;
997 
998 		/*! @brief Constructor for the PlotGraph class.
999 		 * Plots a series of data according to a style.
1000 		 * @param data data to be plot, will be processed by the style
1001 		 * @param style sets parameters to gnuplot to achieve a nice
1002 		 * plot.
1003 		 */
1004 		PlotGraph( PlotData & data, PlotStyle & style );
1005 
1006 		/*! @brief sets the ouput file name.
1007 		 * All output is put in a "data" subfolder.
1008 		 * @warning Since no file is overwritten, this
1009 		 * directory can rapidly get very populated.
1010 		 */
1011 		void setOutFilename( const std::string & filename ) ;
1012 
1013 		const std::string & getUsingSeries() ;
1014 
1015 		/*! @brief Gets the plot command line.
1016 		 * @param File the name of/path to the data file (with extension)
1017 		 * @return a gnuplot "plot" command stream.
1018 		 */
1019 		std::string getPlotCommand(const std::string & File) ;
1020 
1021 		void print( Tag::Printer pt = Tag::Printer::xml) ;
1022 
1023 		void save() ;
1024 
1025 		void load(const std::string & filename) ;
1026 
1027 	}; // PlotGraph
1028 
1029 } // LinBox
1030 
1031 //
1032 // Least Squares
1033 //
1034 
1035 #ifdef __LINBOX_HAVE_LAPACK
1036 extern "C" {
1037 #if 1 // from lapack (not clapack)
1038 
1039 	void dgels_(char *trans, int *m, int *n, int *nrhs, double *a, int *lda,
1040 		    double *b, int *ldb, double *work, int *lwork, int *info);
1041 
1042 	void dgelsy_(int *m, int *n, int *nrhs, double *a, int *lda,
1043 		     double *b, int *ldb, int *JPVT, double *RCOND, int *RANK,
1044 		     double *work, int *lwork, int *info);
1045 
1046 	void dgelss_(int *m, int *n, int *nrhs, double *a, int *lda,
1047 		     double *b, int *ldb, double *s, double *RCOND, int *RANK,
1048 		     double *work, int *lwork, int *info);
1049 #endif
1050 
1051 #if 0
1052 	int clapack_dgels (const enum CBLAS_ORDER 	Order,
1053 			   const enum CBLAS_TRANSPOSE 	TA,
1054 			   int M,
1055 			   int N,
1056 			   int NRHS,
1057 			   double * 	A,
1058 			   int lda,
1059 			   double * 	B,
1060 			   const int 	ldb
1061 			  );
1062 #endif
1063 }
1064 #endif // __LINBOX_HAVE_LAPACK
1065 
1066 //
1067 // Curve fitting
1068 //
1069 
1070 namespace LinBox {
1071 
1072 	//! fit X[n-1,n],Y[n-1,n] and return evaluation at x.
1073 	double fit2(const dvector_t & X, const dvector_t & Y, int n, double x);
1074 
1075 #ifdef __LINBOX_HAVE_LAPACK
1076 	//! fits with a degree 3 polynomial and return evaluation at x.
1077 	double fit_lapack3(const dvector_t &X, const dvector_t &Z, double x);
1078 #endif // __LINBOX_HAVE_LAPACK
1079 
1080 
1081 	//! fit X[n-2,n],Y[n-2,n] and return evaluation at x.
1082 	double fit3(const dvector_t & X, const dvector_t & Y,int n, double x);
1083 
1084 } // LinBox
1085 
1086 
1087 #ifdef LinBoxSrcOnly
1088 #include "benchmarks/benchmark.C"
1089 #endif
1090 
1091 #include "benchmarks/benchmark.inl"
1092 
1093 #endif // __LINBOX_benchmarks_benchmark_H
1094 
1095 // Local Variables:
1096 // mode: C++
1097 // tab-width: 4
1098 // indent-tabs-mode: nil
1099 // c-basic-offset: 4
1100 // End:
1101 // vim:sts=4:sw=4:ts=4:et:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s
1102