root/bdm/stat/libBM.h @ 270

Revision 270, 20.3 kB (checked in by smidl, 15 years ago)

Changes in the very root classes!
* rv and rvc are no longer compulsory,
* samplecond does not return ll
* BM has drv

  • Property svn:eol-style set to native
Line 
1/*!
2  \file
3  \brief Bayesian Models (bm) that use Bayes rule to learn from observations
4  \author Vaclav Smidl.
5
6  -----------------------------------
7  BDM++ - C++ library for Bayesian Decision Making under Uncertainty
8
9  Using IT++ for numerical operations
10  -----------------------------------
11*/
12
13/*!
14\defgroup core Core BDM classes
15@{
16\defgroup const Constructors
17\defgroup math Mathematical operations
18*/
19#ifndef BM_H
20#define BM_H
21
22
23#include "../itpp_ext.h"
24#include <map>
25
26namespace bdm {
27using namespace itpp;
28using namespace std;
29
30//! Root class of BDM objects
31class bdmroot {
32public:
33        //! make sure this is a virtual object
34        virtual ~bdmroot() {}
35};
36
37typedef std::map<string, int> RVmap;
38extern ivec RV_SIZES;
39extern Array<string> RV_NAMES;
40
41//! Structure of RV (used internally), i.e. expanded RVs
42class str {
43public:
44        //! vector id ids (non-unique!)
45        ivec ids;
46        //! vector of times
47        ivec times;
48        //!Default constructor
49        str ( ivec ids0, ivec times0 ) :ids ( ids0 ),times ( times0 ) {
50                it_assert_debug ( times0.length() ==ids0.length(),"Incompatible input" );
51        };
52};
53
54/*!
55* \brief Class representing variables, most often random variables
56
57The purpose of this class is to decribe a vector of data. Such description is used for connecting various vectors between each other, see class datalink.
58
59The class is implemented using global variables to assure uniqueness of description:
60
61 In is a vector
62\dot
63digraph datalink {
64rankdir=LR;
65subgraph cluster0 {
66node [shape=record];
67label = "RV_MAP \n std::map<string,int>";
68map [label="{{\"a\"| \"b\" | \"c\"} | {<3> 3 |<1> 1|<2> 2}}"];
69color = "white"
70}
71subgraph cluster1{
72node [shape=record];
73label = "RV_NAMES";
74names [label="{<1> \"b\" | <2> \"c\" | <3>\"a\" }"];
75color = "white"
76}
77subgraph cluster2{
78node [shape=record];
79label = "RV_SIZES";
80labelloc = b;
81sizes [label="{<1>1 |<2> 4 |<3> 1}"];
82color = "white"
83}
84map:1 -> names:1;
85map:1 -> sizes:1;
86map:3 -> names:3;
87map:3 -> sizes:3;
88}
89\enddot
90*/
91
92class RV :public bdmroot {
93protected:
94        //! size of the data vector
95        int dsize;
96        //! number of individual rvs
97        int len;
98        //! Vector of unique IDs
99        ivec ids;
100        //! Vector of shifts from current time
101        ivec times;
102
103private:
104        //! auxiliary function used in constructor
105        void init ( Array<std::string> in_names, ivec in_sizes, ivec in_times );
106        int init ( const  string &name, int size );
107public:
108        //! \name Constructors
109        //!@{
110       
111        //! Full constructor
112        RV ( Array<std::string> in_names, ivec in_sizes, ivec in_times ) {init ( in_names,in_sizes,in_times );};
113        //! Constructor with times=0
114        RV ( Array<std::string> in_names, ivec in_sizes ) {init ( in_names,in_sizes,zeros_i ( in_names.length() ) );};
115        //! Constructor with sizes=1, times=0
116        RV ( Array<std::string> in_names ) {init ( in_names,ones_i ( in_names.length() ),zeros_i ( in_names.length() ) );}
117        //! Constructor of empty RV
118        RV () :dsize ( 0 ),len ( 0 ),ids ( 0 ),times ( 0 ) {};
119        //! Constructor of a single RV with given id
120        RV ( string name, int sz, int tm=0 );
121        //!@}
122       
123        //! \name Access functions
124        //!@{
125       
126        //! Printing output e.g. for debugging.
127        friend std::ostream &operator<< ( std::ostream &os, const RV &rv );
128        int _dsize() const {return dsize;} ;
129        //! Recount size of the corresponding data vector
130        int countsize() const;
131        int length() const {return len;} ;
132        int id ( int at ) const{return ids ( at );};
133        int size ( int at ) const {return RV_SIZES ( at );};
134        int time ( int at ) const{return times ( at );};
135        std::string name ( int at ) const {return RV_NAMES ( at );};
136        void set_time ( int at, int time0 ) {times ( at ) =time0;};
137        //!@}
138       
139        //TODO why not inline and later??
140
141        //! \name Algebra on Random Variables
142        //!@{
143       
144        //! Find indices of self in another rv, \return ivec of the same size as self.
145        ivec findself ( const RV &rv2 ) const;
146        //! Compare if \c rv2 is identical to this \c RV
147        bool equal ( const RV &rv2 ) const;
148        //! Add (concat) another variable to the current one, \return true if all rv2 were added, false if rv2 is in conflict
149        bool add ( const RV &rv2 );
150        //! Subtract  another variable from the current one
151        RV subt ( const RV &rv2 ) const;
152        //! Select only variables at indeces ind
153        RV subselect ( const ivec &ind ) const;
154        //! Select only variables at indeces ind
155        RV operator() ( const ivec &ind ) const {return subselect ( ind );};
156        //! Shift \c time shifted by delta.
157        void t ( int delta );
158        //!@}
159       
160        //!\name Relation to vectors
161        //!@{
162       
163        //! generate \c str from rv, by expanding sizes
164        str tostr() const;
165        //! when this rv is a part of bigger rv, this function returns indeces of self in the data vector of the bigger crv.
166        //! Then, data can be copied via: data_of_this = cdata(ind);
167        ivec dataind ( const RV &crv ) const;
168        //! generate mutual indeces when copying data betwenn self and crv.
169        //! Data are copied via: data_of_this(selfi) = data_of_rv2(rv2i)
170        void dataind ( const RV &rv2, ivec &selfi, ivec &rv2i ) const;
171        //! Minimum time-offset
172        int mint () const {return min ( times );};
173        //!@}
174       
175};
176
177
178//! Concat two random variables
179RV concat ( const RV &rv1, const RV &rv2 );
180
181//!Default empty RV that can be used as default argument
182extern RV RV0;
183
184//! Class representing function \f$f(x)\f$ of variable \f$x\f$ represented by \c rv
185
186class fnc :public bdmroot {
187protected:
188        //! Length of the output vector
189        int dimy;
190public:
191        //!default constructor
192        fnc ( ) {};
193        //! function evaluates numerical value of \f$f(x)\f$ at \f$x=\f$ \c cond
194        virtual vec eval ( const vec &cond ) {
195                return vec ( 0 );
196        };
197
198        //! function substitutes given value into an appropriate position
199        virtual void condition ( const vec &val ) {};
200
201        //! access function
202        int _dimy() const{return dimy;}
203};
204
205class mpdf;
206
207//! Probability density function with numerical statistics, e.g. posterior density.
208
209class epdf :public bdmroot {
210protected:
211        //! dimension of the random variable
212        int dim;
213        //! Description of the random variable
214        RV rv;
215
216public:
217        /*! \name Constructors
218         Construction of each epdf should support two types of constructors:
219        \li empty constructor,
220        \li copy constructor,
221       
222        The following constructors should be supported for convenience:
223        \li constructor followed by calling \c set_parameters()
224        \li constructor accepting random variables calling \c set_rv()
225       
226         All internal data structures are constructed as empty. Their values (including sizes) will be set by method \c set_parameters(). This way references can be initialized in constructors.
227        @{*/
228        epdf() :dim(0),rv ( ) {};
229        epdf(const epdf &e) :dim(e.dim),rv (e.rv) {};
230        epdf(const RV &rv0) {set_rv(rv0);};
231        void set_parameters(int dim0){dim=dim0;}
232        //!@}
233       
234        //! \name Matematical Operations
235        //!@{
236       
237        //! Returns a sample, \f$ x \f$ from density \f$ f_x()\f$
238        virtual vec sample () const {it_error("not implemneted");return vec(0);};
239        //! Returns N samples, \f$ [x_1 , x_2 , \ldots \ \f$  from density \f$ f_x(rv)\f$
240        virtual mat sample_m ( int N ) const;
241        //! Compute log-probability of argument \c val
242        virtual double evallog ( const vec &val ) const {it_error("not implemneted");return 0.0;};
243        //! Compute log-probability of multiple values argument \c val
244        virtual vec evallog_m ( const mat &Val ) const {
245                vec x ( Val.cols() );
246                for ( int i=0;i<Val.cols();i++ ) {x ( i ) =evallog ( Val.get_col ( i ) ) ;}
247                return x;
248        }
249        //! Return conditional density on the given RV, the remaining rvs will be in conditioning
250        virtual mpdf* condition ( const RV &rv ) const  {it_warning ( "Not implemented" ); return NULL;}
251        //! Return marginal density on the given RV, the remainig rvs are intergrated out
252        virtual epdf* marginal ( const RV &rv ) const {it_warning ( "Not implemented" ); return NULL;}
253        //! return expected value
254        virtual vec mean() const {it_error("not implemneted");return vec(0);};
255        //! return expected variance (not covariance!)
256        virtual vec variance() const {it_error("not implemneted");return vec(0);};
257        //!@}
258       
259        //! \name Connection to other classes
260        //! Description of the random quantity via attribute \c rv is optional.
261        //! For operations such as sampling \c rv does not need to be set. However, for \c marginalization
262        //! and \c conditioning \c rv has to be set. NB:
263        //! @{
264       
265        //!Name its rv
266        void set_rv ( const RV &rv0 ) {rv = rv0; }//it_assert_debug(isnamed(),""); };
267        //! True if rv is assigned
268        bool isnamed() const {bool b=( dim==rv._dsize() );return b;}
269        //! Return name (fails when isnamed is false)
270        const RV& _rv() const {it_assert_debug ( isnamed(),"" ); return rv;}
271        //!@}
272       
273        //! \name Access to attributes
274        //! @{
275       
276        //! Size of the random variable
277        int dimension() const {return dim;}
278        //!@}
279       
280};
281
282
283//! Conditional probability density, e.g. modeling some dependencies.
284//TODO Samplecond can be generalized
285
286class mpdf : public bdmroot {
287protected:
288        //!dimension of the condition
289        int dimc;
290        //! random variable in condition
291        RV rvc;
292        //! pointer to internal epdf
293        epdf* ep;
294public:
295        //! \name Constructors
296        //! @{
297       
298        mpdf ( ) :dimc(0),rvc ( ) {};
299        //! copy constructor does not set pointer \c ep - has to be done in offsprings!
300        mpdf (const mpdf &m ) :dimc(m.dimc),rvc (m.rvc ) {};
301        //!@}
302
303        //! \name Matematical operations
304        //!@{
305       
306        //! Returns a sample from the density conditioned on \c cond, \f$x \sim epdf(rv|cond)\f$. \param cond is numeric value of \c rv
307        virtual vec samplecond ( const vec &cond ) {
308                this->condition ( cond );
309                vec temp= ep->sample();
310                return temp;
311        };
312        //! Returns \param N samples from the density conditioned on \c cond, \f$x \sim epdf(rv|cond)\f$. \param cond is numeric value of \c rv \param ll is a return value of log-likelihood of the sample.
313        virtual mat samplecond_m ( const vec &cond, int N ) {
314                this->condition ( cond );
315                mat temp ( ep->dimension(),N ); vec smp ( ep->dimension() );
316                for ( int i=0;i<N;i++ ) {smp=ep->sample() ;temp.set_col ( i, smp );}
317                return temp;
318        };
319        //! Update \c ep so that it represents this mpdf conditioned on \c rvc = cond
320        virtual void condition ( const vec &cond ) {it_error ( "Not implemented" );};
321
322        //! Shortcut for conditioning and evaluation of the internal epdf. In some cases,  this operation can be implemented efficiently.
323        virtual double evallogcond ( const vec &dt, const vec &cond ) {
324                double tmp; this->condition ( cond );tmp = ep->evallog ( dt );          it_assert_debug ( std::isfinite ( tmp ),"Infinite value" ); return tmp;
325        };
326
327        //! Matrix version of evallogcond
328        virtual vec evallogcond_m ( const mat &Dt, const vec &cond ) {this->condition ( cond );return ep->evallog_m ( Dt );};
329
330        //! \name Access to attributes
331        //! @{
332       
333        RV _rv() {return ep->_rv();}
334        RV _rvc() {it_assert_debug ( isnamed(),"" ); return rvc;}
335        int dimension() {return ep->dimension();}
336        int dimensionc() {return dimc;}
337        epdf& _epdf() {return *ep;}
338        epdf* _e() {return ep;}
339        //!@}
340       
341        //! \name Connection to other objects
342        //!@{
343        void set_rvc ( const RV &rvc0 ) {rvc=rvc0;}
344        void set_rv ( const RV &rv0 ) {ep->set_rv(rv0);}
345        bool isnamed() {return (ep->isnamed())&&(dimc==rvc._dsize());}
346        //!@}
347};
348
349/*! \brief DataLink is a connection between two data vectors Up and Down
350
351Up can be longer than Down. Down must be fully present in Up (TODO optional)
352See chart:
353\dot
354digraph datalink {
355        node [shape=record];
356        subgraph cluster0 {
357                label = "Up";
358        up [label="<1>|<2>|<3>|<4>|<5>"];
359                color = "white"
360}
361        subgraph cluster1{
362                label = "Down";
363                labelloc = b;
364        down [label="<1>|<2>|<3>"];
365                color = "white"
366}
367    up:1 -> down:1;
368    up:3 -> down:2;
369    up:5 -> down:3;
370}
371\enddot
372
373*/
374class datalink {
375protected:
376        //! Remember how long val should be
377        int downsize;
378        //! Remember how long val of "Up" should be
379        int upsize;
380        //! val-to-val link, indeces of the upper val
381        ivec v2v_up;
382public:
383        //! Constructor
384        datalink ( const RV &rv, const RV &rv_up ) :
385                        downsize ( rv._dsize() ), upsize ( rv_up._dsize() ), v2v_up ( rv.dataind ( rv_up ) )  {
386                it_assert_debug ( v2v_up.length() ==downsize,"rv is not fully in rv_up" );
387        }
388        //! Get val for myself from val of "Up"
389        vec pushdown ( const vec &val_up ) {
390                it_assert_debug ( upsize==val_up.length(),"Wrong val_up" );
391                return get_vec ( val_up,v2v_up );
392        }
393        //! Fill val of "Up" by my pieces
394        void pushup ( vec &val_up, const vec &val ) {
395                it_assert_debug ( downsize==val.length(),"Wrong val" );
396                it_assert_debug ( upsize==val_up.length(),"Wrong val_up" );
397                set_subvector ( val_up, v2v_up, val );
398        }
399};
400
401//! data link between
402class datalink_m2e: public datalink {
403protected:
404        //! Remember how long cond should be
405        int condsize;
406        //!upper_val-to-local_cond link, indeces of the upper val
407        ivec v2c_up;
408        //!upper_val-to-local_cond link, ideces of the local cond
409        ivec v2c_lo;
410
411public:
412        //! Constructor
413        datalink_m2e ( const RV &rv,  const RV &rvc, const RV &rv_up ) :
414                        datalink ( rv,rv_up ), condsize ( rvc._dsize() ) {
415                //establish v2c connection
416                rvc.dataind ( rv_up, v2c_lo, v2c_up );
417        }
418        //!Construct condition
419        vec get_cond ( const vec &val_up ) {
420                vec tmp ( condsize );
421                set_subvector ( tmp,v2c_lo,val_up ( v2c_up ) );
422                return tmp;
423        }
424        void pushup_cond ( vec &val_up, const vec &val, const vec &cond ) {
425                it_assert_debug ( downsize==val.length(),"Wrong val" );
426                it_assert_debug ( upsize==val_up.length(),"Wrong val_up" );
427                set_subvector ( val_up, v2v_up, val );
428                set_subvector ( val_up, v2c_up, cond );
429        }
430};
431//!DataLink is a connection between mpdf and its superordinate (Up)
432//! This class links
433class datalink_m2m: public datalink_m2e {
434protected:
435        //!cond-to-cond link, indeces of the upper cond
436        ivec c2c_up;
437        //!cond-to-cond link, indeces of the local cond
438        ivec c2c_lo;
439public:
440        //! Constructor
441        datalink_m2m ( const RV &rv, const RV &rvc, const RV &rv_up, const RV &rvc_up ) :
442                        datalink_m2e ( rv, rvc, rv_up ) {
443                //establish c2c connection
444                rvc.dataind ( rvc_up, c2c_lo, c2c_up );
445                it_assert_debug ( c2c_lo.length() +v2c_lo.length() ==condsize, "cond is not fully given" );
446        }
447        //! Get cond for myself from val and cond of "Up"
448        vec get_cond ( const vec &val_up, const vec &cond_up ) {
449                vec tmp ( condsize );
450                set_subvector ( tmp,v2c_lo,val_up ( v2c_up ) );
451                set_subvector ( tmp,c2c_lo,cond_up ( c2c_up ) );
452                return tmp;
453        }
454        //! Fill
455
456};
457
458/*!
459@brief Class for storing results (and semi-results) of an experiment
460
461This class abstracts logging of results from implementation. This class replaces direct logging of results (e.g. to files or to global variables) by calling methods of a logger. Specializations of this abstract class for specific storage method are designed.
462 */
463class logger : public bdmroot {
464protected:
465        //! RVs of all logged variables.
466        Array<RV> entries;
467        //! Names of logged quantities, e.g. names of algorithm variants
468        Array<string> names;
469public:
470        //!Default constructor
471        logger ( ) : entries ( 0 ),names ( 0 ) {}
472
473        //! returns an identifier which will be later needed for calling the log() function
474        virtual int add ( const RV &rv, string name="" ) {
475                int id=entries.length();
476                names=concat ( names, name ); // diff
477                entries.set_length ( id+1,true );
478                entries ( id ) = rv;
479                return id; // identifier of the last entry
480        }
481
482        //! log this vector
483        virtual void logit ( int id, const vec &v ) =0;
484
485        //! Shifts storage position for another time step.
486        virtual void step() =0;
487
488        //! Finalize storing information
489        virtual void finalize() {};
490
491        //! Initialize the storage
492        virtual void init() {};
493
494};
495
496/*! \brief Unconditional mpdf, allows using epdf in the role of mpdf.
497
498*/
499class mepdf : public mpdf {
500public:
501        //!Default constructor
502        mepdf ( const epdf* em ) :mpdf ( ) {ep=const_cast<epdf*> ( em );};
503        void condition ( const vec &cond ) {}
504};
505
506//!\brief Abstract composition of pdfs, will be used for specific classes
507//!this abstract class is common to epdf and mpdf
508class compositepdf {
509protected:
510        //!Number of mpdfs in the composite
511        int n;
512        //! Elements of composition
513        Array<mpdf*> mpdfs;
514public:
515        compositepdf ( Array<mpdf*> A0 ) : n ( A0.length() ), mpdfs ( A0 ) {};
516        //! find common rv, flag \param checkoverlap modifies whether overlaps are acceptable
517        RV getrv ( bool checkoverlap=false );
518        //! common rvc of all mpdfs is written to rvc
519        void setrvc ( const RV &rv, RV &rvc );
520};
521
522/*! \brief Abstract class for discrete-time sources of data.
523
524The class abstracts operations of: (i) data aquisition, (ii) data-preprocessing, (iii) scaling of data, and (iv) data resampling from the task of estimation and control.
525Moreover, for controlled systems, it is able to receive the desired control action and perform it in the next step. (Or as soon as possible).
526
527*/
528
529class DS : public bdmroot {
530protected:
531        int dtsize;
532        int utsize;
533        //!Description of data returned by \c getdata().
534        RV Drv;
535        //!Description of data witten by by \c write().
536        RV Urv; //
537        //! Remember its own index in Logger L
538        int L_dt, L_ut;
539public:
540        //! default constructors
541        DS() :Drv (  ),Urv ( ) {};
542        //! Returns full vector of observed data=[output, input]
543        virtual void getdata ( vec &dt ) {it_error ( "abstract class" );};
544        //! Returns data records at indeces.
545        virtual void getdata ( vec &dt, const ivec &indeces ) {it_error ( "abstract class" );};
546        //! Accepts action variable and schedule it for application.
547        virtual void write ( vec &ut ) {it_error ( "abstract class" );};
548        //! Accepts action variables at specific indeces
549        virtual void write ( vec &ut, const ivec &indeces ) {it_error ( "abstract class" );};
550
551        //! Moves from \f$ t \f$ to \f$ t+1 \f$, i.e. perfroms the actions and reads response of the system.
552        virtual void step() =0;
553
554        //! Register DS for logging into logger L
555        virtual void log_add ( logger &L ) {
556                it_assert_debug ( dtsize==Drv._dsize(),"" );
557                it_assert_debug ( utsize==Urv._dsize(),"" );
558
559                L_dt=L.add ( Drv,"" );
560                L_ut=L.add ( Urv,"" );
561        }
562        //! Register DS for logging into logger L
563        virtual void logit ( logger &L ) {
564                vec tmp ( Drv._dsize() +Urv._dsize() );
565                getdata ( tmp );
566                // d is first in getdata
567                L.logit ( L_dt,tmp.left ( Drv._dsize() ) );
568                // u follows after d in getdata
569                L.logit ( L_ut,tmp.mid ( Drv._dsize(), Urv._dsize() ) );
570        }
571        //!access function
572        virtual RV _drv() const {return concat ( Drv,Urv );}
573        //!access function
574        const RV& _urv() const {return Urv;}
575};
576
577/*! \brief Bayesian Model of a system, i.e. all uncertainty is modeled by probabilities.
578
579*/
580
581class BM :public bdmroot {
582protected:
583        //! Random variable of the data (optional)
584        RV drv;
585        //!Logarithm of marginalized data likelihood.
586        double ll;
587        //!  If true, the filter will compute likelihood of the data record and store it in \c ll . Set to false if you want to save computational time.
588        bool evalll;
589public:
590        //! \name Constructors
591        //! @{
592       
593        BM () :ll (0),evalll ( false) {};
594        BM ( const BM &B ) :  drv(B.drv), ll ( B.ll ), evalll ( B.evalll ) {}
595        //! Copy function required in vectors, Arrays of BM etc. Have to be DELETED manually!
596        //! Prototype: \code BM* _copy_(){return new BM(*this);} \endcode
597        virtual BM* _copy_ () {return NULL;};
598        //!@}
599
600        //! \name Mathematical operations
601        //!@{
602       
603        /*! \brief Incremental Bayes rule
604        @param dt vector of input data
605        */
606        virtual void bayes ( const vec &dt ) = 0;
607        //! Batch Bayes rule (columns of Dt are observations)
608        virtual void bayesB ( const mat &Dt );
609        //! Evaluates predictive log-likelihood of the given data record
610        //! I.e. marginal likelihood of the data with the posterior integrated out.
611        virtual double logpred ( const vec &dt ) const{it_error ( "Not implemented" );return 0.0;}
612        //! Matrix version of logpred
613        vec logpred_m ( const mat &dt ) const{vec tmp ( dt.cols() );for ( int i=0;i<dt.cols();i++ ) {tmp ( i ) =logpred ( dt.get_col ( i ) );}return tmp;}
614
615        //!Constructs a predictive density \f$ f(d_{t+1} |d_{t}, \ldots d_{0}) \f$
616        virtual epdf* epredictor (  ) const {it_error ( "Not implemented" );return NULL;};
617        //!Constructs a conditional density 1-step ahead predictor \f$ f(d_{t+1} |d_{t+h-1}, \ldots d_{t})
618        virtual mpdf* predictor ( ) const {it_error ( "Not implemented" );return NULL;};
619        //!@}
620       
621        //! \name Access to attributes
622        //!@{
623       
624        const RV& _drv() const {return drv;}
625        void set_drv ( const RV &rv ) {drv=rv;}
626        double _ll() const {return ll;}
627        void set_evalll ( bool evl0 ) {evalll=evl0;}
628        virtual const epdf& _epdf() const =0;
629        virtual const epdf* _e() const =0;
630        //!@}
631
632};
633
634/*!
635\brief Conditional Bayesian Filter
636
637Evaluates conditional filtering density \f$f(rv|rvc,data)\f$ for a given \c rvc which is specified in each step by calling function \c condition.
638
639This is an interface class used to assure that certain BM has operation \c condition .
640
641*/
642
643class BMcond :public bdmroot {
644protected:
645        //! Identificator of the conditioning variable
646        RV rvc;
647public:
648        //! Substitute \c val for \c rvc.
649        virtual void condition ( const vec &val ) =0;
650        //! Default constructor
651        BMcond ( ) :rvc ( ) {};
652        //! Destructor for future use
653        virtual ~BMcond() {};
654        //! access function
655        const RV& _rvc() const {return rvc;}
656};
657
658}; //namespace
659/*! @} */
660#endif // BM_H
Note: See TracBrowser for help on using the browser.