1 /* Copyright (C) 2013 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 /*!@internal
26  * @file   benchmarks/benchmark.C
27  * @ingroup benchmarks
28  * @brief   utils
29   */
30 
31 #ifndef __LINBOX_benchmarks_benchmark_C
32 #define __LINBOX_benchmarks_benchmark_C
33 
34 #include "linbox/linbox-config.h"
35 
36 #include "benchmark.h"
37 
38 //
39 // PlotData
40 //
41 
42 namespace LinBox {
43 #ifdef __LINBOX_HAVE_TINYXML2
saveData(tinyxml2::XMLDocument & doc)44 	tinyxml2::XMLElement * PlotData::saveData(tinyxml2::XMLDocument & doc)
45 	{
46 		using namespace tinyxml2;
47 		XMLElement * data = doc.NewElement( "data" );
48 
49 		selectFirstSeries();
50 		for (size_t i = 0 ; i < size() ; ++i  ) {
51 
52 			XMLElement * series = doc.NewElement ( "series" );
53 			series->SetAttribute("name",unfortifyString(getCurrentSeriesName()).c_str());
54 
55 			for (size_t j = 0 ;  j < getCurrentSeriesSize() ; ++j)
56 			{
57 				XMLElement * point = doc.NewElement ( "point" );
58 				point->SetAttribute("x",unfortifyString(getCurrentSeriesEntry(j,Point::Labels() )).c_str());
59 				point->SetAttribute("y",getCurrentSeriesEntry(j,Point::Values() ));
60 				point->SetAttribute("time",getCurrentSeriesEntry(j,Point::Times() ));
61 				point->SetAttribute("xval",getCurrentSeriesEntry(j,Point::Points() ));
62 				point->SetAttribute("id",getCurrentSeriesId(j).c_str());
63 
64 				series->InsertEndChild( point );
65 			}
66 
67 			data->InsertEndChild( series );
68 
69 			selectNextSeries();
70 		}
71 
72 		return data ;
73 	}
74 #endif
75 
76 
PlotData()77 	PlotData::PlotData() :
78 		_tableau_      (0)
79 		,_series_label_ (0)
80 		,_curr_series_  ( )
81 		,_time_watch_  ( )
82 	{
83 	}
84 
~PlotData()85 	PlotData::~PlotData() {}
86 
PlotData(const PlotData & PD)87 	PlotData::PlotData(const PlotData & PD):
88 		_tableau_(PD.getTable())
89 		,_series_label_(PD.getSeriesLabels())
90 		,_curr_series_(PD.getCurrentSeriesNumber())
91 		,_time_watch_  (_tableau_[_curr_series_].Points,_tableau_[_curr_series_].Times)
92 	{
93 	}
94 
selectIndex(const std::string & nom)95 	size_t PlotData::selectIndex(const std::string & nom)
96 	{
97 
98 		std::string nomf = fortifyString(nom);
99 		size_t j ;
100 		bool ok = findKeyword(j,_series_label_.begin() , _series_label_.end() , nomf);
101 
102 
103 		if ( ! ok ) {
104 			linbox_check(j ==(size_t)_series_label_.size() );
105 			_series_label_.push_back(fortifyString(nom));
106 			_tableau_.resize(j+1);
107 		}
108 
109 		initWatch(j);
110 
111 		return j ;
112 	}
113 
getIndex(const std::string & nom)114 	size_t PlotData::getIndex(const std::string & nom) const
115 	{
116 
117 		std::string nomf = fortifyString(nom);
118 		size_t j ;
119 #ifdef NDEBUG
120                 findKeyword(j,_series_label_.begin() , _series_label_.end() , nomf);
121 #else
122 		bool ok = findKeyword(j,_series_label_.begin() , _series_label_.end() , nomf);
123 		linbox_check(ok);
124 #endif
125 
126 		return j ;
127 	}
128 
clear()129 	void PlotData::clear()
130 	{
131 		_tableau_.resize(0);
132 		_series_label_.resize(0);
133 		_curr_series_ =  0;
134 		_time_watch_.clear();
135 	}
136 
merge(const PlotData & PD)137 	void PlotData::merge(const PlotData &PD)
138 	{
139 		for (size_t i = 0 ; i < (size_t)PD.size() ; ++i) {
140 			_tableau_.push_back(PD.getSeries(i));
141 			_series_label_.push_back(fortifyString(PD.getSeriesName(i)));
142 		}
143 		return ;
144 	}
145 
size()146 	size_t PlotData::size() const
147 	{
148 		linbox_check(_tableau_.size() == _series_label_.size());
149 		return (size_t)_tableau_.size() ;
150 	}
151 
getCurrentSeriesNumber()152 	size_t PlotData::getCurrentSeriesNumber() const
153 	{
154 		return _curr_series_ ;
155 	}
156 
setSeriesName(const size_t & i,const std::string & nom)157 	void PlotData::setSeriesName(const size_t & i, const std::string & nom)
158 	{
159 		linbox_check(i<size());
160 		_series_label_[i] = fortifyString(nom) ;
161 	}
162 
getSeriesName(const size_t & i)163 	const std::string & PlotData::getSeriesName(const size_t & i) const
164 	{
165 		linbox_check(i<size());
166 		return _series_label_[i] ;
167 	}
168 
getCurrentSeriesName()169 	const std::string & PlotData::getCurrentSeriesName() const
170 	{
171 		return getSeriesName(_curr_series_) ;
172 	}
173 
setCurrentSeriesName(const std::string & nom)174 	void PlotData::setCurrentSeriesName(const std::string & nom)
175 	{
176 		return setSeriesName(_curr_series_,nom);
177 	}
178 
initWatch(const size_t & i)179 	void PlotData::initWatch ( const size_t & i)
180 	{
181 		linbox_check(i < size());
182 		_curr_series_ = i ;
183 		_time_watch_.init(_tableau_[i].Points,_tableau_[i].Times);
184 	}
185 
initCurrentSeriesWatch()186 	void PlotData::initCurrentSeriesWatch ()
187 	{
188 		initWatch(_curr_series_);
189 	}
190 
newSeries(const std::string & nom)191 	void PlotData::newSeries(const std::string & nom )
192 	{
193 
194 		size_t old_size = size() ;
195 		_curr_series_ = old_size ;
196 
197 		_tableau_.resize(old_size+1);
198 		_series_label_.resize(old_size+1);
199 
200 		if (nom.empty()) {
201 			std::ostringstream emptytitle ;
202 			emptytitle << "series." << _curr_series_ ;
203 			setCurrentSeriesName(emptytitle.str());
204 		}
205 		else
206 			setCurrentSeriesName(nom);
207 
208 		initCurrentSeriesWatch();
209 
210 		return;
211 	}
212 
finishSeries()213 	void PlotData::finishSeries()
214 	{
215 	}
216 
getSeries(const size_t & i)217 	const DataSeries & PlotData::getSeries(const size_t  &i) const
218 	{
219 		linbox_check(i < size());
220 		return _tableau_[i] ;
221 	}
222 
selectSeries(const size_t & i)223 	const DataSeries & PlotData::selectSeries(const size_t  &i)
224 	{
225 		initWatch(i);
226 		return getSeries(i) ;
227 	}
228 
selectSeries(const std::string & name)229 	const DataSeries & PlotData::selectSeries(const std::string & name)
230 	{
231 		return selectSeries(selectIndex(name));
232 	}
233 
refSeries(const size_t & i)234 	DataSeries & PlotData::refSeries(const size_t  &i)
235 	{
236 		linbox_check(i < size());
237 		return _tableau_[i] ;
238 	}
239 
refSeries(const std::string & nom)240 	DataSeries & PlotData::refSeries(const std::string &nom)
241 	{
242 		return refSeries(getIndex(nom));
243 	}
244 
getCurrentSeries()245 	const DataSeries & PlotData::getCurrentSeries() const
246 	{
247 		return getSeries(_curr_series_);
248 	}
249 
refCurrentSeries()250 	DataSeries & PlotData::refCurrentSeries()
251 	{
252 		return refSeries(_curr_series_);
253 	}
254 
getSeriesSize(const size_t & i)255 	size_t PlotData::getSeriesSize(const size_t & i) const
256 	{
257 		return getSeries(i).size();
258 	}
259 
getCurrentSeriesSize()260 	size_t PlotData::getCurrentSeriesSize() const
261 	{
262 		return getSeries(_curr_series_).size();
263 	}
264 
265 
selectFirstSeries()266 	void PlotData::selectFirstSeries()
267 	{
268 		selectSeries(0);
269 
270 		return;
271 	}
272 
selectNextSeries()273 	bool PlotData::selectNextSeries()
274 	{
275 		linbox_check(_curr_series_ < size());
276 		++_curr_series_ ;
277 		if (_curr_series_ < size()) {
278 			selectSeries(_curr_series_);
279 			return true;
280 		}
281 		return false;
282 	}
283 
setCurrentSeriesPointLabel(const size_t & j,const std::string & nom)284 	void PlotData::setCurrentSeriesPointLabel(const size_t & j, const std::string & nom)
285 	{
286 		return setSeriesPointLabel(_curr_series_,j,nom);
287 	}
288 
289 
getSeriesLabel(const size_t & i)290 	std::string  PlotData::getSeriesLabel(const size_t & i) const
291 	{
292 		linbox_check(i<size());
293 		linbox_check(i<_series_label_.size() );
294 		linbox_check(! _series_label_[i].empty()) ;
295 
296 		return(_series_label_[i]);
297 	}
298 
getSeriesLabels()299 	const svector_t &  PlotData::getSeriesLabels() const
300 	{
301 		return _series_label_ ;
302 	}
303 
304 
setSeriesEntry(const size_t & i,const std::string & nam,const double & val,const double & xval,const double & yval)305 	void PlotData::setSeriesEntry(const size_t &i, const std::string & nam, const double & val
306 				      , const double & xval , const double & yval)
307 	{
308 		refSeries(i).push_back(fortifyString(nam),val,xval,yval);
309 		initWatch(i); //  in case series has changed
310 		return ;
311 	}
312 
setSeriesEntry(const std::string & nom,const std::string & nam,const double & val,const double & xval,const double & yval)313 	void PlotData::setSeriesEntry(const std::string & nom, const std::string & nam, const double & val
314 				, const double & xval, const double & yval)
315 	{
316 		selectSeries(nom);
317 		return setCurrentSeriesEntry(nam,val,xval,yval);
318 	}
319 
getTable()320 	const std::vector<DataSeries > & PlotData::getTable() const
321 	{
322 		return _tableau_ ;
323 	}
324 
refTable()325 	std::vector<DataSeries > & PlotData::refTable()
326 	{
327 		return _tableau_ ;
328 	}
329 
keepon(size_t & repet,double tim,bool usePrediction)330 	bool PlotData::keepon(size_t & repet, double tim, bool usePrediction)
331 	{
332 		return _time_watch_.keepon(repet,tim, usePrediction);
333 	}
334 
load(const std::string & filename)335 	void PlotData::load( const std::string & filename)
336 	{
337 #ifdef __LINBOX_HAVE_TINYXML2
338 		using namespace tinyxml2;
339 		XMLDocument doc;
340 		doc.LoadFile( filename.c_str() );
341 		// std::cout << "loaded " << filename << std::endl;
342 		linbox_check(!doc.ErrorID());
343 
344 		XMLElement * bench = doc.FirstChildElement( "benchmark");
345 		linbox_check(bench);
346 		XMLElement* data = bench -> FirstChildElement( "data" ) ;
347 		linbox_check(data);
348 		XMLElement* series = data -> FirstChildElement( "series" ) ;
349 
350 		clear();
351 
352 		while (series)
353 		{
354 			newSeries( series->Attribute( "name" ) );
355 			XMLElement * points = series->FirstChildElement() ;
356 			while (points) {
357 				std::string x = points->Attribute( "x" );
358 				double      y = points->DoubleAttribute( "y" );
359 				double      time = points->DoubleAttribute( "time" );
360 				double      xval = points->DoubleAttribute( "xval" );
361 				// std::string id   = points->Attribute( "id" );
362 
363 				setCurrentSeriesEntry(x,y,xval,time);
364 
365 				// setCurrentSeriesEntryId(id);
366 
367 				points = points->NextSiblingElement();
368 			}
369 
370 			series = series->NextSiblingElement();
371 		}
372 #else
373 		throw LinBoxError("You need tinyxml2 for loading data");
374 #endif
375 		// save("toto.xml");
376 
377 	}
378 
save(const std::string & filename,const std::string & title,const std::string & xtitle,const std::string & ytitle)379 	void PlotData::save( const std::string & filename
380 			     , const std::string & title
381 			     , const std::string & xtitle
382 			     , const std::string & ytitle )
383 	{
384 #ifdef __LINBOX_HAVE_TINYXML2
385 		using namespace tinyxml2;
386 		XMLDocument doc;
387 
388 		doc.InsertEndChild(doc.NewDeclaration());
389 
390 		XMLElement * benchmark = doc.NewElement( "benchmark" );
391 		doc.InsertEndChild(benchmark);
392 
393 		{ // Benchmark Metadata
394 			XMLElement * metadata = doc.NewElement( "metadata" );
395 
396 			smatrix_t uname = getMachineInformation();
397 
398 			for (size_t i = 0 ; i < uname[0].size() ; ++i) {
399 				metadata->SetAttribute(uname[0][i].c_str(),uname[1][i].c_str());
400 			}
401 
402 			std::string myTime = getDateTime();
403 
404 			metadata->SetAttribute("time",myTime.c_str());
405 
406 			benchmark->InsertEndChild(metadata);
407 		}
408 
409 		{ // Legende
410 			XMLElement * legende = doc.NewElement( "legende" );
411 
412 			std::string mytitle = title;
413 			if (title.empty())
414 				mytitle =filename ;
415 			legende->SetAttribute("title",unfortifyString(mytitle).c_str());
416 			if (!xtitle.empty())
417 				legende->SetAttribute("X",unfortifyString(xtitle).c_str());
418 			if (!ytitle.empty())
419 				legende->SetAttribute("Y",unfortifyString(ytitle).c_str());
420 
421 
422 			benchmark->InsertEndChild(legende);
423 		}
424 
425 
426 		{ // series
427 			XMLElement * data = saveData(doc);
428 
429 			benchmark->InsertEndChild(data);
430 		}
431 
432 		{ // point metadata
433 			XMLElement * metapoint = doc.NewElement( "PointMetaData" );
434 			for (size_t i = 0 ; i < _meta_data_.MetaDataVec.size() ; ++i)
435 			{
436 				XMLElement * item = NULL ;
437 				_meta_data_.MetaDataVec[i].writeMetaData(&item,doc);
438 				std::string pts = "";
439 				for (size_t j = 0 ; j < _meta_data_.MetaDataIDs[i].size(); ++j){
440 					pts += _meta_data_.MetaDataIDs[i][j] ;
441 					if (j+1 < _meta_data_.MetaDataIDs[i].size()  )
442 						pts += ',';
443 				}
444 				item->SetAttribute("used_in",pts.c_str());
445 				metapoint->InsertEndChild(item);
446 			}
447 
448 			benchmark->InsertEndChild(metapoint);
449 		}
450 
451 		doc.SaveFile(filename.c_str());
452 
453 		std::cout << "xml table saved in " << filename << std::endl;
454 #else
455 		std::cout << "tinyxml2 is not installed, could not save" << std::endl;
456 #endif
457 
458 	}
459 
460 } // LinBox
461 
462 
463 //
464 // PlotStyle
465 //
466 
467 namespace LinBox {
468 
469 
PlotStyle()470 	PlotStyle::PlotStyle() :
471 		_term_(Term::eps),_plot_type_(Plot::histo),_line_type_(Line::histogram)
472 	{
473 
474 	}
475 
setTitle(const std::string & titre,const std::string & titre_y,const std::string & titre_x)476 	void PlotStyle::setTitle ( const std::string  &  titre
477 				   , const std::string  & titre_y
478 				   , const std::string  & titre_x)
479 	{
480 		_title_   = titre ;
481 		_title_x_ = titre_x ;
482 		_title_y_ = titre_y ;
483 	}
484 
getTitle()485 	std::string PlotStyle::getTitle() const
486 	{
487 		std::string title = "#title\nset title \""  + _title_ + '\"';
488 		if (!_title_x_.empty())
489 			title +="\nset xlabel \"" + _title_x_ +'\"' ;
490 		if (!_title_y_.empty())
491 			title +="\nset ylabel \"" + _title_y_ +'\"' ;
492 		return title ;
493 	}
494 
getTitleX()495 	std::string PlotStyle::getTitleX() const
496 	{
497 		return "\nset xlabel \"" + _title_x_ + '\"' ;
498 	}
499 
getTitleY()500 	std::string PlotStyle::PlotStyle::getTitleY() const
501 	{
502 		return "\nset ylabel \"" + _title_y_ + '\"' ;
503 	}
504 
getRawTitle(int index)505 	std::string PlotStyle::getRawTitle(int index) const
506 	{
507 		switch (index) {
508 		case 0 :
509 			return _title_ ;
510 		case 1 :
511 			return _title_x_ ;
512 		case 2 :
513 			return _title_y_ ;
514 		default :
515 			return "bad index" ;
516 		}
517 	}
518 
setTerm(enum Term::Type term)519 	void PlotStyle::setTerm( enum Term::Type term)
520 	{
521 		_term_ = term ;
522 	}
523 
getTerm()524 	std::string PlotStyle::getTerm() const
525 	{
526 		std::string term = "#term\nset term " ;
527 		switch(_term_) {
528 		case (Term::png) :
529 			term += "png noenhanced" ;
530 			break;
531 		case (Term::pdf) :
532 			std::cerr << "warning, pdf not really working for now" << std::endl;
533 			term += "postscript eps noenhanced color" ;
534 			break;
535 		case (Term::eps) :
536 			term += "postscript eps noenhanced color" ;
537 			break;
538 		case (Term::epstex) :
539 			term += "epslatex color colortext" ;
540 			break;
541 
542 		case (Term::svg) :
543 			term += "svg" ;
544 			break;
545 		case (Term::other) :
546 		default :
547 			std::cerr  << " *** error ***" << std::endl << "No supported term set" << std::endl;
548 			term += "unknown" ;
549 		}
550 		return term ;
551 	}
552 
getExt()553 	std::string PlotStyle::getExt() const
554 	{
555 		switch(_term_) {
556 		case (Term::png) :
557 			return ".png" ;
558 		case (Term::pdf) :
559 #ifndef __LINBOX_HAVE_GHOSTSCRIPT
560 			std::cerr << "warning, pdf not available. falling back to eps" << std::endl;
561 #endif
562 			return ".pdf" ;
563 		case (Term::eps) :
564 			return ".eps" ;
565 		case (Term::epstex) :
566 			return ".tex" ;
567 		case (Term::svg) :
568 			return ".svg" ;
569 		default :
570 			std::cerr << "unknown extension set" << std::endl;
571 			return ".xxx" ;
572 		}
573 	}
574 
setKeyPos(const std::string & keypos)575 	void PlotStyle::setKeyPos(const std::string & keypos)
576 	{
577 		_legend_pos_ = keypos ;
578 	}
579 
getKeyPos()580 	std::string PlotStyle::getKeyPos() const
581 	{
582 		std::string lgd ="#legend\nset key " ;
583 		if (!_legend_pos_.empty())
584 			lgd +=  _legend_pos_ ;
585 		else
586 			lgd += " under" ;
587 		return lgd;
588 	}
589 
setXtics(enum Options::Type opt,const std::string & more)590 	void PlotStyle::setXtics ( enum Options::Type opt, const std::string & more )
591 	{
592 		_xtics_ =  "#xtics\nset xtics ";
593 		if (opt == Options::oblique)
594 			_xtics_ +=  "nomirror rotate by -45 scale 0 ";
595 		else {
596 			linbox_check(opt == Options::other);
597 			_xtics_ += more ;
598 		}
599 	}
600 
getXtics()601 	const std::string & PlotStyle::getXtics() const
602 	{
603 		return _xtics_ ;
604 	}
605 
getOutput(const std::string & basnam)606 	std::string PlotStyle::getOutput(const std::string & basnam) const
607 	{
608 		std::string setout = "#output\nset output \'" ;
609 #ifdef __LINBOX_HAVE_GHOSTSCRIPT
610 		if (_term_ == Term::pdf)
611 			setout += "| ps2pdf - " ;
612 		setout += basnam + getExt() + '\'' ;
613 #else
614 		setout += basnam + ".eps\'" ;
615 #endif
616 
617 		return setout ;
618 	}
619 
setPlotType(enum Plot::Type type)620 	void PlotStyle::setPlotType(enum Plot::Type type)
621 	{
622 		_plot_type_ = type ;
623 		// _plot_extra_ = moreargs ;
624 	}
625 
setLineType(enum Line::Type type)626 	void PlotStyle::setLineType( enum Line::Type type)
627 	{
628 		_line_type_ = type ;
629 	}
630 
getPlotType(const std::string & extraargs)631 	std::string PlotStyle::getPlotType(const std::string & extraargs) // const
632 	{
633 		_styleopts_ += "\nset datafile missing \"inf\"" ;
634 		std::string mystyle = "#style\nset style data " ;
635 		if (_line_type_ != Line::other) {
636 			switch (_line_type_) {
637 			case (Line::lines) :
638 				mystyle += "lines" ;
639 				break;
640 			case (Line::histogram) :
641 				mystyle += "histogram" ;
642 				if (extraargs.empty()) // default style
643 					mystyle += "\nset style histogram cluster gap 1\nset style fill solid border rgb \"black\"";
644 				break;
645 			case (Line::points) :
646 				mystyle += "points" ;
647 				break;
648 			case (Line::linespoints) :
649 				mystyle += "linespoints" ;
650 				break;
651 			default :
652 				std::cout << __func__ << " : you should have set the LineType when ploting PlotType::graph !" << std::endl;
653 				mystyle += "other" ;
654 			}
655 		}
656 		else { // userd defined datastyle
657 			return _styleopts_  ;
658 		}
659 		// some more style args :
660 		mystyle += "\n" + _styleopts_ + "\n" + extraargs + "\n";
661 		return mystyle ;
662 	}
663 
addPlotType(const std::string & style)664 	void PlotStyle::addPlotType(const std::string & style)
665 	{
666 		_styleopts_ += "\n" + style ;
667 	}
668 
setUsingSeries(size_t col,const std::string & moreargs)669 	void PlotStyle::setUsingSeries(size_t col, const std::string & moreargs)
670 	{
671 		linbox_check(col>1);
672 		std::ostringstream usingcols ;
673 		if (_plot_type_ == Plot::histo) {
674 			usingcols << " using " << col << ":xtic(1) title columnheader(" << col << ") "  << moreargs << " ";
675 		}
676 		else {
677 			linbox_check(_plot_type_ == Plot::graph);
678 			usingcols << " using 1:" << col << " title columnheader(" << col << ") "  << moreargs << " ";
679 		}
680 		_usingcols_ = usingcols.str();
681 	}
682 
addUsingSeries(size_t col,const std::string & moreargs)683 	void PlotStyle::addUsingSeries(size_t col, const std::string & moreargs)
684 	{
685 		linbox_check(col>2);
686 		linbox_check(!_usingcols_.empty()); // we don't add if nothing was set
687 		std::ostringstream usingcols ;
688 		usingcols << ", \'\' using " ;
689 		if (_plot_type_ == Plot::graph)
690 			usingcols << "1:" ;
691 		usingcols << col << " ti col "  << moreargs << " ";
692 		_usingcols_ += usingcols.str();
693 	}
694 
setUsingSeries(std::list<size_t> cols,const std::string & moreargs)695 	void PlotStyle::setUsingSeries(std::list<size_t> cols, const std::string & moreargs)
696 	{
697 		linbox_check(!cols.empty());
698 		std::list<size_t>::iterator it = cols.begin();
699 		// no way to check *it< coldim...
700 		std::ostringstream usingcols ;
701 		if ( _plot_type_ == Plot::histo ) {
702 			usingcols << " using " << *it << ":xtic(1) title columnheader(" << *it << ") " << moreargs << " " ;
703 			++it ;
704 			for (;it != cols.end();++it) {
705 				usingcols << ", \'\' using " << *it << " ti col "  << moreargs << " ";
706 			}
707 		}
708 		else {
709 			linbox_check(_plot_type_ == Plot::graph);
710 			usingcols << " using 1:" << *it << " title columnheader(" << *it << ") "  << moreargs << " ";
711 			++it ;
712 			for (;it != cols.end();++it) {
713 				usingcols << ", \'\' using 1:" << *it << " ti col "  << moreargs << " ";
714 			}
715 		}
716 
717 		_usingcols_ = usingcols.str();
718 		return;
719 	}
720 
addUsingSeries(std::list<size_t> cols,const std::string & moreargs)721 	void PlotStyle::addUsingSeries(std::list<size_t> cols, const std::string & moreargs)
722 	{
723 		linbox_check(!cols.empty());
724 		linbox_check(!_usingcols_.empty()); // we don't add if nothing was set
725 		std::list<size_t>::iterator it = cols.begin();
726 		std::ostringstream usingcols ;
727 		if (_plot_type_ == Plot::histo) {
728 			for (;it != cols.end();++it) {
729 				usingcols << ", \'\' using " << *it << " ti col "  << moreargs << " ";
730 			}
731 		}
732 		else {
733 			linbox_check(_plot_type_ == Plot::graph);
734 			for (;it != cols.end();++it) {
735 				usingcols << ", \'\' using 1:" << *it << " ti col "  << moreargs << " ";
736 
737 			}
738 		}
739 		_usingcols_ += usingcols.str();
740 		return;
741 	}
742 
setUsingSeries(std::pair<size_t,size_t> cols,const std::string & moreargs)743 	void PlotStyle::setUsingSeries(std::pair<size_t,size_t> cols, const std::string & moreargs)
744 	{
745 		std::ostringstream usingcols ;
746 		if (_plot_type_ == Plot::histo) {
747 			usingcols << " using " << cols.first << ":xtic(1) title columnheader(" << cols.first << ") "  << moreargs << " ";
748 			usingcols << ", for [i=" << cols.first+1 << ":" << cols.second << "] \'\' using i title columnheader(i) "  << moreargs << " ";
749 		}
750 		else {
751 			linbox_check(_plot_type_ == Plot::graph);
752 			usingcols << " using 1:" << cols.first << " title columnheader(" << cols.first << ") "  << moreargs << " ";
753 			usingcols << ", for [i=" << cols.first+1 << ":" << cols.second << "] \'\' using 1:i title columnheader(i) "  << moreargs << " ";
754 		}
755 
756 		_usingcols_ = usingcols.str();
757 		return;
758 
759 	}
760 
addUsingSeries(std::pair<size_t,size_t> cols,const std::string & moreargs)761 	void PlotStyle::addUsingSeries(std::pair<size_t,size_t> cols, const std::string & moreargs)
762 	{
763 		linbox_check(!_usingcols_.empty()); // we don't add if nothing was set
764 		std::ostringstream usingcols ;
765 		if (_plot_type_ == Plot::histo) {
766 			usingcols << ", for i=[" << cols.first << ":" << cols.second << "] \'\' using i title columnheader(i) " << moreargs << " ";
767 		}
768 		else {
769 			usingcols << ", for i=[" << cols.first << ":" << cols.second << "] \'\' using 1:i title columnheader(i) "  << moreargs << " ";
770 			linbox_check(_plot_type_ == Plot::graph);
771 		}
772 
773 		_usingcols_ += usingcols.str();
774 
775 	}
776 
getUsingSeries()777 	const std::string & PlotStyle::getUsingSeries() const
778 	{
779 		return _usingcols_ ;
780 	}
781 
782 } // LinBox
783 
784 //
785 // Curve fitting
786 //
787 
788 namespace LinBox {
789 
790 	// fit X[nn-1,nn],Y[nn-1,nn] and return evaluation at x.
fit2(const dvector_t & X,const dvector_t & Y,int nn,double x)791 	double fit2(const dvector_t & X, const dvector_t & Y, int nn, double x)
792 	{
793 		size_t n = (size_t) nn;
794 		assert(n>0);
795 		if ( n==1 ) {
796 			if ( X[0]==X[1] ) {
797 				// std::cerr << "two of your evaluation points are at the same X" << std::endl;
798 				// this is NOT supposed to happen.
799 				return (Y[0]+Y[1])/2 ;
800 			}
801 		}
802 		if (X[n]==X[n-1]) // discard the last one.
803 			return fit2(X,Y,(int)n-1,x);
804 
805 		double a = (Y[n-1]-Y[n])/(X[n-1]-X[n]) ;
806 		double b = (X[n-1]*Y[n]-X[n]*Y[n-1])/(X[n-1]-X[n]) ;
807 		return a*x+b ;
808 	}
809 
810 #ifdef __LINBOX_HAVE_LAPACK
811 
fit_lapack3(const dvector_t & X,const dvector_t & Z,double x)812 	double fit_lapack3(const dvector_t &X, const dvector_t &Z, double x)
813 	{
814 
815 		dvector_t Y = Z ;
816 
817 		int n = (int) Z.size();
818 		linbox_check((size_t)n == X.size());
819 
820 		int deg = (int) std::min((int)4,n);
821 		dvector_t V((size_t)(deg*n));
822 
823 		int ldv = deg ;
824 
825 #if 0 // Clapack (not working)
826 		for(size_t i = 0 ; i < (size_t)n; ++i) {
827 			for (size_t j = 0 ; j < (size_t)ldv; ++j) {
828 				V[i*ldv+j] = std::pow(X[i],j);
829 			}
830 		}
831 
832 		clapack_dgels(CblasRowMajor, CblasNoTrans, n, deg, 1, &V[0],
833 			      deg, &Y[0], 1);
834 
835 #endif
836 
837 #if 1 /* basic least squares */
838 		// std::cout << V.size() << std::endl;
839 		for(size_t i = 0 ; i < (size_t)n; ++i) {
840 			for (size_t j = 0 ; j < (size_t)ldv; ++j) {
841 				V[i+j*(size_t)n] = std::pow(X[i],j);
842 			}
843 		}
844 
845 		// std::cout << V << std::endl;
846 
847 		int info;
848 		int ldun = 1 ;
849 		{
850 
851 			int lwork = 2*n*deg*4 ;
852 			dvector_t work((size_t)lwork);
853 			char N[] = "N";
854 			dgels_(N, &n, &ldv, &ldun, &(V[0]) , &n, &(Y[0]), &n, &work[0], &lwork, &info);
855 		}
856 
857 #endif
858 
859 #if 0 /* least squares using SVN and V not nec. full rank */
860 		{
861 			int lwork = 2*deg+std::max(2*deg,n)*4 ;
862 			dvector_t work(lwork);
863 			dvector_t s(deg);
864 			double rcond = 1e-8 ;
865 			int rank ;
866 			dgelss_( &n, &ldv, &ldun, &(V[0]) , &n, &(Y[0]), &n, &s[0], &rcond, &rank, &work[0], &lwork, &info);
867 		}
868 #endif
869 
870 #if 0 /* weighted least squares */
871 		//DGGGLM
872 
873 		// TODO
874 
875 #endif
876 
877 
878 		// std::cout << Y << std::endl;
879 		// horner eval the poly
880 		double res = 0.0;
881 
882 		for(int i=deg-1; i >= 0; i--) {
883 			res = res * x + Y[(size_t)i];
884 		}
885 		return res;
886 	}
887 #endif // __LINBOX_HAVE_LAPACK
888 
889 
fit3(const dvector_t & X,const dvector_t & Y,int n,double x)890 	double fit3(const dvector_t & X, const dvector_t & Y,int n, double x)
891 	{
892 #ifndef __LINBOX_HAVE_LAPACK /* à la main */
893 		linbox_check(n>1);
894 		linbox_check((size_t)n< X.size());
895 		linbox_check((size_t)n< Y.size());
896 		if (n==2) {
897 			if (X[1]==X[2])
898 				return fit2(X,Y,1,x) ;
899 			if (X[0]==X[2]) {
900 				return fit2(X,Y,1,x) ;
901 			}
902 			if (X[0]==X[1]) {
903 				dvector_t X1(2); X1[0]=X[1]; X1[2]=X[2];
904 				dvector_t Y1(2); Y1[0]=Y[1]; Y1[2]=Y[2];
905 				return fit2(X1,Y1,1,x) ;
906 			}
907 		}
908 		if (X[n]==X[n-1]) { // discard last
909 			dvector_t X1(X.begin(),X.begin()+(n-1));
910 			dvector_t Y1(Y.begin(),Y.begin()+(n-1));
911 
912 			return fit3(X1,Y1,n-1,x) ;
913 		}
914 		if (X[n]==X[n-2]) { // discard last
915 			dvector_t X1(X.begin(),X.begin()+(n-1));
916 			dvector_t Y1(Y.begin(),Y.begin()+(n-1));
917 
918 			return fit3(X1,Y1,n-1,x) ;
919 		}
920 		if (X[n-1]==X[n-2]) { // discard last but one
921 			dvector_t X1(X.begin(),X.begin()+(n-1));
922 			dvector_t Y1(Y.begin(),Y.begin()+(n-1));
923 			X1[n-1]=X[n];
924 			Y1[n-1]=Y[n];
925 
926 			return fit3(X1,Y1,n-1,x) ;
927 		}
928 
929 		// todo: use Lagrange ?
930 		// std::cout << X[n-2] << ',' << X[n-1] << ',' << X[n] << std::endl;
931 		double d  = (-X[n]+X[n-1])*(-X[n]+X[n-2])*(X[n-2]-X[n-1]) ;
932 		double a1 = -X[n]*Y[n-2]+X[n-2]*Y[n]+X[n-1]*Y[n-2]-X[n-1]*Y[n]+X[n]*Y[n-1]-X[n-2]*Y[n-1];
933 		double a2 = -X[n-2]*X[n-2]*Y[n]+X[n-2]*X[n-2]*Y[n-1]+X[n-1]*X[n-1]*Y[n]-Y[n-2]*X[n-1]*X[n-1]+Y[n-2]*X[n]*X[n]-Y[n-1]*X[n]*X[n];
934 		double a3 = X[n-2]*X[n-2]*X[n-1]*Y[n]-X[n-2]*X[n-2]*X[n]*Y[n-1]-X[n-1]*X[n-1]*X[n-2]*Y[n]+Y[n-1]*X[n-2]*X[n]*X[n]+X[n-1]*X[n-1]*X[n]*Y[n-2]-Y[n-2]*X[n-1]*X[n]*X[n];
935 
936 		// std::cout <<" (("<<a1<<"*x+"<<a2<<")*x+"<<a3<<")/"<<d << std::endl;
937 		return ((a1*x+a2)*x+a3)/d ;
938 #else // __LINBOX_HAVE_LAPACK
939 		int m = min(n,5);
940 		dvector_t X1((size_t)m) ;
941 		dvector_t Y1((size_t)m) ;
942 		for (int i = 0 ; i < m ; ++i) X1[(size_t)i] = X[(size_t)(n-m+i)] ;
943 		for (int i = 0 ; i < m ; ++i) Y1[(size_t)i] = Y[(size_t)(n-m+i)] ;
944 		return fit_lapack3(X1,Y1,x);
945 
946 #endif // __LINBOX_HAVE_LAPACK
947 	}
948 
949 } // LinBox
950 
951 
952 //
953 //  TimeWatcher
954 //
955 
956 namespace LinBox {
TimeWatcher(dvector_t & pts,dvector_t & vals)957 	TimeWatcher::TimeWatcher (dvector_t & pts, dvector_t & vals) :
958 		Points_(&pts)
959 		,Values_(&vals)
960 		,MaxRepet_(12)
961 		,MinRepet_(2)
962 		,MaxTime_(0.5)
963 		,AbortTime_(10)
964 		,aborted_(false)
965 	{
966 		linbox_check(vals.size() == pts.size());
967 	}
968 
TimeWatcher()969 	TimeWatcher::TimeWatcher () :
970 		Points_(NULL)
971 		,Values_(NULL)
972 		,MaxRepet_(12)
973 		,MinRepet_(2)
974 		,MaxTime_(0.5)
975 		,AbortTime_(10)
976 		,aborted_(false)
977 	{
978 	}
979 
980 
init(dvector_t & pts,dvector_t & vals)981 	void TimeWatcher::init(dvector_t & pts, dvector_t & vals)
982 	{
983 		linbox_check(vals.size() == pts.size());
984 		Points_ = &pts ;
985 		Values_ = &vals ;
986 	}
987 
988 
refX()989 	dvector_t & TimeWatcher::refX()
990 	{
991 		return *Points_ ;
992 	}
993 
refY()994 	dvector_t & TimeWatcher::refY()
995 	{
996 		return *Values_ ;
997 	}
998 
999 	// we don't assume that t(0sec) = 0 unless nothing has been computed yet.
predict(double x)1000 	double TimeWatcher::predict(double x)
1001 	{
1002 		size_t Current_ = size();
1003 		if (Current_ == 0)
1004 			return 0 ;
1005 		if (Current_ ==1 )
1006 			return refX()[Current_-1] ; // unknown. could be known if we suppose t(0)=0
1007 		if (Current_ == 2 ) {
1008 			return fit2(refX(),refY(),1,x);
1009 		}
1010 		return fit3(refX(),refY(), (int) Current_-1,x);
1011 	}
1012 
keepon(size_t & repet,double tim,bool usePrediction)1013 	bool TimeWatcher::keepon( size_t & repet, double tim, bool usePrediction )
1014 	{
1015 
1016 		if (aborted_)
1017 			return false ;
1018 
1019 		if (usePrediction) {
1020 			if (predict(tim) < AbortTime_)
1021 				return true ;
1022 			else{
1023 				aborted_ = true ;
1024 				return false;
1025 			}
1026 		}
1027 
1028 		if (repet<MinRepet_ || (tim < MaxTime_ && repet < MaxRepet_) ) {
1029 			++repet ;
1030 			return true;
1031 		}
1032 		return false ;
1033 	}
1034 
size()1035 	size_t TimeWatcher::size() const
1036 	{
1037 		if (Points_ == NULL || Values_ == NULL) {
1038 			linbox_check(Values_ == NULL && Points_ == NULL);
1039 			return  0 ;
1040 		}
1041 		linbox_check(Points_->size() == Values_->size());
1042 		return (size_t)Points_->size();
1043 	}
1044 
clear()1045 	void TimeWatcher::clear()
1046 	{
1047 		Points_ = NULL ;
1048 		Values_ = NULL ;
1049 	}
1050 
1051 } // LinBox
1052 
1053 //
1054 // DataSeries
1055 //
1056 
1057 namespace LinBox {
1058 
DataSeries()1059 	DataSeries:: DataSeries() :
1060 		PointLabels(0)
1061 		, Points(0)
1062 		, Times(0)
1063 		, Values(0)
1064 		, UID(0)
1065 	{}
1066 
~DataSeries()1067 	DataSeries::~DataSeries() {}
1068 
1069 #if 0
1070 	void
1071 	DataSeries::resize(const size_t & n)
1072 	{
1073 		linbox_check(n == Values.size()+1);
1074 		PointLabels.resize(n);
1075 		Times.resize(n);
1076 		Points.resize(n);
1077 		Values.resize(n);
1078 		UID.resize(n);
1079 
1080 		return;
1081 	}
1082 #endif
1083 
1084 	size_t
size()1085 	DataSeries::size() const
1086 	{
1087 		linbox_check(PointLabels.size() == Points.size())
1088 		linbox_check(Times.size() == Points.size())
1089 		linbox_check(Times.size() == Values.size())
1090 		linbox_check(Times.size() == UID.size())
1091 
1092 		return (size_t)Values.size();
1093 	}
1094 
push_back(const std::string & nam,const double & val,const double & x,const double & y)1095 	void DataSeries::push_back(const std::string & nam, const double & val, const double & x , const double &y )
1096 	{
1097 		linbox_check(PointLabels.size() == Values.size());
1098 
1099 		PointLabels.push_back(nam);
1100 
1101 		Values.push_back(val);
1102 
1103 		if ( std::isnan(x) )
1104 			Points.push_back((double)Points.size());
1105 		else
1106 			Points.push_back(x);
1107 
1108 		if ( std::isnan(y))
1109 			Times.push_back(val);
1110 		else
1111 			Times.push_back(y);
1112 
1113 		UID.push_back("point_" + randomAlNum(8));
1114 		return;
1115 	}
1116 
1117 } // LinBox
1118 
1119 //
1120 // PlotGraph
1121 //
1122 
1123 namespace LinBox {
1124 
1125 	//!@todo use getUsingSeries in latex/html/csv/xml
1126 
1127 
_randomName()1128 		void PlotGraph::_randomName()
1129 		{
1130 			std::ostringstream unique_filename ;
1131 			unique_filename << _filename_ << '_' << getDateTime("_") << '_' << randomAlNum(4);
1132 
1133 			// std::cout << unique_filename.str() << std::endl;
1134 
1135 			_printname_ = unique_filename.str() ;
1136 
1137 		}
1138 
getFileName()1139 		const std::string & PlotGraph::getFileName()
1140 		{
1141 			if (_printname_.empty())
1142 				_randomName();
1143 			return _printname_;
1144 		}
1145 
mergeTwoSeries(svector_t & merge_points,dmatrix_t & merge_data,const svector_t & pts,const dvector_t & dat,const size_t & idx)1146 		void PlotGraph::mergeTwoSeries( svector_t & merge_points
1147 				     , dmatrix_t & merge_data
1148 				     , const svector_t & pts
1149 				     , const dvector_t & dat
1150 				     , const size_t & idx) const
1151 		{
1152 			size_t data_size = (size_t)merge_points.size();
1153 			linbox_check(data_size == (size_t)merge_data[0].size());
1154 
1155 			merge_data[idx].resize(data_size,NAN);
1156 			typename svector_t::iterator it ;
1157 
1158 			for (size_t i = 0 ; i < pts.size() ; ++i) {
1159 
1160 				size_t k ;
1161 			       bool ok = findKeyword(k, merge_points.begin(), merge_points.begin()+data_size,pts[i]);
1162 
1163 				if ( ok ){
1164 					merge_data[idx][k] = dat[i] ;
1165 				}
1166 				else {
1167 					for (size_t j = 0 ; j < idx ; ++j) {
1168 						merge_data[j].push_back(NAN);
1169 					}
1170 
1171 					merge_data[idx].push_back(dat[i]) ;
1172 					merge_points.push_back(pts[i]) ;
1173 				}
1174 				// std::cout << "..." << std::endl;
1175 				// std::cout << merge_points << std::endl;
1176 				// std::cout << merge_data << std::endl;
1177 				// std::cout << "..." << std::endl;
1178 			}
1179 
1180 			return;
1181 
1182 		}
1183 
mergeSeries()1184 		void PlotGraph::mergeSeries()
1185 		{
1186 			_data_. selectFirstSeries();
1187 			_merge_points_ = _data_.getCurrentSeries( Point::Labels() ) ;
1188 			_merge_data_[0] = _data_.getCurrentSeries( Point::Values() ) ;
1189 
1190 			// std::cout << "merge points " << _merge_points_ << std::endl;
1191 			// std::cout << "merge data   " << _merge_data_ << std::endl;
1192 
1193 			for (size_t i = 1 ; i < _data_.size() ; ++i) {
1194 				_data_. selectNextSeries() ;
1195 				// std::cout << "to be merged "  << i << " : "  << std::endl;
1196 				// std::cout << "new points " << _data_.getCurrentSeriesPointLabel() << std::endl;
1197 				// std::cout << "new data   " << _data_.getCurrentSeriesValues() << std::endl;
1198 
1199 				mergeTwoSeries(_merge_points_,_merge_data_,
1200 					       _data_. getCurrentSeries( Point::Labels() ), _data_. getCurrentSeries( Point::Values() ),i);
1201 
1202 				// std::cout << "result : " << std::endl;
1203 				// std::cout << "merge points " << _merge_points_ << std::endl;
1204 				// std::cout << "merge data   " << _merge_data_ << std::endl;
1205 
1206 			}
1207 
1208 			return ;
1209 		}
1210 
print_csv()1211 		void PlotGraph::print_csv()
1212 		{
1213 			char comma   = ',';
1214 			char comment = '#';
1215 			size_t nb_points = (size_t)_merge_points_.size() ;
1216 			size_t nb_series = (size_t)_data_.size() ;
1217 
1218 			std::string unique_filename  = getFileName();
1219 			std::string DataFileName = unique_filename + ".csv" ;
1220 			std::ofstream DF(DataFileName.c_str());
1221 
1222 			/*  Data file to be plot */
1223 			DF.precision(2);
1224 			// metadata
1225 			DF << comment << fortifyString("title") << comma << fortifyString(_style_.getRawTitle()) << std::endl;
1226 			DF << comment << fortifyString("date") << fortifyString(getDateTime()) << std::endl;
1227 			smatrix_t uname = getMachineInformation();
1228 			for (size_t i = 0 ; i < uname[0].size() ; ++i)
1229 				DF << comment << fortifyString(uname[0][i]) << comma << fortifyString(uname[1][i]) << std::endl ;
1230 
1231 			// data
1232 			DF << fortifyString(_style_.getRawTitle(1)) << comma ;
1233 			for (size_t i = 0 ; i < nb_series ; ++i) {
1234 				DF << _data_.getSeriesLabel(i) ;
1235 				if (i != nb_series -1)
1236 					DF << comma ;
1237 			}
1238 			DF << std::endl;
1239 
1240 			for (size_t j = 0 ; j < nb_points ; ++j) {
1241 				DF << _merge_points_[j] << comma;
1242 				for (size_t i = 0 ; i < nb_series ; ++i) {
1243 					DF  << _merge_data_[i][j] ;
1244 					if (i != nb_series -1)
1245 						DF << comma ;
1246 
1247 				}
1248 				DF << std::endl;
1249 			}
1250 
1251 			std::cout << "csv data in " << DataFileName << std::endl;
1252 
1253 		}
1254 
print_dat()1255 		void PlotGraph::print_dat()
1256 		{
1257 			print_gnuplot(true);
1258 		}
1259 
print_xml()1260 		void PlotGraph::print_xml()
1261 		{
1262 #ifdef __LINBOX_HAVE_TINYXML2
1263 			std::string unique_filename = getFileName();
1264 			unique_filename += ".xml" ;
1265 
1266 			_data_.save(unique_filename,_style_.getRawTitle(),_style_.getRawTitle(1),_style_.getRawTitle(2));
1267 
1268 			load(unique_filename);
1269 #else
1270 			std::cout << "tinyxml2 is not installed, could not print" << std::endl;
1271 			exit(-1);
1272 #endif
1273 			return ;
1274 		}
1275 
print_html()1276 		void PlotGraph::print_html()
1277 		{
1278 
1279 			std::string comment_in = "<!--";
1280 			std::string comment_out = "-->";
1281 			size_t nb_points = (size_t)_merge_points_.size() ;
1282 			size_t nb_series = (size_t)_data_.size() ;
1283 
1284 			std::string unique_filename  = getFileName();
1285 			std::string DataFileName = unique_filename + ".html" ;
1286 			std::ofstream DF(DataFileName.c_str());
1287 
1288 			/*  Data file to be plot */
1289 			DF.precision(2);
1290 			// metadata
1291 			DF << comment_in << ("date") << (getDateTime()) << std::endl;
1292 			smatrix_t uname = getMachineInformation();
1293 			for (size_t i = 0 ; i < uname[0].size() ; ++i)
1294 				DF << (uname[0][i]) << " : " << (uname[1][i]) << std::endl ;
1295 			DF << comment_out << std::endl ;
1296 
1297 			// data
1298 			DF << "<table border=\"1\">" << std::endl;
1299 			DF << "<caption> " <<  (_style_.getRawTitle()) << " (data in " << _style_.getRawTitle(2) << ')'  << " </caption>" << std::endl;
1300 			DF << "<tr> " << std::endl;
1301 			DF << "<th> " << _style_.getRawTitle(1) << " </th>";
1302 			for (size_t i = 0 ; i < nb_series ; ++i) {
1303 				DF << "<th> " << unfortifyString(_data_.getSeriesLabel(i)) << " </th>";
1304 			}
1305 			DF << " </tr>" << std::endl;
1306 
1307 			for (size_t j = 0 ; j < nb_points ; ++j) {
1308 				DF << "<tr> " << std::endl;
1309 				DF << "<th> " << unfortifyString(_merge_points_[j]) << " </th>";
1310 				for (size_t i = 0 ; i < nb_series ; ++i) {
1311 					DF  << "<td> " << _merge_data_[i][j]  << " </td>";
1312 
1313 				}
1314 				DF << std::endl;
1315 				DF << "</tr>" << std::endl;
1316 			}
1317 
1318 			DF << "</table>" << std::endl;
1319 			std::cout << "html data in " << DataFileName << std::endl;
1320 
1321 
1322 		}
1323 
print_latex()1324 		void PlotGraph::print_latex()
1325 		{
1326 			size_t nb_points = (size_t)_merge_points_.size();
1327 			size_t nb_series = _data_.size();
1328 
1329 			linbox_check(nb_points);
1330 			linbox_check(nb_series);
1331 			// srand(time(NULL));
1332 			// std::ostringstream unique_filename  ;
1333 			std::string unique_filename = getFileName();
1334 			unique_filename += ".tex" ;
1335 			// std::cout << _filename_ << " plot in " << unique_filename << '.'<< std::endl;
1336 			std::ofstream FN(unique_filename.c_str());
1337 			//!@todo check FN opened.
1338 			// begin
1339 			FN << "%\\usepackage{slashbox}" << std::endl;
1340 			FN << "\\begin{table}" << std::endl;
1341 			FN << "\\centering"    << std::endl;
1342 			// format
1343 			FN << "\\begin{tabular}{c||" ;
1344 			for (size_t j = nb_points ; j-- ; )
1345 				FN << 'c' ;
1346 			FN << "|}" << std::endl;
1347 			// top left case
1348 			std::string series = _style_.getRawTitle(2);
1349 			std::string points = _style_.getRawTitle(1);
1350 			if (!points.empty()) {
1351 				FN << "\\backslashbox{" << points << "}{" << series << "}" ;
1352 			}
1353 			else {
1354 				FN << series ;
1355 			}
1356 			// first line
1357 			for (size_t j = 0 ; j < nb_points ; ++j ) {
1358 				FN << " & " <<  _merge_points_[j] ;
1359 			}
1360 			// lines of data
1361 			FN << std::endl << "\\hline" << std::endl;
1362 			FN.precision(2);
1363 			for (size_t i = 0 ; i < nb_series ; ++i) {
1364 				FN << _data_.getSeriesLabel(i) ;
1365 				for (size_t j =  0 ; j < nb_points ; ++j )
1366 					FN << " & " << _merge_data_[i][j] ;
1367 				if (i+1 < nb_series )
1368 					FN << "\\\\" ;
1369 				FN << std::endl;
1370 			}
1371 			// end
1372 			FN << "\\end{tabular}" << std::endl;
1373 			FN << "\\caption{" << _style_.getRawTitle() << "}" << std::endl;
1374 			FN << "\\label{tab:<+" << "label+>}" << std::endl;
1375 			FN << "\\end{table}" << std::endl ;
1376 
1377 			FN.close();
1378 
1379 			std::cout << "latex table in " << unique_filename << '.' << std::endl;
1380 			return ;
1381 
1382 		}
1383 
print_gnuplot(bool only_data)1384 		void PlotGraph::print_gnuplot(bool only_data)
1385 		{
1386 #ifndef __LINBOX_HAVE_GNUPLOT
1387 			std::cout << "gnuplot is not available on your system. only the data will be printed" << std::endl;
1388 #endif
1389 			size_t nb_points = (size_t)_merge_points_.size() ;
1390 			size_t nb_series = (size_t)_data_.size() ;
1391 
1392 			std::string unique_filename  = getFileName();
1393 			std::string DataFileName = unique_filename + ".dat" ;
1394 			std::ofstream DF(DataFileName.c_str());
1395 
1396 			/*  Data file to be plot */
1397 			// DF.precision(_style_.getPrecision());
1398 			DF.precision(2);
1399 
1400 			char comment = '#' ;
1401 			char comma   = ' ';
1402 			// metadata
1403 			DF << comment << ("title") << comma << (_style_.getRawTitle()) << std::endl;
1404 			DF << comment << ("date") << (getDateTime()) << std::endl;
1405 			smatrix_t uname = getMachineInformation();
1406 			for (size_t i = 0 ; i < uname[0].size() ; ++i)
1407 				DF << comment << (uname[0][i]) << comma << (uname[1][i]) << std::endl ;
1408 
1409 
1410 			DF << "legend " ;
1411 			for (size_t i = 0 ; i < nb_series ; ++i) {
1412 				DF << _data_.getSeriesLabel(i) << ' ' ;
1413 			}
1414 			DF << std::endl;
1415 
1416 			for (size_t j = 0 ; j < nb_points ; ++j) {
1417 				DF << _merge_points_[j] ;
1418 				for (size_t i = 0 ; i < nb_series ; ++i) {
1419 					DF << " " << _merge_data_[i][j] ;
1420 				}
1421 				DF << std::endl;
1422 			}
1423 
1424 			if (only_data)
1425 				std::cout << "data in " << DataFileName << std::endl;
1426 
1427 #ifdef __LINBOX_HAVE_GNUPLOT
1428 			if (!only_data) {
1429 				std::string PlotFileName = unique_filename + ".gp" ;
1430 				std::ofstream PF(PlotFileName.c_str());
1431 
1432 				/*  Ploting script */
1433 				PF << "#" << _filename_                    << std::endl;
1434 				PF << _style_.getTerm()                    << std::endl;
1435 				PF << _style_.getOutput(unique_filename)   << std::endl;
1436 				PF << _style_.getTitle()                   << std::endl;
1437 				PF << _style_.getKeyPos()                  << std::endl;
1438 				PF << _style_.getXtics()                   << std::endl;
1439 				PF << _style_.getPlotType()                << std::endl;
1440 
1441 				PF << getPlotCommand(DataFileName) << std::endl;
1442 
1443 				PF.close();
1444 
1445 				std::string command( "gnuplot " ) ;
1446 				command += PlotFileName ;
1447 				int err = system( command.c_str() ) ;
1448 				if (err) {
1449 					std::cout << "errors have occured. Look at gnuplot output." << std::endl;
1450 				}
1451 				else {
1452 					std::cout << "Output generated as " << unique_filename  + _style_.getExt() << std::endl;
1453 				}
1454 			}
1455 #endif
1456 
1457 
1458 			return;
1459 		}
1460 
1461 
setData(PlotData & data)1462 		void PlotGraph::setData( PlotData & data )
1463 		{
1464 			_data_ = data ;
1465 		}
1466 
refData(PlotData & data)1467 		PlotData & PlotGraph::refData( PlotData & data)
1468 		{
1469 			return data = _data_ ;
1470 		}
1471 
setStyle(PlotStyle & style)1472 		void PlotGraph::setStyle( PlotStyle & style )
1473 		{
1474 			_style_ = style ;
1475 		}
1476 
refStyle(PlotStyle & style)1477 		PlotStyle & PlotGraph::refStyle( PlotStyle & style)
1478 		{
1479 			return style = _style_ ;
1480 		}
1481 
1482 
1483 		// not implemented yet
sortSeries()1484 		void PlotGraph::sortSeries() {}
1485 
1486 		// not implemented yet
unique()1487 		void PlotGraph::unique() {}
1488 
PlotGraph(PlotData & data,PlotStyle & style)1489 		PlotGraph::PlotGraph( PlotData & data, PlotStyle & style ) :
1490 			_data_(data)
1491 			,_style_(style)
1492 			,_filename_("")
1493 			,_printname_("")
1494 			,_merge_data_(data.size())
1495 			,_merge_points_(data.getSeries(0).size())
1496 		{
1497 			srand((unsigned)time(NULL));
1498 			mergeSeries();
1499 		}
1500 
setOutFilename(const std::string & filename)1501 		void PlotGraph::setOutFilename( const std::string & filename )
1502 		{
1503 			int err = system( "test -d data || ( rm -rf data && mkdir data )" ) ;
1504 			if (err) {
1505 				throw LinBoxError("could not create directory data");
1506 			}
1507 
1508 			if ( filename.empty() ) {
1509 				_filename_ = "./data/plotdata" ;
1510 				std::cerr << "you should provide a filename. Using " << _filename_ << " as default ."<<std::endl;
1511 			}
1512 			else {
1513 				_filename_ = "./data/" + filename;
1514 			}
1515 
1516 		}
1517 
getUsingSeries()1518 		const std::string & PlotGraph::getUsingSeries() // const
1519 		{
1520 			// mutable _style_ ?
1521 			linbox_check(_merge_points_.size());
1522 			if (_style_.getUsingSeries().empty()) {
1523 				_style_.setUsingSeries(std::pair<size_t,size_t>((size_t)2,(size_t)_merge_data_.size()+1));
1524 			}
1525 			return _style_.getUsingSeries();
1526 		}
1527 
getPlotCommand(const std::string & File)1528 		std::string PlotGraph::getPlotCommand(const std::string & File) //const
1529 		{
1530 			std::string PC = "#plot\nplot \'" + File + "\' ";
1531 			PC += getUsingSeries() ;
1532 			return PC ;
1533 		}
1534 
print(Tag::Printer pt)1535 		void PlotGraph::print( Tag::Printer pt ) {
1536 			switch (pt) {
1537 			case (Tag::Printer::xml):
1538 				{
1539 					print_xml();
1540 					break;
1541 				}
1542 			case (Tag::Printer::csv) :
1543 				{
1544 					print_csv();
1545 					break;
1546 				}
1547 			case (Tag::Printer::dat) :
1548 				{
1549 					print_dat();
1550 					break;
1551 				}
1552 			case (Tag::Printer::gnuplot) :
1553 				{
1554 					print_gnuplot();
1555 					break;
1556 				}
1557 			case (Tag::Printer::tex) :
1558 				{
1559 					print_latex();
1560 					break;
1561 				}
1562 			case (Tag::Printer::html) :
1563 				{
1564 					print_html();
1565 					break;
1566 				}
1567 			default :
1568 				{
1569 					throw LinBoxError("printer unknown");
1570 				}
1571 
1572 			}
1573 
1574 			return ;
1575 		}
1576 
save()1577 		void PlotGraph::save()
1578 		{
1579 			return print_xml();
1580 		}
1581 
load(const std::string & filename)1582 		void PlotGraph::load(const std::string & filename)
1583 		{
1584 			return _data_.load(filename);
1585 		}
1586 
1587 } // LinBox
1588 
1589 #endif // __LINBOX_benchmarks_benchmark_C
1590 
1591 // Local Variables:
1592 // mode: C++
1593 // tab-width: 4
1594 // indent-tabs-mode: nil
1595 // c-basic-offset: 4
1596 // End:
1597 // vim:sts=4:sw=4:ts=4:et:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s
1598