From c9826b013b396c81454ea36f68b9fa2167a0aab7 Mon Sep 17 00:00:00 2001 From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de> Date: Mon, 19 Jan 2015 14:04:18 +0100 Subject: [PATCH] CObjVec now has subclasses ..Num,Int,Dbl,Enu --- pub/lib/expr.cpp | 11 ++- pub/lib/geni.cpp | 102 +++++++++---------- pub/lib/geni.hpp | 2 +- pub/lib/node.cpp | 253 +++++++++++++++++++++++++++-------------------- pub/lib/node.hpp | 16 +-- pub/lib/obj.cpp | 51 ++++++++-- pub/lib/obj.hpp | 83 +++++++++++----- pub/lib/olf.cpp | 6 +- pub/lib/ptr.hpp | 31 +++--- 9 files changed, 335 insertions(+), 220 deletions(-) diff --git a/pub/lib/expr.cpp b/pub/lib/expr.cpp index 6edef85d..351147d5 100644 --- a/pub/lib/expr.cpp +++ b/pub/lib/expr.cpp @@ -242,7 +242,7 @@ double CNode::tree_point_dbl( int k, int j, int i ) const CContext ctx( k, j, i ); ctx.want_error = false; RObj val = tree_val( ctx ); - RObjNumber pr = PCAST<const CObjNumber>(val); + RObjNum pr = PCAST<const CObjNum>(val); if ( !pr ) throw "Tree point value has unexpected type"; return pr->to_r(); @@ -258,15 +258,16 @@ void CNode::tree_vec_val( vector<double> *ret, vector<double> *dret, int k, int ctx.request_VI( nret ); ctx.want_error = (bool)dret; RObj val = tree_val( ctx ); - if ( RObjNumber pr = PCAST<const CObjNumber>(val) ) { + if ( RObjNum pr = PCAST<const CObjNum>(val) ) { ret->assign( nret, pr->to_r() ); if( dret && pr->has_err() ) dret->assign( nret, pr->to_dr() ); - } else if ( RObjVecDble pv = PCAST<const CObjVecDble>(val) ) { + } else if ( RObjVecDbl pv = PCAST<const CObjVecDbl>(val) ) { *ret = pv->v; - if( dret && pv->has_err() ) - *dret = pv->dv; + if( dret ) + if ( RObjVecEnu pdv = PCAST<const CObjVecEnu>(val) ) + *dret = pdv->dv; } else throw string( "BUG in tree_vec_val: unexpected return type" ); } diff --git a/pub/lib/geni.cpp b/pub/lib/geni.cpp index b773327b..33bcc8fa 100644 --- a/pub/lib/geni.cpp +++ b/pub/lib/geni.cpp @@ -28,79 +28,79 @@ using boost::format; //! Compute minimum value of a vector. -void geni_valmin( double* r, double* dr, int n, const vector<RObjVecDble>& a ) +void geni_valmin( double* r, double* dr, int n, const vector<RObjVecNum>& a ) { int idx = 0; - *r = a[0]->v[0]; + *r = a[0]->to_r(0); for ( int i=1; i<n; ++i ) { - if ( a[0]->v[i]<*r ) { - *r = a[0]->v[i]; + if ( a[0]->to_r(i)<*r ) { + *r = a[0]->to_r(i); idx = i; } } if( dr ) - *dr = a[0]->dv[idx]; + *dr = a[0]->to_dr(idx); } //! Compute maximum value of a vector. -void geni_valmax( double* r, double* dr, int n, const vector<RObjVecDble>& a ) +void geni_valmax( double* r, double* dr, int n, const vector<RObjVecNum>& a ) { int idx = 0; - *r = a[0]->v[0]; + *r = a[0]->to_r(0); for ( int i=1; i<n; ++i ) { - if ( a[0]->v[i]>*r ) { - *r = a[0]->v[i]; + if ( a[0]->to_r(i)>*r ) { + *r = a[0]->to_r(i); idx = i; } } if( dr ) - *dr = a[0]->dv[idx]; + *dr = a[0]->to_dr(idx); } //! Return x[i] with i for which y[i] is minimal. -void geni_argmin( double* r, double* dr, int n, const vector<RObjVecDble>& a ) +void geni_argmin( double* r, double* dr, int n, const vector<RObjVecNum>& a ) { int idx = 0; - double extr = a[1]->v[0]; + double extr = a[1]->to_r(0); for ( int i=1; i<n; ++i ) { - if ( a[1]->v[i]<extr ) { - extr = a[1]->v[i]; + if ( a[1]->to_r(i)<extr ) { + extr = a[1]->to_r(i); idx = i; } } - *r = a[0]->v[idx]; + *r = a[0]->to_r(idx); if( dr ) *dr = 0; // TODO better estimate } //! Return x[i] with i for which y[i] is maximal. -void geni_argmax( double* r, double* dr, int n, const vector<RObjVecDble>& a ) +void geni_argmax( double* r, double* dr, int n, const vector<RObjVecNum>& a ) { int idx = 0; - double extr = a[1]->v[0]; + double extr = a[1]->to_r(0); for ( int i=1; i<n; ++i ) { - if ( a[1]->v[i]>extr ) { - extr = a[1]->v[i]; + if ( a[1]->to_r(i)>extr ) { + extr = a[1]->to_r(i); idx = i; } } - *r = a[0]->v[idx]; + *r = a[0]->to_r(idx); if( dr ) *dr = 0; // TODO better estimate } //! Return i for which x[i] is minimal. -void geni_idxmin( double* r, double* dr, int n, const vector<RObjVecDble>& a ) +void geni_idxmin( double* r, double* dr, int n, const vector<RObjVecNum>& a ) { int idx = 0; - double extr = a[0]->v[0]; + double extr = a[0]->to_r(0); for ( int i=1; i<n; ++i ) { - if ( a[0]->v[i]<extr ) { - extr = a[0]->v[i]; + if ( a[0]->to_r(i)<extr ) { + extr = a[0]->to_r(i); idx = i; } } @@ -111,13 +111,13 @@ void geni_idxmin( double* r, double* dr, int n, const vector<RObjVecDble>& a ) //! Return i for which x[i] is maximal. -void geni_idxmax( double* r, double* dr, int n, const vector<RObjVecDble>& a ) +void geni_idxmax( double* r, double* dr, int n, const vector<RObjVecNum>& a ) { int idx = 0; - double extr = a[0]->v[0]; + double extr = a[0]->to_r(0); for ( int i=1; i<n; ++i ) { - if ( a[0]->v[i]>extr ) { - extr = a[0]->v[i]; + if ( a[0]->to_r(i)>extr ) { + extr = a[0]->to_r(i); idx = i; } } @@ -128,24 +128,24 @@ void geni_idxmax( double* r, double* dr, int n, const vector<RObjVecDble>& a ) //! Sum. -void geni_sum( double* r, double* dr, int n, const vector<RObjVecDble>& a ) +void geni_sum( double* r, double* dr, int n, const vector<RObjVecNum>& a ) { *r = 0; for ( int i=0; i<n; i++ ) - *r += a[0]->v[i]; + *r += a[0]->to_r(i); if( dr ) *dr = 0; // TODO better estimate } //! Average. -void geni_avge( double* r, double* dr, int n, const vector<RObjVecDble>& a ) +void geni_avge( double* r, double* dr, int n, const vector<RObjVecNum>& a ) { *r = 0; if ( !n ) throw string("Cannot compute average of empty vector"); for ( int i=0; i<n; i++ ) - *r += a[0]->v[i]; + *r += a[0]->to_r(i); *r /= n; if( dr ) *dr = 0; // TODO better estimate @@ -153,14 +153,14 @@ void geni_avge( double* r, double* dr, int n, const vector<RObjVecDble>& a ) //! Standard deviation. -void geni_stdv( double* r, double* dr, int n, const vector<RObjVecDble>& a ) +void geni_stdv( double* r, double* dr, int n, const vector<RObjVecNum>& a ) { if ( n<2 ) throw string("Cannot compute corrected standard deviation for sample size < 2"); double p=0, pp=0, q=0; for ( int i=0; i<n; i++ ) { - pp = p + ( a[0]->v[i] - p ) / (i+1); - q += ( a[0]->v[i] - p ) * ( a[0]->v[i] - pp ); + pp = p + ( a[0]->to_r(i) - p ) / (i+1); + q += ( a[0]->to_r(i) - p ) * ( a[0]->to_r(i) - pp ); p = pp; } *r = q / (n-1); @@ -170,13 +170,13 @@ void geni_stdv( double* r, double* dr, int n, const vector<RObjVecDble>& a ) //! Integral. -void geni_integral( double* r, double* dr, int n, const vector<RObjVecDble>& a ) +void geni_integral( double* r, double* dr, int n, const vector<RObjVecNum>& a ) { *r = 0; for ( int i=0; i<n-1; i++ ) { - if (a[0]->v[i+1]<=a[0]->v[i]) + if (a[0]->to_r(i+1)<=a[0]->to_r(i)) throw "a not sorted"; - *r += (a[0]->v[i+1]-a[0]->v[i])*(a[1]->v[i+1]+a[1]->v[i])/2; + *r += (a[0]->to_r(i+1)-a[0]->to_r(i))*(a[1]->to_r(i+1)+a[1]->to_r(i))/2; } if( dr ) *dr = 0; // TODO better estimate @@ -184,12 +184,12 @@ void geni_integral( double* r, double* dr, int n, const vector<RObjVecDble>& a ) //! Center of gravity in x, weighed by y. -void geni_cog( double* r, double* dr, int n, const vector<RObjVecDble>& a ) +void geni_cog( double* r, double* dr, int n, const vector<RObjVecNum>& a ) { double r0 = 0, r1 = 0; for ( int i=0; i<n; i++ ) { - r0 += a[1]->v[i]; - r1 += a[1]->v[i] * a[0]->v[i]; + r0 += a[1]->to_r(i); + r1 += a[1]->to_r(i) * a[0]->to_r(i); } *r = r0>0 ? r1/r0 : 0; if( dr ) @@ -198,18 +198,18 @@ void geni_cog( double* r, double* dr, int n, const vector<RObjVecDble>& a ) //! Standard deviation in x, weighed by y. -void geni_width( double* r, double* dr, int n, const vector<RObjVecDble>& a ) +void geni_width( double* r, double* dr, int n, const vector<RObjVecNum>& a ) { double r0 = 0, r1 = 0, r2 = 0; for ( int i=0; i<n; i++ ) { - r0 += a[1]->v[i]; - r1 += a[1]->v[i] * a[0]->v[i]; + r0 += a[1]->to_r(i); + r1 += a[1]->to_r(i) * a[0]->to_r(i); } if( r0<=0 ) throw "r0 <= 0"; double center = r1/r0; for ( int i=0; i<n; i++ ) { - r2 += a[1]->v[i] * SQR(a[0]->v[i]-center); + r2 += a[1]->to_r(i) * SQR(a[0]->to_r(i)-center); } *r = sqrt( r2/r0 ); if( dr ) @@ -217,17 +217,17 @@ void geni_width( double* r, double* dr, int n, const vector<RObjVecDble>& a ) } //! Correlation coefficient. -void geni_corr( double* r, double* dr, int n, const vector<RObjVecDble>& a ) +void geni_corr( double* r, double* dr, int n, const vector<RObjVecNum>& a ) { double r0 = 0, r1 = 0, s0 = 0, s1 = 0, v = 0; for ( int i=0; i<n; i++ ) { - r0 += a[0]->v[i] / n; - r1 += a[1]->v[i] / n; + r0 += a[0]->to_r(i) / n; + r1 += a[1]->to_r(i) / n; } for ( int i=0; i<n; i++ ) { - s0 += SQR(a[0]->v[i]-r0) / n; - s1 += SQR(a[1]->v[i]-r1) / n; - v += (a[0]->v[i]-r0) * (a[1]->v[i]-r1) / n; + s0 += SQR(a[0]->to_r(i)-r0) / n; + s1 += SQR(a[1]->to_r(i)-r1) / n; + v += (a[0]->to_r(i)-r0) * (a[1]->to_r(i)-r1) / n; } *r = v / sqrt(s0*s1); if( dr ) diff --git a/pub/lib/geni.hpp b/pub/lib/geni.hpp index 0c376c63..c6d5ca95 100644 --- a/pub/lib/geni.hpp +++ b/pub/lib/geni.hpp @@ -10,7 +10,7 @@ //! Function type: Evaluate generalized integral for given vector(s). -typedef void (*geni_eval) (double*, double*, int, const vector<RObjVecDble>& ); +typedef void (*geni_eval) (double*, double*, int, const vector<RObjVecNum>& ); //! A wrapper holding a functional. diff --git a/pub/lib/node.cpp b/pub/lib/node.cpp index 2ca8acfb..38d93bf6 100644 --- a/pub/lib/node.cpp +++ b/pub/lib/node.cpp @@ -71,7 +71,7 @@ const RObj CNodeFun::tree_val( const CContext& ctx ) const for ( int iarg=0; iarg<narg; ++iarg ) { pa[iarg] = arg[iarg]->tree_val( ctx ); basetypes += pa[iarg]->base_type(); - if ( pa[iarg]->vectorial ) + if ( pa[iarg]->is_vec() ) is_scalar = false; } @@ -154,7 +154,7 @@ const RObj CNodeFun::tree_val( const CContext& ctx ) const return PObjStr( new CObjStr( val ) ); } else throw S("BUG: unexpected outtype"); - } else { //vectorial + } else { //is_vec() // determine length of input vectors int n=1; for ( int iarg=0; iarg<narg; ++iarg ) { @@ -165,67 +165,67 @@ const RObj CNodeFun::tree_val( const CContext& ctx ) const throw S("vector arguments have different sizes"); } if ( tf->outtype=="i" ) { - vector<double> v(n); + PObjVecInt ret( new CObjVecInt( n ) ); if ( tf->intypes=="i" ) for ( int i=0; i<n; ++i ) - v[i] = (*(func_i_i)(f))( pa[0]->to_i(i) ); + ret->v[i] = (*(func_i_i)(f))( pa[0]->to_i(i) ); else if ( tf->intypes=="d" ) for ( int i=0; i<n; ++i ) - v[i] = (*(func_i_d)(f))( pa[0]->to_r(i) ); + ret->v[i] = (*(func_i_d)(f))( pa[0]->to_r(i) ); else if ( tf->intypes=="ii" ) for ( int i=0; i<n; ++i ) - v[i] = (*(func_i_ii)(f))( pa[0]->to_i(i), pa[1]->to_i(i) ); + ret->v[i] = (*(func_i_ii)(f))( pa[0]->to_i(i), pa[1]->to_i(i) ); else if ( tf->intypes=="dd" ) for ( int i=0; i<n; ++i ) - v[i] = (*(func_i_dd)(f))( pa[0]->to_r(i), pa[1]->to_r(i) ); + ret->v[i] = (*(func_i_dd)(f))( pa[0]->to_r(i), pa[1]->to_r(i) ); else if ( tf->intypes=="iii" ) for ( int i=0; i<n; ++i ) - v[i] = (*(func_i_iii)(f))( pa[0]->to_i(i), pa[1]->to_i(i), pa[2]->to_i(i) ); + ret->v[i] = (*(func_i_iii)(f))( pa[0]->to_i(i), pa[1]->to_i(i), pa[2]->to_i(i) ); else throw S("BUG: unexpected intypes"); - return PObjVecDble( new CObjVecDble( v ) ); + return ret; } else if ( tf->outtype=="d" ) { - vector<double> v(n); + PObjVecDbl ret( new CObjVecDbl( n ) ); if ( tf->intypes=="i" ) for ( int i=0; i<n; ++i ) - v[i] = (*(func_d_i)(f))( pa[0]->to_i(i) ); + ret->v[i] = (*(func_d_i)(f))( pa[0]->to_i(i) ); else if ( tf->intypes=="d" ) for ( int i=0; i<n; ++i ) - v[i] = (*(func_d_d)(f))( pa[0]->to_r(i) ); + ret->v[i] = (*(func_d_d)(f))( pa[0]->to_r(i) ); else if ( tf->intypes=="ii" ) for ( int i=0; i<n; ++i ) - v[i] = (*(func_d_ii)(f))( pa[0]->to_i(i), pa[1]->to_i(i) ); + ret->v[i] = (*(func_d_ii)(f))( pa[0]->to_i(i), pa[1]->to_i(i) ); else if ( tf->intypes=="dd" ) for ( int i=0; i<n; ++i ) - v[i] = (*(func_d_dd)(f))( pa[0]->to_r(i), pa[1]->to_r(i) ); + ret->v[i] = (*(func_d_dd)(f))( pa[0]->to_r(i), pa[1]->to_r(i) ); else if ( tf->intypes=="ddd" ) for ( int i=0; i<n; ++i ) - v[i] = (*(func_d_ddd)(f))( pa[0]->to_r(i), pa[1]->to_r(i), pa[2]->to_r(i) ); + ret->v[i] = (*(func_d_ddd)(f))( pa[0]->to_r(i), pa[1]->to_r(i), pa[2]->to_r(i) ); else throw S("BUG: unexpected intypes"); - return PObjVecDble( new CObjVecDble( v ) ); + return ret; } else if ( tf->outtype=="e" ) { - vector<double> v(n), dv(n); + PObjVecEnu ret( new CObjVecEnu( n ) ); if ( tf->intypes=="e" ) for ( int i=0; i<n; ++i ) - (*(func_e_e)(f))( v[i], dv[i], pa[0]->to_r(i), pa[0]->to_dr(i) ); + (*(func_e_e)(f))( ret->v[i], ret->dv[i], pa[0]->to_r(i), pa[0]->to_dr(i) ); else if ( tf->intypes=="dd" ) for ( int i=0; i<n; ++i ) - (*(func_e_dd)(f))( v[i], dv[i], pa[0]->to_r(i), pa[1]->to_r(i) ); + (*(func_e_dd)(f))( ret->v[i], ret->dv[i], pa[0]->to_r(i), pa[1]->to_r(i) ); else if ( tf->intypes=="ee" ) for ( int i=0; i<n; ++i ) - (*(func_e_ee)(f))( v[i], dv[i], + (*(func_e_ee)(f))( ret->v[i], ret->dv[i], pa[0]->to_r(i), pa[0]->to_dr(i), pa[1]->to_r(i), pa[1]->to_dr(i) ); else if ( tf->intypes=="eee" ) for ( int i=0; i<n; ++i ) - (*(func_e_eee)(f))( v[i], dv[i], + (*(func_e_eee)(f))( ret->v[i], ret->dv[i], pa[0]->to_r(i), pa[0]->to_dr(i), pa[1]->to_r(i), pa[1]->to_dr(i), pa[2]->to_r(i), pa[2]->to_dr(i) ); else throw S("BUG: unexpected intypes"); - return PObjVecDble( new CObjVecDble( v, dv ) ); + return ret; } else throw S("BUG: unexpected outtype"); } @@ -349,29 +349,29 @@ const RObj CNodeGeni::tree_val( const CContext& ctx ) const { try { if( ctx.dim!=CContext::_1 ) - throw "Unexpected vectorial context " + ctx.context_info(); + throw "Unexpected is_vec() context " + ctx.context_info(); CContext myctx(ctx); myctx.dim = CContext::_VI; myctx.nv = -1; - // Evaluate arguments, and determine size of vectorial arguments. + // Evaluate arguments, and determine size of is_vec() arguments. vector<RObj> pa(narg); - vector<RObjVecDble> pav(narg); + vector<RObjVecNum> pav(narg); int n=0; for ( int iarg=0; iarg<narg; ++iarg ) { pa[iarg] = arg[iarg]->tree_val( myctx ); - pav[iarg] = PCAST<const CObjVecDble>(pa[iarg]); + pav[iarg] = PCAST<const CObjVecNum>(pa[iarg]); if( !pav[iarg] ) throw "argument " + S(iarg) + " of generalized integral " + tree_info() + " is scalar: " + pa[iarg]->result_info(); if ( n==0 ) - n = pav[iarg]->v.size(); - else if ( pav[iarg]->v.size() != n ) + n = pav[iarg]->size(); + else if ( pav[iarg]->size() != n ) throw string("vector arguments have different size"); } // Now evaluate the function. double val; geni->eval( &val, NULL, n, pav ); // TODO: compute errors - return PObjDbl( new CObjDbl( val ) ); + return RObjDbl( new CObjDbl( val ) ); } catch( string& ex ) { throw ex+" in NodeGeni "+tree_info()+" {context="+ctx.context_info()+"}"; @@ -449,7 +449,7 @@ const RObj CNodeCvin::tree_val( const CContext& ctx ) const { try { if( ctx.dim!=CContext::_1 ) - throw "Unexpected vectorial context " + ctx.context_info(); + throw "Unexpected is_vec() context " + ctx.context_info(); CContext myctx(ctx); myctx.dim = CContext::_1; // Evaluate arguments. @@ -640,34 +640,70 @@ const RObj CNodeIva::tree_val( const CContext& ctx ) const if ( ref->ti ) { CContext myctx = ctx; myctx.dim = CContext::_1; - PObjVecDble pret( new CObjVecDble( - ctx.nv, var->typ == CVar::_Y && ctx.want_error) ); - for( int ii=0; ii<ctx.nv; ++ii ){ - myctx.i = ii; - int j = ref->get_j( myctx, f->nJ() ); - PSpec sj = fd->VS(j); - int i = ref->ti->tree_val_idx( myctx ); - if( i >= sj->size() ) - throw "i="+S(i)+" while there are only ni="+S(sj->size())+" points"; - if ( var->typ == CVar::_I ) { + if ( var->typ == CVar::_I ) { + PObjVecInt pret( new CObjVecInt( ctx.nv ) ); + for ( int ii=0; ii<ctx.nv; ++ii ) { + myctx.i = ii; + int i = ref->ti->tree_val_idx( myctx ); pret->v[ii] = i; - } else if ( var->typ == CVar::_X ) { - pret->v[ii] = sj->x[i]; - } else if ( var->typ == CVar::_Y ) { + } + return pret; + } else if ( var->typ == CVar::_Y && ctx.want_error ) { + PObjVecEnu pret( new CObjVecEnu( ctx.nv ) ); + for ( int ii=0; ii<ctx.nv; ++ii ) { + myctx.i = ii; + int j = ref->get_j( myctx, f->nJ() ); + RSpec sj = fd->VS(j); + int i = ref->ti->tree_val_idx( myctx ); + if( i >= sj->size() ) + throw "i="+S(i)+" while there are only" + " ni="+S(sj->size())+" points"; pret->v[ii] = sj->y[i]; - if( pret->dv.size() ){ - if ( sj->dy.size() >= pret->dv.size() ) - pret->dv[ii] = sj->dy[i]; - else - pret->dv.clear(); - } - } else if ( var->typ == CVar::_DY ) { - if( !sj->dy.size() ) - throw string("dy not set"); pret->v[ii] = sj->dy[i]; } - } - return pret; + return pret; + } else if ( var->typ == CVar::_Y ) { + PObjVecDbl pret( new CObjVecDbl( ctx.nv ) ); + for ( int ii=0; ii<ctx.nv; ++ii ) { + myctx.i = ii; + int j = ref->get_j( myctx, f->nJ() ); + RSpec sj = fd->VS(j); + int i = ref->ti->tree_val_idx( myctx ); + if( i >= sj->size() ) + throw "i="+S(i)+" while there are only" + " ni="+S(sj->size())+" points"; + pret->v[ii] = sj->y[i]; + } + return pret; + } else if ( var->typ == CVar::_X ) { + PObjVecDbl pret( new CObjVecDbl( ctx.nv ) ); + for ( int ii=0; ii<ctx.nv; ++ii ) { + myctx.i = ii; + int j = ref->get_j( myctx, f->nJ() ); + RSpec sj = fd->VS(j); + int i = ref->ti->tree_val_idx( myctx ); + if( i >= sj->size() ) + throw "i="+S(i)+" while there are only" + " ni="+S(sj->size())+" points"; + pret->v[ii] = sj->x[i]; + } + return pret; + } else if ( var->typ == CVar::_DY ) { + PObjVecDbl pret( new CObjVecDbl( ctx.nv ) ); + for ( int ii=0; ii<ctx.nv; ++ii ) { + myctx.i = ii; + int j = ref->get_j( myctx, f->nJ() ); + RSpec sj = fd->VS(j); + int i = ref->ti->tree_val_idx( myctx ); + if( i >= sj->size() ) + throw "i="+S(i)+" while there are only" + " ni="+S(sj->size())+" points"; + pret->v[ii] = sj->dy[i]; + } + return pret; + } else + throw S("BUG: unexpected case"); + return NULL; } else { int j = ref->get_j( ctx, f->nJ() ); @@ -679,19 +715,19 @@ const RObj CNodeIva::tree_val( const CContext& ctx ) const throw "ref_val "+var->var_info()+": requested vec("+S(ctx.nv)+ "), found vec("+S( sj->size() ); if ( var->typ == CVar::_I ) { - PObjVecDble pret( new CObjVecDble( nv, false ) ); + PObjVecInt pret( new CObjVecInt( nv ) ); for( int i=0; i<nv; ++i ) - PCAST<CObjVecDble>(pret)->v[i] = i; + pret->v[i] = i; return pret; } else if ( var->typ == CVar::_X ) { - return RObjVecDble( new CObjVecDble( sj->x ) ); + return RObjVecDbl( new CObjVecDbl( sj->x ) ); } else if ( var->typ == CVar::_Y ) { if ( ctx.want_error ) - return RObjVecDble( new CObjVecDble( sj->y, sj->dy ) ); + return RObjVecEnu( new CObjVecEnu( sj->y, sj->dy ) ); else - return RObjVecDble( new CObjVecDble( sj->y ) ); + return RObjVecDbl( new CObjVecDbl( sj->y ) ); } else if ( var->typ == CVar::_DY ) { - return RObjVecDble( new CObjVecDble( sj->dy ) ); + return RObjVecDbl( new CObjVecDbl( sj->dy ) ); } else throw S("BUG: unexpected case"); } @@ -844,7 +880,7 @@ const RObj CNodeDummy::tree_val( const CContext& ctx ) const { if ( !(ctx.vt) ) throw "BUG: tree_val with *vt=0"; - PObjVecDble pret( new CObjVecDble( *(ctx.vt) ) ); + RObjVecDbl pret( new CObjVecDbl( *(ctx.vt) ) ); return pret; } @@ -877,13 +913,17 @@ const RObj CNodeCev::tree_val( const CContext& ctx ) const RObj farg = arg->tree_val( ctx ); // evaluate the curve: - if ( RObjVecDble pav = PCAST<const CObjVecDble>(farg) ) { - PObjVecDble pret( new CObjVecDble( pav->v.size(), ctx.want_error ) ); - fc->curve_val_vec( &(PCAST<CObjVecDble>(pret)->v), - ctx.want_error? &(PCAST<CObjVecDble>(pret)->dv) : NULL, - pav->v, k, j ); - return pret; - } else if ( RObjNumber par = PCAST<const CObjNumber>(farg) ) { + if ( RObjVecDbl pav = PCAST<const CObjVecDbl>(farg) ) { + if ( ctx.want_error ) { + PObjVecEnu pret( new CObjVecEnu( pav->size() ) ); + fc->curve_val_vec( &(pret->v), &(pret->dv), pav->v, k, j ); + return pret; + } else { + PObjVecDbl pret( new CObjVecDbl( pav->size() ) ); + fc->curve_val_vec( &(pret->v), NULL, pav->v, k, j ); + return pret; + } + } else if ( RObjNum par = PCAST<const CObjNum>(farg) ) { double val, err; fc->curve_val_sca( &val, ctx.want_error? &err : NULL, par->to_r(), k, j ); return ctx.want_error ? @@ -907,7 +947,7 @@ const RObj CNodeMixin::tree_val( const CContext& ctx ) const { // Shift: RObj res_shift = shift->tree_val( ctx ); - RObjNumber par = PCAST<const CObjNumber>(res_shift); + RObjNum par = PCAST<const CObjNum>(res_shift); if( !par ) throw S("shift is not a scalar"); double theshift = par->to_r(); @@ -917,7 +957,7 @@ const RObj CNodeMixin::tree_val( const CContext& ctx ) const PSpec sv; NCurveFile::getConv( &sv, &kconv, &jconv, ctx.k, ctx.j ); - PObjVecDble pret( new CObjVecDble ); + PObjVecDbl pret( ctx.want_error ? (new CObjVecDbl) : (new CObjVecEnu) ); if ( kconv==-1 ) { copy_theory( pret, ctx, theshift ); @@ -956,14 +996,14 @@ void CNodeConvBase::npar_exec( int *np ) const //* CNodeConv: convoluted function node //************************************************************************************************** -void CNodeConv::copy_theory( PObjVecDble& ret, const CContext& ctx, double theshift ) const +void CNodeConv::copy_theory( PObjVecDbl& ret, const CContext& ctx, double theshift ) const { RObj res_theory = theory->tree_val( ctx ); for ( int i=0; i<ctx.vt->size(); ++i ) ret->v[i] = res_theory->to_r(i); } -void CNodeConv::convolve( PObjVecDble& ret, const CContext& ctx, +void CNodeConv::convolve( PObjVecDbl& ret, const CContext& ctx, double theshift, const PSpec& sv, double conv_norm, double conv_step ) const { @@ -972,9 +1012,9 @@ void CNodeConv::convolve( PObjVecDble& ret, const CContext& ctx, CContext cv_ctx(ctx); vector<double> tt; // theory grid cv_ctx.vt = &tt; - bool with_error = ctx.want_error && sv->dy.size(); - if( with_error ) { - if( ret->dv.size()!=n ) + PObjVecEnu dret = PCAST<CObjVecEnu>(ret); + if( dret ) { + if( dret->dv.size()!=n ) throw S("BUG: convolve: bad #dv"); if( sv->dy.size()!=n ) throw S("BUG: convolve: bad #dy"); @@ -991,21 +1031,21 @@ void CNodeConv::convolve( PObjVecDble& ret, const CContext& ctx, // now convolve for ( int i=0; i<n; ++i ){ ret->v[i] = 0; - if( with_error ) - ret->dv[i] = 0; + if( dret ) + dret->dv[i] = 0; for ( int iv=0; iv<nv; ++iv ) { ret->v[i] += res_theory->to_r(nv-1+i-iv) * sv->y[iv]; - if( with_error ) - ret->dv[i] += res_theory->to_r(nv-1+i-iv) * SQR(sv->dy[iv]); + if( dret ) + dret->dv[i] += res_theory->to_r(nv-1+i-iv) * SQR(sv->dy[iv]); } ret->v[i] *= conv_step / conv_norm; - if( with_error ) - ret->dv[i] = sqrt(ret->dv[i]) * conv_step / conv_norm; + if( dret ) + dret->dv[i] = sqrt(dret->dv[i]) * conv_step / conv_norm; } } else { // simplest version: non-equidistant x_out and x_res. ret->v.assign( n, 0. ); - if( with_error ) - ret->dv.assign( n, 0. ); + if( dret ) + dret->dv.assign( n, 0. ); tt.resize(n); for ( int iv=0; iv<nv; ++iv ) { double dx; // variable step @@ -1020,14 +1060,14 @@ void CNodeConv::convolve( PObjVecDble& ret, const CContext& ctx, RObj res_theory = theory->tree_val( cv_ctx ); for ( int i=0; i<n; ++i ) { ret->v[i] += res_theory->to_r(i) * sv->y[iv] * dx; - if( with_error ) - ret->dv[i] += res_theory->to_r(i) * SQR(sv->dy[iv]); + if( dret ) + dret->dv[i] += res_theory->to_r(i) * SQR(sv->dy[iv]); } } for ( int i=0; i<n; ++i ) { ret->v[i] /= conv_norm; - if( with_error ) - ret->dv[i] = sqrt(ret->dv[i])/conv_norm; + if( dret ) + dret->dv[i] = sqrt(dret->dv[i])/conv_norm; } } } @@ -1037,14 +1077,14 @@ void CNodeConv::convolve( PObjVecDble& ret, const CContext& ctx, //* CNodePConv: convolution with primitive //************************************************************************************************** -void CNodePConv::copy_theory( PObjVecDble& ret, const CContext& ctx, double theshift ) const +void CNodePConv::copy_theory( PObjVecDbl& ret, const CContext& ctx, double theshift ) const { throw "non-convolution not implemented for pconv"; // to implement this efficiently, I would like to have CObj::operator+ // for which we should go to shared pointers ... } -void CNodePConv::convolve( PObjVecDble& ret, const CContext& ctx, double theshift, +void CNodePConv::convolve( PObjVecDbl& ret, const CContext& ctx, double theshift, const PSpec& sv, double conv_norm, double conv_step ) const { int n = ctx.vt->size(); @@ -1052,9 +1092,9 @@ void CNodePConv::convolve( PObjVecDble& ret, const CContext& ctx, double theshif CContext cv_ctx(ctx); vector<double> tt; cv_ctx.vt = &tt; - bool with_error = ctx.want_error && sv->dy.size(); - if( with_error ) { - if( ret->dv.size()!=n ) + PObjVecEnu dret = PCAST<CObjVecEnu>(ret); + if( dret ) { + if( dret->dv.size()!=n ) throw "BUG: convolve: bad #dv"; if( sv->dy.size()!=n ) throw "BUG: convolve: bad #dy"; @@ -1071,17 +1111,17 @@ void CNodePConv::convolve( PObjVecDble& ret, const CContext& ctx, double theshif // now convolve resolution with differential of primitive for ( int i=0; i<n; ++i ){ ret->v[i] = 0; - if( with_error ) - ret->dv[i] = 0; + if( dret ) + dret->dv[i] = 0; for ( int iv=0; iv<nv; ++iv ) { double igral = res_theory->to_r(nv +i-iv) - res_theory->to_r(nv-1+i-iv); ret->v[i] += igral * sv->y[iv]; - if( with_error ) - ret->dv[i] += igral * SQR(sv->dy[iv]); + if( dret ) + dret->dv[i] += igral * SQR(sv->dy[iv]); } ret->v[i] /= conv_norm; - if( with_error ) - ret->dv[i] = sqrt(ret->dv[i]) / conv_norm; + if( dret ) + dret->dv[i] = sqrt(dret->dv[i]) / conv_norm; } } else { // simplest version: non-equidistant x_out and x_res. throw S("PCONV BROKEN"); @@ -1141,14 +1181,14 @@ void CNodeDirac::npar_exec( int *np ) const //! Convolution or Dirac function: conv(f, shift), dirac(shift). -void CNodeDirac::convolve( PObjVecDble& ret, const CContext& ctx, +void CNodeDirac::convolve( PObjVecDbl& ret, const CContext& ctx, double theshift, const PSpec& sv, double conv_norm, double conv_step ) const { int n = ctx.vt->size(); - bool with_error = ctx.want_error && sv->dy.size(); - if( with_error ) { - if( ret->dv.size()!=n ) + PObjVecEnu dret = PCAST<CObjVecEnu>(ret); + if( dret ) { + if( dret->dv.size()!=n ) throw S("BUG: convolve: bad #dv"); if( sv->dy.size()!=n ) throw S("BUG: convolve: bad #dy"); @@ -1160,20 +1200,19 @@ void CNodeDirac::convolve( PObjVecDble& ret, const CContext& ctx, tt[i] = (*(ctx.vt))[i]-theshift; // interpolation try { - sv->intpol( tt, &yy, with_error ? &dd : NULL ); + sv->intpol( tt, &yy, dret ? &dd : NULL ); } catch( string& s ) { throw "error while evaluating delta function with shift "+S(theshift)+": "+s; } // normalization for ( int i=0; i<n; ++i ) { ret->v[i] = yy[i] / conv_norm; - if( with_error ) - ret->dv[i] = dd[i] / conv_norm; + if( dret ) + dret->dv[i] = dd[i] / conv_norm; } } -void CNodeDirac::copy_theory( PObjVecDble& ret, const CContext& ctx, - double theshift ) const +void CNodeDirac::copy_theory( PObjVecDbl& ret, const CContext& ctx, double theshift ) const { // Naive representation of delta function, // for use when convolution is switched off. diff --git a/pub/lib/node.hpp b/pub/lib/node.hpp index bf814907..af264ec0 100644 --- a/pub/lib/node.hpp +++ b/pub/lib/node.hpp @@ -193,8 +193,8 @@ class CNodeMixin: public CNode { public: CNodeMixin( const PNode& _shift ) : shift(_shift) {} const RObj tree_val( const CContext& ctx ) const; - virtual void copy_theory( PObjVecDble& ret, const CContext& ctx, double theshift ) const =0; - virtual void convolve( PObjVecDble& ret, const CContext& ctx, double theshift, + virtual void copy_theory( PObjVecDbl& ret, const CContext& ctx, double theshift ) const =0; + virtual void convolve( PObjVecDbl& ret, const CContext& ctx, double theshift, const PSpec& sv, double conv_norm, double conv_step ) const =0; bool has_conv() const { return true; } }; @@ -220,8 +220,8 @@ class CNodeConv: public CNodeConvBase { public: CNodeConv( const PNode& _theory, const PNode& _shift=PNode( new CNodeVal( 0.0 ) ) ) : CNodeConvBase( _theory, _shift ) {} - void copy_theory( PObjVecDble& ret, const CContext& ctx, double theshift ) const; - void convolve( PObjVecDble& ret, const CContext& ctx, double theshift, + void copy_theory( PObjVecDbl& ret, const CContext& ctx, double theshift ) const; + void convolve( PObjVecDbl& ret, const CContext& ctx, double theshift, const PSpec& sv, double conv_norm, double conv_step ) const; string tree_info() const { return "conv(" + theory->tree_info() +","+ shift->tree_info() + ")"; } @@ -234,8 +234,8 @@ class CNodePConv: public CNodeConvBase { public: CNodePConv( const PNode& _theory, const PNode& _shift=PNode( new CNodeVal( 0.0 ) ) ) : CNodeConvBase( _theory, _shift ) {}; - void copy_theory( PObjVecDble& ret, const CContext& ctx, double theshift ) const; - void convolve( PObjVecDble& ret, const CContext& ctx, double theshift, + void copy_theory( PObjVecDbl& ret, const CContext& ctx, double theshift ) const; + void convolve( PObjVecDbl& ret, const CContext& ctx, double theshift, const PSpec& sv, double conv_norm, double conv_step ) const; string tree_info() const { return "pconv(" + theory->tree_info() +","+ shift->tree_info() + ")"; } @@ -250,8 +250,8 @@ class CNodeDirac: public CNodeMixin { public: CNodeDirac( const PNode& _shift=PNode( new CNodeVal( 0.0 ) ) ) : CNodeMixin( _shift ) {}; - void copy_theory( PObjVecDble& ret, const CContext& ctx, double theshift ) const; - void convolve( PObjVecDble& ret, const CContext& ctx, double theshift, + void copy_theory( PObjVecDbl& ret, const CContext& ctx, double theshift ) const; + void convolve( PObjVecDbl& ret, const CContext& ctx, double theshift, const PSpec& sv, double conv_norm, double conv_step ) const; bool has_dummy() const { return true; } // has implicit t dependence bool has_conv() const { return true; } diff --git a/pub/lib/obj.cpp b/pub/lib/obj.cpp index 7024dd28..3f0531b9 100644 --- a/pub/lib/obj.cpp +++ b/pub/lib/obj.cpp @@ -80,23 +80,58 @@ string CObjEnu::result_info() const //************************************************************************************************** -// CObjVecDble +// CObjVecInt //************************************************************************************************** //! Returns string representation. -string CObjVecDble::to_s() const +string CObjVecInt::to_s() const { - return "["+S(v.size())+"entries "+(dv.size()?"with":"without")+" errors]"; + return "["+S(size())+" integer entries]"; } //! Returns textual representation of the class instance, for debugging. -string CObjVecDble::result_info() const +string CObjVecInt::result_info() const { - if( !v.size() ) - return "CObjVecDble(no values assigned)"; - else - return "CObjVecDble["+S(v.size())+"entries "+(dv.size()?"with":"without")+" errors]"; + return to_s(); +} + +//************************************************************************************************** +// CObjVecDbl +//************************************************************************************************** + + +//! Returns string representation. + +string CObjVecDbl::to_s() const +{ + return "["+S(size())+" floating-point entries]"; +} + +//! Returns textual representation of the class instance, for debugging. + +string CObjVecDbl::result_info() const +{ + return to_s(); +} + +//************************************************************************************************** +// CObjVecEnu +//************************************************************************************************** + + +//! Returns string representation. + +string CObjVecEnu::to_s() const +{ + return "["+S(size())+" floating-point entries with errors]"; +} + +//! Returns textual representation of the class instance, for debugging. + +string CObjVecEnu::result_info() const +{ + return to_s(); } diff --git a/pub/lib/obj.hpp b/pub/lib/obj.hpp index 82dd66b6..d2b6d580 100644 --- a/pub/lib/obj.hpp +++ b/pub/lib/obj.hpp @@ -11,11 +11,9 @@ class CObj { public: - bool vectorial; //!< Is it a vector? - - CObj( bool _vectorial ) : vectorial(_vectorial) {}; virtual ~CObj() {}; + virtual bool is_vec() const =0; virtual bool has_err() const =0; virtual char base_type() const =0; virtual string result_info() const =0; @@ -37,17 +35,19 @@ class CObj { //! Data container holding a single number; virtual base class for CObjInt, CObjDble. -class CObjNumber : public CObj { +class CObjNum : public CObj { public: - CObjNumber() : CObj(false) {}; + CObjNum() : CObj() {}; + bool is_vec() const { return false; }; + double to_dr() const { return 0.; } ; }; //! Data container holding a single integer number. -class CObjInt : public CObjNumber { +class CObjInt : public CObjNum { public: int val; //!< Scalar value. - CObjInt( int _val ) : CObjNumber(), val(_val) {}; + CObjInt( int _val ) : CObjNum(), val(_val) {}; bool has_err() const { return false; }; char base_type() const { return 'i'; }; string result_info() const { return "CObjInt("+S(val)+")"; }; @@ -56,24 +56,22 @@ class CObjInt : public CObjNumber { double to_dr( int i ) const { return 0. ; }; int to_i() const { return val; }; double to_r() const { return val; }; - double to_dr() const { return 0.; } ; string to_s() const; bool to_b() const { return val; }; }; //! Data container holding a single floating-point number. -class CObjDbl : public CObjNumber { +class CObjDbl : public CObjNum { public: double val; //!< Scalar value. - CObjDbl( double _val=NAN ) : CObjNumber(), val(_val) {}; + CObjDbl( double _val=NAN ) : CObjNum(), val(_val) {}; bool has_err() const { return false; }; char base_type() const { return 'd'; }; string result_info() const; double to_r( int i ) const { return val; }; double to_dr( int i ) const { return 0.; } ; double to_r() const { return val; }; - double to_dr() const { return 0.; } ; string to_s() const; bool to_b() const { return val; }; }; @@ -101,7 +99,8 @@ class CObjEnu : public CObjDbl { class CObjStr : public CObj { public: string val; - CObjStr( string _val ) : CObj(false), val(_val) {}; + CObjStr( string _val ) : CObj(), val(_val) {}; + bool is_vec() const { return false; }; bool has_err() const { return false; }; char base_type() const { return 's'; }; string result_info() const { return "CObjStr("+val+")"; }; @@ -114,25 +113,63 @@ class CObjStr : public CObj { class CObjVec : public CObj { public: - CObjVec() : CObj(true) {}; + CObjVec() : CObj() {}; + bool is_vec() const { return true; }; +}; + +//! Data container holding a vector of numbers. + +class CObjVecNum : public CObjVec { + public: + CObjVecNum() : CObjVec() {}; + double to_dr( int i ) const { return 0; } ; +}; + + +//! Data container holding a vector of integer numbers. + +class CObjVecInt : public CObjVecNum { + public: + vector<int> v; //!< The data. + CObjVecInt( int n=0 ) : CObjVecNum(), v(n,-1) {}; + CObjVecInt( const vector<int>& _v ) : CObjVecNum(), v(_v) {}; + bool has_err() const { return false; }; + char base_type() const { return 'i'; }; + string result_info() const; + int to_i( int i ) const { return v[i]; }; + double to_r( int i ) const { return v[i]; }; + string to_s() const; + bool to_b() const { return v.size(); }; + int size() const { return v.size(); }; }; //! Data container holding a vector of floating-point numbers. -class CObjVecDble : public CObjVec { +class CObjVecDbl : public CObjVecNum { public: vector<double> v; //!< Resulting vector. - vector<double> dv; //!< Errors of vectorial result. - CObjVecDble() : CObjVec() {}; - CObjVecDble( int _n, bool _with_err ) : CObjVec() { v.resize(_n); dv.resize(_with_err?_n:0); }; - CObjVecDble( const vector<double>& _v ) : CObjVec(), v(_v) {}; - CObjVecDble( const vector<double>& _v, const vector<double>& _dv ) - : CObjVec(), v(_v), dv(_dv) {}; - bool has_err() const { return dv.size(); }; - char base_type() const { return has_err() ? 'e' : 'd'; }; + CObjVecDbl( int n=0 ) : CObjVecNum(), v(n,NAN) {}; + CObjVecDbl( const vector<double>& _v ) : CObjVecNum(), v(_v) {}; + bool has_err() const { return false; }; + char base_type() const { return 'd'; }; string result_info() const; double to_r( int i ) const { return v[i]; }; - double to_dr( int i ) const { return dv.size() ? dv[i] : 0; } ; + string to_s() const; + bool to_b() const { return v.size(); }; + int size() const { return v.size(); }; +}; + +//! Data container holding a vector of floating-point numbers. + +class CObjVecEnu : public CObjVecDbl { + public: + vector<double> dv; //!< Errors. + CObjVecEnu( int n=0 ) : CObjVecDbl( n ), dv(n,NAN) {}; + CObjVecEnu( const vector<double>& _v, const vector<double>& _dv ) : CObjVecDbl(_v), dv(_dv) {}; + bool has_err() const { return true; }; + char base_type() const { return 'e'; }; + string result_info() const; + double to_dr( int i ) const { return dv[i]; } ; string to_s() const; bool to_b() const { return v.size(); }; int size() const { return v.size(); }; diff --git a/pub/lib/olf.cpp b/pub/lib/olf.cpp index f24a81ef..91596283 100644 --- a/pub/lib/olf.cpp +++ b/pub/lib/olf.cpp @@ -368,7 +368,7 @@ void COlc::curve_val_vec_expr( vector<double>* v, vector<double>* dv, throw "BUG: inconsistent call of curve_val_vec_expr"; if ( !T->has_dummy() ) { // curve does not depend on t val = T->tree_val( ctx ); - if ( RObjNumber pr = PCAST<const CObjNumber>(val) ) { + if ( RObjNum pr = PCAST<const CObjNum>(val) ) { for( int i=0; i<v->size(); ++i ) { (*v)[i] = pr->to_r(); if( dv ) @@ -379,10 +379,10 @@ void COlc::curve_val_vec_expr( vector<double>* v, vector<double>* dv, } else { ctx.request_VT( &vt ); val = T->tree_val( ctx ); - if ( RObjVecDble pv = PCAST<const CObjVecDble>(val) ) { + if ( RObjVecDbl pv = PCAST<const CObjVecDbl>(val) ) { *v = pv->v; if( dv ) - *dv = pv->dv; + *dv = PCAST<const CObjVecEnu>(val)->dv; } else throw "BUG: tree_curve_val did not get vectorial result"; } diff --git a/pub/lib/ptr.hpp b/pub/lib/ptr.hpp index cf2aab32..a1cf0234 100644 --- a/pub/lib/ptr.hpp +++ b/pub/lib/ptr.hpp @@ -15,17 +15,20 @@ typedef boost::shared_ptr< class Class> Ptr; \ typedef boost::shared_ptr<const class Class> Ref -DEF_PTR( COlo, POlo, ROlo ); -DEF_PTR( COlc, POlc, ROlc ); -DEF_PTR( COld, POld, ROld ); -DEF_PTR( CSlice, PSlice, RSlice ); -DEF_PTR( CSpec, PSpec, RSpec ); -DEF_PTR( CCurve, PCurve, RCurve ); -DEF_PTR( CObj, PObj, RObj ); -DEF_PTR( CObjNumber,PObjNumber,RObjNumber ); -DEF_PTR( CObjInt, PObjInt, RObjInt ); -DEF_PTR( CObjDbl, PObjDbl, RObjDbl ); -DEF_PTR( CObjEnu, PObjEnu, RObjEnu ); -DEF_PTR( CObjStr, PObjStr, RObjStr ); -DEF_PTR( CObjVecDble, PObjVecDble, RObjVecDble ); -DEF_PTR( CNode, PNode, RNode ); +DEF_PTR( COlo, POlo, ROlo ); +DEF_PTR( COlc, POlc, ROlc ); +DEF_PTR( COld, POld, ROld ); +DEF_PTR( CSlice, PSlice, RSlice ); +DEF_PTR( CSpec, PSpec, RSpec ); +DEF_PTR( CCurve, PCurve, RCurve ); +DEF_PTR( CObj, PObj, RObj ); +DEF_PTR( CObjNum, PObjNum, RObjNum ); +DEF_PTR( CObjInt, PObjInt, RObjInt ); +DEF_PTR( CObjDbl, PObjDbl, RObjDbl ); +DEF_PTR( CObjEnu, PObjEnu, RObjEnu ); +DEF_PTR( CObjStr, PObjStr, RObjStr ); +DEF_PTR( CObjVecNum, PObjVecNum, RObjVecNum ); +DEF_PTR( CObjVecInt, PObjVecInt, RObjVecInt ); +DEF_PTR( CObjVecDbl, PObjVecDbl, RObjVecDbl ); +DEF_PTR( CObjVecEnu, PObjVecEnu, RObjVecEnu ); +DEF_PTR( CNode, PNode, RNode ); -- GitLab