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