00001
00002
00003
00004
00005 #include "transform.h"
00006 #include "logic.h"
00007 #include "lexer.h"
00008 #include "data.h"
00009
00010 using namespace std;
00011
00012 namespace {
00013
00014 struct DtStackItem
00015 {
00016 bool is_num;
00017 realt num;
00018 vector<Point> points;
00019 string title;
00020 };
00021
00022 realt find_extrapolated_y(vector<Point> const& pp, realt x)
00023 {
00024 if (pp.empty())
00025 return 0;
00026 else if (x <= pp.front().x)
00027 return pp.front().y;
00028 else if (x >= pp.back().x)
00029 return pp.back().y;
00030 vector<Point>::const_iterator i = lower_bound(pp.begin(), pp.end(),
00031 Point(x, 0));
00032 assert (i > pp.begin() && i < pp.end());
00033 if (is_eq(x, i->x))
00034 return i->y;
00035 else
00036 return (i-1)->y + (i->y - (i-1)->y) * (i->x - x) / (i->x - (i-1)->x);
00037 }
00038
00039 void merge_same_x(vector<Point> &pp, bool avg)
00040 {
00041 int count_same = 1;
00042 double x0 = 0;
00043 for (int i = pp.size() - 2; i >= 0; --i) {
00044 if (count_same == 1)
00045 x0 = pp[i+1].x;
00046 if (is_eq(pp[i].x, x0)) {
00047 pp[i].x += pp[i+1].x;
00048 pp[i].y += pp[i+1].y;
00049 pp[i].sigma += pp[i+1].sigma;
00050 pp[i].is_active = pp[i].is_active || pp[i+1].is_active;
00051 pp.erase(pp.begin() + i+1);
00052 count_same++;
00053 if (i > 0)
00054 continue;
00055 else
00056 i = -1;
00057 }
00058 if (count_same > 1) {
00059 pp[i+1].x /= count_same;
00060 if (avg) {
00061 pp[i+1].y /= count_same;
00062 pp[i+1].sigma /= count_same;
00063 }
00064 count_same = 1;
00065 }
00066 }
00067 }
00068
00069 void shirley_bg(vector<Point> &pp)
00070 {
00071 const int max_iter = 50;
00072 const double max_rdiff = 1e-6;
00073 const int n = pp.size();
00074 double ya = pp[0].y;
00075 double yb = pp[n-1].y;
00076 double dy = yb - ya;
00077 vector<double> B(n, ya);
00078 vector<double> PA(n, 0.);
00079 double old_A = 0;
00080 for (int iter = 0; iter < max_iter; ++iter) {
00081 vector<double> Y(n);
00082 for (int i = 0; i < n; ++i)
00083 Y[i] = pp[i].y - B[i];
00084 for (int i = 1; i < n; ++i)
00085 PA[i] = PA[i-1] + (Y[i] + Y[i-1]) / 2 * (pp[i].x - pp[i-1].x);
00086 double rel_diff = old_A != 0. ? fabs(PA[n-1] - old_A) / old_A : 1.;
00087 if (rel_diff < max_rdiff)
00088 break;
00089 old_A = PA[n-1];
00090 for (int i = 0; i < n; ++i)
00091 B[i] = ya + dy / PA[n-1] * PA[i];
00092 }
00093 for (int i = 0; i < n; ++i)
00094 pp[i].y = B[i];
00095 }
00096
00097 }
00098
00099
00100
00101 void DatasetTransformer::run_dt(const VMData& vm, int out)
00102 {
00103 DtStackItem stack[6];
00104 DtStackItem* stackPtr = stack - 1;
00105
00106 v_foreach (int, i, vm.code()) {
00107 switch (*i) {
00108
00109 case OP_NUMBER:
00110 stackPtr += 1;
00111 if (stackPtr - stack >= 6)
00112 throw ExecuteError("stack overflow");
00113 i++;
00114 stackPtr->is_num = true;
00115 stackPtr->num = vm.numbers()[*i];
00116 break;
00117
00118 case OP_DATASET:
00119 stackPtr += 1;
00120 if (stackPtr - stack >= 6)
00121 throw ExecuteError("stack overflow");
00122 stackPtr->is_num = false;
00123 i++;
00124 stackPtr->points = F_->get_data(*i)->points();
00125 stackPtr->title = F_->get_data(*i)->get_title();
00126 if (stackPtr->title.empty())
00127 stackPtr->title = "nt";
00128 break;
00129
00130 case OP_NEG:
00131 if (stackPtr->is_num)
00132 stackPtr->num = -stackPtr->num;
00133 else {
00134 vm_foreach (Point, j, stackPtr->points)
00135 j->y = -j->y;
00136 stackPtr->title = "-" + stackPtr->title;
00137 }
00138 break;
00139
00140 case OP_ADD:
00141 stackPtr -= 1;
00142 if (stackPtr->is_num && (stackPtr+1)->is_num)
00143 stackPtr->num += (stackPtr+1)->num;
00144 else if (!stackPtr->is_num && !(stackPtr+1)->is_num) {
00145 vm_foreach (Point, j, stackPtr->points)
00146 j->y += find_extrapolated_y((stackPtr+1)->points, j->x);
00147 stackPtr->title += "+" + (stackPtr+1)->title;
00148 }
00149 else
00150 throw ExecuteError("adding number and dataset");
00151 break;
00152
00153 case OP_SUB:
00154 stackPtr -= 1;
00155 if (stackPtr->is_num && (stackPtr+1)->is_num)
00156 stackPtr->num -= (stackPtr+1)->num;
00157 else if (!stackPtr->is_num && !(stackPtr+1)->is_num) {
00158 vm_foreach (Point, j, stackPtr->points)
00159 j->y -= find_extrapolated_y((stackPtr+1)->points, j->x);
00160 stackPtr->title += "-" + (stackPtr+1)->title;
00161 }
00162 else
00163 throw ExecuteError("substracting number and dataset");
00164 break;
00165
00166 case OP_MUL:
00167 stackPtr -= 1;
00168 if (stackPtr->is_num && (stackPtr+1)->is_num)
00169 stackPtr->num *= (stackPtr+1)->num;
00170 else if (!stackPtr->is_num && !(stackPtr+1)->is_num) {
00171 throw ExecuteError("multiplying two datasets");
00172 }
00173 else if (!stackPtr->is_num && (stackPtr+1)->is_num) {
00174 realt mult = (stackPtr+1)->num;
00175 vm_foreach (Point, j, stackPtr->points)
00176 j->y *= mult;
00177 stackPtr->title += "*" + S(mult);
00178 }
00179 else if (stackPtr->is_num && !(stackPtr+1)->is_num) {
00180 realt mult = stackPtr->num;
00181 stackPtr->points.swap((stackPtr+1)->points);
00182 stackPtr->is_num = false;
00183 vm_foreach (Point, j, stackPtr->points)
00184 j->y *= mult;
00185 stackPtr->title = S(mult) + "*" + (stackPtr+1)->title;
00186 }
00187 break;
00188
00189 case OP_DT_SUM_SAME_X:
00190 if (stackPtr->is_num)
00191 throw ExecuteError(op2str(*i) + " is defined only for @n");
00192 merge_same_x(stackPtr->points, false);
00193 break;
00194
00195 case OP_DT_AVG_SAME_X:
00196 if (stackPtr->is_num)
00197 throw ExecuteError(op2str(*i) + " is defined only for @n");
00198 merge_same_x(stackPtr->points, true);
00199 break;
00200
00201 case OP_DT_SHIRLEY_BG:
00202 if (stackPtr->is_num)
00203 throw ExecuteError(op2str(*i) + " is defined only for @n");
00204 shirley_bg(stackPtr->points);
00205 break;
00206
00207 case OP_AND:
00208
00209 break;
00210
00211 case OP_AFTER_AND:
00212 stackPtr -= 1;
00213 if (stackPtr->is_num || (stackPtr+1)->is_num)
00214 throw ExecuteError("expected @n on both sides of `and'");
00215 stackPtr->points.insert(stackPtr->points.end(),
00216 (stackPtr+1)->points.begin(),
00217 (stackPtr+1)->points.end());
00218 sort(stackPtr->points.begin(), stackPtr->points.end());
00219 stackPtr->title += "&" + (stackPtr+1)->title;
00220 break;
00221
00222 default:
00223 throw ExecuteError("op " + op2str(*i) +
00224 " is not allowed in dataset transformations.");
00225 }
00226 }
00227 assert(stackPtr == stack);
00228
00229
00230 if (out == Lexer::kNew) {
00231 F_->append_dm();
00232 out = F_->get_dm_count() - 1;
00233 }
00234 Data *data = F_->get_data(out);
00235 if (!stackPtr->is_num) {
00236 data->set_points(stackPtr->points);
00237 data->set_title(stackPtr->title);
00238 }
00239 else if (stackPtr->num == 0.)
00240 data->clear();
00241 else
00242 throw ExecuteError("dataset or 0 expected on RHS");
00243 }
00244