@@ -30,7 +30,19 @@ GSL_SHELL = gsl-shell$(EXE_EXT) GSL_SHELL_GUI = gsl-shell-gui$(EXE_EXT) LUA_CFLAGS = -I$(LUADIR)/src -SUBDIRS = $(LUADIR) lua-gsl +ifeq ($(HOST_SYS),Windows) + INCLUDES += -I/usr/include + LIBS += -L/usr/lib -lsupc++ +else + ifeq ($(HOST_SYS),Darwin) + LDFLAGS += -L/usr/X11/lib -undefined dynamic_lookup -pagezero_size 10000 -image_base 100000000 + LIBS += -ldl -lreadline -lncurses + else + LIBS += -ldl -lreadline -lhistory -lncurses -lsupc++ + endif +endif + +SUBDIRS = $(LUADIR) lua-gsl gdt C_SRC_FILES = @@ -43,7 +55,7 @@ endif LUA_BASE_FILES = bspline.lua fft-init.lua integ-init.lua template.lua check.lua graph-init.lua rng.lua rnd.lua randist.lua iter.lua time.lua gsl-check.lua linfit.lua roots.lua contour.lua gsl.lua matrix.lua csv.lua gslext.lua num.lua demo-init.lua import.lua plot3d.lua sf.lua vegas.lua eigen.lua help.lua HELP_FILES = graphics matrix iter integ ode nlfit vegas rng fft -DEMOS_LIST = bspline fft plot wave-particle fractals ode nlinfit integ anim linfit contour svg graphics sf vegas +DEMOS_LIST = bspline fft plot wave-particle fractals ode nlinfit integ anim linfit contour svg graphics sf vegas gdt-lm LUA_TEMPLATES = gauss-kronrod-x-wgs qag rk8pd lmfit qng rkf45 ode-defs rk4 sf-defs vegas-defs LUA_BASE_FILES += $(DEMOS_LIST:%=demos/%.lua) @@ -64,7 +76,7 @@ SUBDIRS += agg-plot $(GUI_SUBDIR) LUAGSL_LIBS += agg-plot/libaggplot.a LIBS += $(AGG_LIBS) $(FREETYPE_LIBS) $(PTHREADS_LIBS) -LUAGSL_LIBS += lua-gsl/libluagsl.a +LUAGSL_LIBS += lua-gsl/libluagsl.a gdt/libgdt.a COMPILE = $(CC) $(CFLAGS) $(LUA_CFLAGS) $(DEFS) $(INCLUDES) @@ -111,6 +123,7 @@ clean: $(MAKE) -C agg-plot clean $(MAKE) -C $(LUADIR) clean $(MAKE) -C fox-gui clean + $(MAKE) -C gdt clean $(HOST_RM) *.o $(TARGETS) $(HOST_RM) -r ./.libs/ diff --git a/agg-plot/Makefile b/agg-plot/Makefile index f68b3cd8..5f2c1a48 100644 --- a/agg-plot/Makefile +++ b/agg-plot/Makefile @@ -39,7 +39,7 @@ endif INCLUDES += $(FREETYPE_INCLUDES) $(AGG_INCLUDES) -I$(GSH_BASE_DIR) -I$(GSH_BASE_DIR)/lua-gsl -I$(LUADIR)/src -I$(GSH_BASE_DIR)/cpp-utils -AGGPLOT_SRC_FILES = $(PLATSUP_SRC_FILES) printf_check.cpp fonts.cpp gamma.cpp agg_font_freetype.cpp utils.cpp units.cpp colors.cpp markers.cpp draw_svg.cpp canvas_svg.cpp lua-draw.cpp lua-text.cpp text.cpp agg-parse-trans.cpp window_registry.cpp window.cpp lua-plot.cpp canvas-window.cpp bitmap-plot.cpp lua-graph.cpp +AGGPLOT_SRC_FILES = $(PLATSUP_SRC_FILES) printf_check.cpp fonts.cpp gamma.cpp agg_font_freetype.cpp plot.cpp plot-auto.cpp utils.cpp units.cpp colors.cpp markers.cpp draw_svg.cpp canvas_svg.cpp lua-draw.cpp lua-text.cpp text.cpp agg-parse-trans.cpp window_registry.cpp window.cpp lua-plot.cpp canvas-window.cpp bitmap-plot.cpp lua-graph.cpp AGGPLOT_OBJ_FILES := $(AGGPLOT_SRC_FILES:%.cpp=%.o) diff --git a/agg-plot/factor_labels.h b/agg-plot/factor_labels.h new file mode 100644 index 00000000..27f6ef47 --- /dev/null +++ b/agg-plot/factor_labels.h @@ -0,0 +1,28 @@ +#include "agg_array.h" +#include "utils.h" +#include "strpp.h" + +class factor_labels +{ +public: + factor_labels(double delta): m_mark_delta(delta) {} + + double mark(int k) const { return m_mark_index[k] * m_mark_delta; } + const char *label_text(int k) const { return m_label_text[k]->cstr(); } + int labels_number() const { return m_label_text.size(); } + + void add_mark(int index, const char *text) + { + m_mark_index.add(index); + if (text) + { + str* text_str = new str(text); + m_label_text.add(text_str); + } + } + +private: + double m_mark_delta; + agg::pod_bvector<short> m_mark_index; + ptr_list<str> m_label_text; +}; diff --git a/agg-plot/lua-draw.cpp b/agg-plot/lua-draw.cpp index 7181dfb2..af6f69ad 100644 --- a/agg-plot/lua-draw.cpp +++ b/agg-plot/lua-draw.cpp @@ -263,17 +263,23 @@ marker_new (lua_State *L) { const double x = luaL_checknumber(L, 1); const double y = luaL_checknumber(L, 2); - const char *sym_name = luaL_optstring(L, 3, ""); const double size = luaL_optnumber(L, 4, 5.0); + const char *sym_name; - bool stroke; - sg_object* sym = new_marker_symbol_raw(sym_name, stroke); + if (lua_isnumber(L, 3)) + { + int n = lua_tointeger(L, 3); + sym_name = marker_lookup(n); + } + else + { + sym_name = luaL_optstring(L, 3, ""); + } + + sg_object* sym = new_marker_symbol_raw(sym_name); draw::marker* marker = new draw::marker(x, y, sym, size); - if (stroke) - new(L, GS_DRAW_MARKER) trans::stroke(marker); - else - new(L, GS_DRAW_MARKER) sg_object_ref<manage_owner>(marker); + new(L, GS_DRAW_MARKER) sg_object_ref<manage_owner>(marker); return 1; } diff --git a/agg-plot/lua-plot-cpp.h b/agg-plot/lua-plot-cpp.h index 5f92e499..0aa7bca4 100644 --- a/agg-plot/lua-plot-cpp.h +++ b/agg-plot/lua-plot-cpp.h @@ -10,7 +10,7 @@ extern "C" { #include "plot-auto.h" #include "resource-manager.h" -typedef plot<manage_owner> sg_plot; -typedef plot_auto<manage_owner> sg_plot_auto; +typedef plot sg_plot; +typedef plot_auto sg_plot_auto; #endif diff --git a/agg-plot/lua-plot.cpp b/agg-plot/lua-plot.cpp index 42961d46..5053dbaa 100644 --- a/agg-plot/lua-plot.cpp +++ b/agg-plot/lua-plot.cpp @@ -70,6 +70,8 @@ static int plot_ylab_angle_get (lua_State *L); static int plot_set_categories (lua_State *L); static int plot_set_legend (lua_State *L); static int plot_get_legend (lua_State *L); +static int plot_xaxis_hol_set (lua_State *L); +static int plot_xaxis_hol_clear(lua_State *L); static int plot_sync_mode_get (lua_State *L); static int plot_sync_mode_set (lua_State *L); @@ -109,6 +111,8 @@ static const struct luaL_Reg plot_methods[] = { {"set_categories", plot_set_categories}, {"set_legend", plot_set_legend}, {"get_legend", plot_get_legend}, + {"set_multi_labels", plot_xaxis_hol_set}, + {"clear_multi_labels", plot_xaxis_hol_clear}, {NULL, NULL} }; @@ -467,6 +471,56 @@ plot_units_get (lua_State *L) return plot_bool_property_get(L, &sg_plot::use_units); } +int plot_xaxis_hol_set (lua_State *L) +{ + sg_plot *p = object_check<sg_plot>(L, 1, GS_PLOT); + double delta = lua_tonumber(L, 2); + + if (!lua_istable(L, 3)) + return luaL_error(L, "expect labels table specification"); + + ptr_list<factor_labels>* hol = p->get_xaxis_hol(); + bool create_hol = (hol == 0); + if (create_hol) + hol = new ptr_list<factor_labels>(); + + factor_labels* fl = new factor_labels(delta); + int n = lua_objlen(L, 3); + for (int k = 1; k <= n; k += 2) + { + lua_rawgeti(L, 3, k); + int idx = lua_tonumber(L, -1); + lua_pop(L, 1); + + lua_rawgeti(L, 3, k + 1); + const char* str = lua_tostring(L, -1); + fl->add_mark(idx, str); + lua_pop(L, 1); + + if (!str) + break; + } + + AGG_LOCK(); + hol->add(fl); + if (create_hol) + p->set_xaxis_hol(hol); + AGG_UNLOCK(); + + plot_update_raw (L, p, 1); + return 0; +} + +int plot_xaxis_hol_clear (lua_State *L) +{ + sg_plot *p = object_check<sg_plot>(L, 1, GS_PLOT); + AGG_LOCK(); + p->set_xaxis_hol(0); + AGG_UNLOCK(); + plot_update_raw (L, p, 1); + return 0; +} + void plot_update_raw (lua_State *L, sg_plot *p, int plot_index) { diff --git a/agg-plot/markers.cpp b/agg-plot/markers.cpp index d6e5548c..b355bf12 100644 --- a/agg-plot/markers.cpp +++ b/agg-plot/markers.cpp @@ -8,141 +8,197 @@ #include "trans.h" #include "path.h" +/* used to encode a simple path */ +struct path_code { + enum {closed = 0, open = 1, end = 2}; + enum {scale = 32767}; + short x, y; +}; + struct symbol_reg { const char *name; - sg_object *(*builder)(bool&); + sg_object *(*builder)(); + const path_code* pcode; +}; + +static sg_object *build_circle(); +static sg_object *build_path(const path_code* pcode); + +/* +-- lua code to generate the coordinates + +use 'math' + +b = 2^15 - 1 + +function rot(alpha, x, y) + return x*cos(alpha) - y*sin(alpha), y*cos(alpha) + x*sin(alpha) +end + +function tr(x, y) + return floor(x*b+0.5), floor(y*b+0.5) +end + +-- example for asterisk +tr(rot(0, -0.08, 0.5)) +tr(rot(0, 0.08, 0.5)) +tr(rot(0, 0.08, -0.5)) +tr(rot(0, -0.08, -0.5)) + +tr(rot(pi/3, -0.08, 0.5)) +tr(rot(pi/3, 0.08, 0.5)) +tr(rot(pi/3, 0.08, -0.5)) +tr(rot(pi/3, -0.08, -0.5)) +... +*/ + +static path_code asterisk[] = { + {path_code::closed, 4}, + {-2621, 16384}, + { 2621, 16384}, + { 2621, -16384}, + {-2621, -16384}, + {path_code::closed, 4}, + {-15499, 5922}, + {-12878, 10462}, + { 15499, -5922}, + { 12878, -10462}, + {path_code::closed, 4}, + { 12878, 10462}, + { 15499, 5922}, + {-12878, -10462}, + {-15499, -5922}, + {path_code::end}, }; -static sg_object *build_circle(bool& stroke); -static sg_object *build_square(bool& stroke); -static sg_object *build_triangle(bool& stroke); -static sg_object *build_diamond(bool& stroke); -static sg_object *build_plus(bool& stroke); -static sg_object *build_cross(bool& stroke); +static path_code square[] = { + {path_code::closed, 4}, + {-16383, 16384}, + { 16384, 16384}, + { 16384, -16383}, + {-16383, -16383}, + {path_code::end}, +}; + +static path_code diamond[] = { + {path_code::closed, 4}, + {-16383, 0}, + { 0, 16384}, + { 16384, 0}, + { 0, -16383}, + {path_code::end}, +}; + +static path_code triangle[] = { + {path_code::closed, 3}, + {-18918, -10922}, + { 18918, -10922}, + { 0, 21845}, + {path_code::end}, +}; + +static path_code plus[] = { + {path_code::closed, 4}, + {-2621, 16384}, + { 2621, 16384}, + { 2621, -16384}, + {-2621, -16384}, + {path_code::closed, 4}, + {-16383, 2621}, + { 16384, 2621}, + { 16384, -2621}, + {-16383, -2621}, + {path_code::end}, +}; + +static path_code cross[] = { + {path_code::closed, 4}, + {-13438, 9731}, + {-9731, 13438}, + {13438, -9731}, + {9731, -13438}, + {path_code::closed, 4}, + {9731, 13438}, + {13438, 9731}, + {-9731, -13438}, + {-13438, -9731}, + {path_code::end}, +}; -const unsigned NB_SYMBOLS = 6; +const unsigned NB_SYMBOLS = 7; static struct symbol_reg builder_table[NB_SYMBOLS+1] = { {"circle", build_circle}, - {"square", build_square}, - {"triangle", build_triangle}, - {"diamond", build_diamond}, - {"plus", build_plus}, - {"cross", build_cross}, + {"square", NULL, square}, + {"triangle", NULL, triangle}, + {"diamond", NULL, diamond}, + {"plus", NULL, plus}, + {"cross", NULL, cross}, + {"asterisk", NULL, asterisk}, {NULL, NULL} }; sg_object * -build_circle(bool& stroke) +build_circle() { draw::ellipse* c = new draw::ellipse(); c->self().init(0.0, 0.0, 0.5, 0.5); - stroke = false; return c; } -sg_object * -build_square(bool& stroke) +static inline void decode_coord(const path_code* p, double x[]) { - draw::path* p = new draw::path(); - - agg::path_storage& square = p->self(); - square.move_to(-0.5, -0.5); - square.line_to( 0.5, -0.5); - square.line_to( 0.5, 0.5); - square.line_to(-0.5, 0.5); - square.close_polygon(); - - stroke = false; - return p; + x[0] = double(p->x) / path_code::scale; + x[1] = double(p->y) / path_code::scale; } sg_object * -build_triangle(bool& stroke) +build_path(const path_code *pcode) { draw::path* p = new draw::path(); + agg::path_storage& ps = p->self(); - agg::path_storage& triangle = p->self(); - - double ht = 0.86602540378444; - triangle.move_to(-0.5, -ht/3); - triangle.line_to( 0.5, -ht/3); - triangle.line_to( 0.0, 2*ht/3); - triangle.close_polygon(); - - stroke = false; - return p; -} - -sg_object * -build_diamond(bool& stroke) -{ - draw::path* p = new draw::path(); - - agg::path_storage& square = p->self(); - square.move_to(-0.5, 0.0); - square.line_to( 0.0, 0.5); - square.line_to( 0.5, 0.0); - square.line_to( 0.0, -0.5); - square.close_polygon(); - - stroke = false; - return p; -} - -sg_object * -build_plus(bool& stroke) -{ - draw::path* p = new draw::path(); - - agg::path_storage& plus = p->self(); - plus.move_to(-0.5, 0.0); - plus.line_to( 0.5, 0.0); - plus.move_to( 0.0, -0.5); - plus.line_to( 0.0, 0.5); - - stroke = true; - return p; -} - -sg_object * -build_cross(bool& stroke) -{ - draw::path* p = new draw::path(); - - agg::path_storage& plus = p->self(); - plus.move_to(-0.5, -0.5); - plus.line_to( 0.5, 0.5); - plus.move_to(-0.5, 0.5); - plus.line_to( 0.5, -0.5); + for (const path_code* op = pcode; op->x != path_code::end; op = op + op->y + 1) + { + const path_code* code = op + 1; + double x[2]; + decode_coord(code ++, x); + ps.move_to(x[0], x[1]); + for (short k = 1; k < op->y; k++) + { + decode_coord(code ++, x); + ps.line_to(x[0], x[1]); + } + + if (op->x == path_code::closed) + ps.close_polygon(); + } - stroke = true; return p; } sg_object* -new_marker_symbol_raw(const char *req_name, bool& stroke) +new_marker_symbol_raw(const char *req_name) { struct symbol_reg *reg; for (reg = builder_table; reg->name != NULL; reg++) { if (strcmp (reg->name, req_name) == 0) - return reg->builder(stroke); + { + if (reg->builder) + return reg->builder(); + else + return build_path(reg->pcode); + } } - return builder_table[0].builder(stroke); + return builder_table[0].builder(); } sg_object* new_marker_symbol (const char *req_name) { - bool stroke; - sg_object* s = new_marker_symbol_raw(req_name, stroke); - - trans::scaling *ss = new trans::scaling(s); - sg_object* sf = ss; - if (stroke) - sf = new trans::stroke(sf); - return sf; + sg_object* s = new_marker_symbol_raw(req_name); + return new trans::scaling(s); } sg_object* @@ -151,3 +207,10 @@ new_marker_symbol (int n) n = (n-1) % NB_SYMBOLS; return new_marker_symbol(builder_table[n].name); } + +const char* +marker_lookup(int n) +{ + n = (n-1) % NB_SYMBOLS; + return builder_table[n].name; +} diff --git a/agg-plot/markers.h b/agg-plot/markers.h index b54b1415..44ffb5b1 100644 --- a/agg-plot/markers.h +++ b/agg-plot/markers.h @@ -5,6 +5,7 @@ extern sg_object* new_marker_symbol(const char *name); extern sg_object* new_marker_symbol(int n); -extern sg_object* new_marker_symbol_raw(const char *req_name, bool& stroke); +extern sg_object* new_marker_symbol_raw(const char *req_name); +extern const char* marker_lookup(int n); #endif diff --git a/agg-plot/plot-auto.cpp b/agg-plot/plot-auto.cpp new file mode 100644 index 00000000..e7ae8869 --- /dev/null +++ b/agg-plot/plot-auto.cpp @@ -0,0 +1,114 @@ +#include "plot-auto.h" + +void plot_auto::add(sg_object* vs, agg::rgba8& color, bool outline) +{ + item d(vs, color, outline); + + if (!this->fit_inside(vs)) + { + this->m_bbox_updated = false; + this->m_need_redraw = true; + this->m_enlarged_layer = true; + } + + list<item> *nn = new list<item>(d); + this->m_drawing_queue = list<item>::push_back(this->m_drawing_queue, nn); + + RM::acquire(vs); +} + +void plot_auto::check_bounding_box() +{ + this->calc_bounding_box(); + this->update_units(); + this->m_bbox_updated = true; +} + +void plot_auto::calc_layer_bounding_box(plot_auto::item_list* layer, + opt_rect<double>& rect) +{ + for (unsigned j = 0; j < layer->size(); j++) + { + item& d = (*layer)[j]; + agg::rect_base<double> r; + + d.vs->bounding_box(&r.x1, &r.y1, &r.x2, &r.y2); + rect.add<rect_union>(r); + } +} + +void plot_auto::calc_bounding_box() +{ + opt_rect<double> box; + + unsigned n = this->nb_layers(); + for (unsigned j = 0; j < n-1; j++) + { + box.add<rect_union>(this->get_layer(j)->bounding_box()); + } + + calc_layer_bounding_box(this->get_layer(n-1), box); + for (list<item> *t = this->m_drawing_queue; t; t = t->next()) + { + const item& d = t->content(); + agg::rect_base<double> r; + d.vs->bounding_box(&r.x1, &r.y1, &r.x2, &r.y2); + box.add<rect_union>(r); + } + + this->m_rect = box; +} + +bool plot_auto::fit_inside(sg_object* obj) const +{ + if (!this->m_bbox_updated || !this->m_rect.is_defined()) + return false; + + agg::rect_base<double> r; + obj->bounding_box(&r.x1, &r.y1, &r.x2, &r.y2); + + const agg::rect_base<double>& bb = this->m_rect.rect(); + return bb.hit_test(r.x1, r.y1) && bb.hit_test(r.x2, r.y2); +} + +void plot_auto::set_opt_limits(const opt_rect<double>& r) +{ + if (r.is_defined()) + this->set_limits(r.rect()); + else + this->unset_limits(); +} + +bool plot_auto::push_layer() +{ + bool retval = this->plot::push_layer(); + if (this->m_rect.is_defined()) + this->parent_layer()->set_bounding_box(this->m_rect.rect()); + this->m_bbox_updated = true; + this->m_enlarged_layer = false; + return retval; +} + +bool plot_auto::pop_layer() +{ + bool retval = this->plot::pop_layer(); + if (this->m_enlarged_layer) + this->m_bbox_updated = false; + this->m_enlarged_layer = true; + return retval; +} + +void plot_auto::clear_current_layer() +{ + this->plot::clear_current_layer(); + if (this->m_enlarged_layer) + { + item_list* parent = this->parent_layer(); + if (parent) + set_opt_limits(parent->bounding_box()); + else + this->unset_limits(); + } + this->m_bbox_updated = true; + this->m_enlarged_layer = false; +} diff --git a/agg-plot/plot-auto.h b/agg-plot/plot-auto.h index 52e40de2..a6321840 100644 --- a/agg-plot/plot-auto.h +++ b/agg-plot/plot-auto.h @@ -27,15 +27,13 @@ #include "agg_array.h" #include "agg_basics.h" -template<class resource_manager> -class plot_auto : public plot<resource_manager> { - typedef typename plot<resource_manager>::item item; - typedef typename plot<resource_manager>::item_list item_list; +class plot_auto : public plot { + typedef typename plot::item item; + typedef typename plot::item_list item_list; public: plot_auto() : - plot<resource_manager>(true), - m_bbox_updated(true), m_enlarged_layer(false) + plot(true), m_bbox_updated(true), m_enlarged_layer(false) { }; virtual ~plot_auto() { }; @@ -43,7 +41,7 @@ public: virtual void add(sg_object* vs, agg::rgba8& color, bool outline); virtual void before_draw() { - plot<resource_manager>::before_draw(); + plot::before_draw(); if (!m_bbox_updated) check_bounding_box(); }; @@ -65,126 +63,4 @@ private: bool m_enlarged_layer; }; -template <class RM> -void plot_auto<RM>::add(sg_object* vs, agg::rgba8& color, bool outline) -{ - item d(vs, color, outline); - - if (!this->fit_inside(vs)) - { - this->m_bbox_updated = false; - this->m_need_redraw = true; - this->m_enlarged_layer = true; - } - - list<item> *nn = new list<item>(d); - this->m_drawing_queue = list<item>::push_back(this->m_drawing_queue, nn); - - RM::acquire(vs); -} - -template<class RM> -void plot_auto<RM>::check_bounding_box() -{ - this->calc_bounding_box(); - this->update_units(); - this->m_bbox_updated = true; -} - -template<class RM> -void plot_auto<RM>::calc_layer_bounding_box(plot_auto<RM>::item_list* layer, - opt_rect<double>& rect) -{ - for (unsigned j = 0; j < layer->size(); j++) - { - item& d = (*layer)[j]; - agg::rect_base<double> r; - - d.vs->bounding_box(&r.x1, &r.y1, &r.x2, &r.y2); - rect.add<rect_union>(r); - } -} - -template<class RM> -void plot_auto<RM>::calc_bounding_box() -{ - opt_rect<double> box; - - unsigned n = this->nb_layers(); - for (unsigned j = 0; j < n-1; j++) - { - box.add<rect_union>(this->get_layer(j)->bounding_box()); - } - - calc_layer_bounding_box(this->get_layer(n-1), box); - for (list<item> *t = this->m_drawing_queue; t; t = t->next()) - { - const item& d = t->content(); - agg::rect_base<double> r; - d.vs->bounding_box(&r.x1, &r.y1, &r.x2, &r.y2); - box.add<rect_union>(r); - } - - this->m_rect = box; -} - -template<class RM> -bool plot_auto<RM>::fit_inside(sg_object* obj) const -{ - if (!this->m_bbox_updated || !this->m_rect.is_defined()) - return false; - - agg::rect_base<double> r; - obj->bounding_box(&r.x1, &r.y1, &r.x2, &r.y2); - - const agg::rect_base<double>& bb = this->m_rect.rect(); - return bb.hit_test(r.x1, r.y1) && bb.hit_test(r.x2, r.y2); -} - -template<class RM> -void plot_auto<RM>::set_opt_limits(const opt_rect<double>& r) -{ - if (r.is_defined()) - this->set_limits(r.rect()); - else - this->unset_limits(); -} - -template<class RM> -bool plot_auto<RM>::push_layer() -{ - bool retval = this->plot<RM>::push_layer(); - if (this->m_rect.is_defined()) - this->parent_layer()->set_bounding_box(this->m_rect.rect()); - this->m_bbox_updated = true; - this->m_enlarged_layer = false; - return retval; -} - -template<class RM> -bool plot_auto<RM>::pop_layer() -{ - bool retval = this->plot<RM>::pop_layer(); - if (this->m_enlarged_layer) - this->m_bbox_updated = false; - this->m_enlarged_layer = true; - return retval; -} - -template<class RM> -void plot_auto<RM>::clear_current_layer() -{ - this->plot<RM>::clear_current_layer(); - if (this->m_enlarged_layer) - { - item_list* parent = this->parent_layer(); - if (parent) - set_opt_limits(parent->bounding_box()); - else - this->unset_limits(); - } - this->m_bbox_updated = true; - this->m_enlarged_layer = false; -} - #endif diff --git a/agg-plot/plot.cpp b/agg-plot/plot.cpp new file mode 100644 index 00000000..c235c35f --- /dev/null +++ b/agg-plot/plot.cpp @@ -0,0 +1,725 @@ +#include "plot.h" + +static double compute_scale(const agg::trans_affine& m) +{ + return m.scale() / 480.0; +} + +static double +std_line_width(double scale, double w = 1.0) +{ +#if 0 + const double dsf = M_LN10; + double ls = log(scale) / dsf; + return exp(round(ls) * dsf) * w * 1.5; +#else + return w * 1.5; +#endif +} + +void plot::commit_pending_draw() +{ + push_drawing_queue(); + m_need_redraw = false; + m_changes_pending.clear(); +} + +void plot::add(sg_object* vs, agg::rgba8& color, bool outline) +{ + item d(vs, color, outline); + list<item> *new_node = new list<item>(d); + m_drawing_queue = list<item>::push_back(m_drawing_queue, new_node); + RM::acquire(vs); +} + +void plot::push_drawing_queue() +{ + item_list* layer = current_layer(); + for (list<item> *c = m_drawing_queue; c != 0; c = c->next()) + { + layer->add(c->content()); + } + + while (m_drawing_queue) + m_drawing_queue = list<item>::pop(m_drawing_queue); +} + +void plot::clear_drawing_queue() +{ + while (m_drawing_queue) + { + item& d = m_drawing_queue->content(); + RM::dispose(d.vs); + m_drawing_queue = list<item>::pop(m_drawing_queue); + } +} + +static bool area_is_valid(const agg::trans_affine& b) +{ + const double thresold = 40.0; + return (b.sx > thresold && b.sy > thresold); +} + +void plot::draw_virtual_canvas(canvas_type& canvas, plot_layout& layout, const agg::rect_i* clip) +{ + before_draw(); + draw_legends(canvas, layout); + + if (area_is_valid(layout.plot_area)) + { + draw_axis(canvas, layout, clip); + draw_elements(canvas, layout); + } +}; + +void plot::draw_simple(canvas_type& canvas, plot_layout& layout, const agg::rect_i* clip) +{ + before_draw(); + draw_axis(canvas, layout, clip); + draw_elements(canvas, layout); +}; + +void plot::draw_element(item& c, canvas_type& canvas, const agg::trans_affine& m) +{ + sg_object& vs = c.content(); + vs.apply_transform(m, 1.0); + + if (c.outline) + canvas.draw_outline(vs, c.color); + else + canvas.draw(vs, c.color); +} + +agg::trans_affine plot::get_model_matrix(const plot_layout& layout) +{ + agg::trans_affine m = m_trans; + trans_affine_compose (m, layout.plot_active_area); + return m; +} + +void plot::clip_plot_area(canvas_type& canvas, const agg::trans_affine& area_mtx) +{ + if (this->clip_is_active()) + { + agg::rect_base<int> clip = rect_of_slot_matrix<int>(area_mtx); + canvas.clip_box(clip); + } +} + +void plot::draw_elements(canvas_type& canvas, const plot_layout& layout) +{ + const agg::trans_affine m = get_model_matrix(layout); + + this->clip_plot_area(canvas, layout.plot_active_area); + + for (unsigned k = 0; k < m_layers.size(); k++) + { + item_list& layer = *(m_layers[k]); + for (unsigned j = 0; j < layer.size(); j++) + { + draw_element(layer[j], canvas, m); + } + } + + canvas.reset_clipping(); +} + +void plot::compute_user_trans() +{ + agg::rect_base<double> r; + + if (m_use_units && m_pad_units) + { + int ixi, ixs, iyi, iys; + double xd, yd; + m_ux.limits(ixi, ixs, xd); + r.x1 = ixi * xd; + r.x2 = ixs * xd; + + m_uy.limits(iyi, iys, yd); + r.y1 = iyi * yd; + r.y2 = iys * yd; + } + else + { + r = m_rect.is_defined() ? m_rect.rect() : agg::rect_base<double>(0.0, 0.0, 1.0, 1.0); + } + + if (m_xaxis_hol) + { + for (unsigned k = 0; k < m_xaxis_hol->size(); k++) + { + factor_labels* f = m_xaxis_hol->at(k); + double x1 = f->mark(0), x2 = f->mark(f->labels_number()); + if (k == 0 || x1 < r.x1) r.x1 = x1; + if (k == 0 || x2 > r.x2) r.x2 = x2; + } + } + + double dx = r.x2 - r.x1, dy = r.y2 - r.y1; + double fx = (dx == 0 ? 1.0 : 1/dx), fy = (dy == 0 ? 1.0 : 1/dy); + this->m_trans = agg::trans_affine(fx, 0.0, 0.0, fy, -r.x1 * fx, -r.y1 * fy); +} + +void plot::draw_grid(const axis_e dir, const units& u, + const agg::trans_affine& user_mtx, + agg::path_storage& ln) +{ + const double eps = 1.0e-3; + const bool isx = (dir == x_axis); + + int jinf = u.begin(), jsup = u.end(); + for (int j = jinf+1; j < jsup; j++) + { + double uq = u.mark_value(j); + double x = (isx ? uq : 0), y = (isx ? 0.0 : uq); + user_mtx.transform(&x, &y); + const double q = (isx ? x : y); + + if (q >= -eps && q <= 1.0 + eps) + { + ln.move_to(isx ? q : 0.0, isx ? 0.0 : q); + ln.line_to(isx ? q : 1.0, isx ? 1.0 : q); + } + } +} + + +double plot::draw_axis_m(axis_e dir, units& u, + const agg::trans_affine& user_mtx, + ptr_list<draw::text>& labels, double scale, + agg::path_storage& mark, agg::path_storage& ln) +{ + const double ppad = double(axis_label_prop_space) / 1000.0; + const double text_label_size = get_default_font_size(text_axis_labels, scale); + const double eps = 1.0e-3; + + // used to store the bounding box of text labels + opt_rect<double> bb; + agg::rect_base<double> r; + + bool isx = (dir == x_axis); + + const axis& ax = get_axis(dir); + double hj = ax.labels_hjustif(), vj = ax.labels_vjustif(); + double langle = ax.labels_angle(); + + category_map::iterator clabels(ax.categories); + units_iterator ulabels(u, ax.format_tag, ax.label_format()); + + label_iterator* ilabels = (ax.use_categories ? (label_iterator*) &clabels : (label_iterator*) &ulabels); + + double uq; + const char* text; + while (ilabels->next(uq, text)) + { + double x = (isx ? uq : 0.0), y = (isx ? 0.0 : uq); + user_mtx.transform(&x, &y); + + double q = (isx ? x : y); + + if (q < -eps || q > 1.0 + eps) + continue; + + draw::text* label = new draw::text(text, text_label_size, hj, vj); + + label->set_point(isx ? q : -ppad, isx ? -ppad : q); + label->angle(langle); + + agg::bounding_rect_single(*label, 0, &r.x1, &r.y1, &r.x2, &r.y2); + bb.add<rect_union>(r); + + labels.add(label); + + mark.move_to(isx ? q : 0.0 , isx ? 0.0 : q); + mark.line_to(isx ? q : -0.01, isx ? -0.01 : q); + } + + this->draw_grid(dir, u, user_mtx, ln); + + double label_size; + if (bb.is_defined()) + { + const agg::rect_base<double>& br = bb.rect(); + label_size = (isx ? br.y2 - br.y1 : br.x2 - br.x1); + } + else + { + label_size = 0.0; + } + + return label_size; +} + +double plot::draw_xaxis_factors(units& u, + const agg::trans_affine& user_mtx, + ptr_list<draw::text>& labels, + ptr_list<factor_labels>* f_labels, double scale, + agg::path_storage& mark, agg::path_storage& ln) +{ + const double text_label_size = get_default_font_size(text_axis_labels, scale); + + const axis& ax = get_axis(x_axis); + const double lab_angle = ax.labels_angle(); + + const double y_spac_top = 3, y_spac_bot = 3; + const int layers_number = f_labels->size(); + double p_lab = 0; + for (int layer = layers_number - 1; layer >= 0; layer--) + { + factor_labels* factor = f_labels->at(layer); + + if (factor->labels_number() > 256) continue; + + agg::pod_bvector<draw::text*> tlabels; + double hmax = 0.0; + bool draw_labels = (factor->labels_number() < 32); + if (draw_labels) + { + for (int k = 0; k < factor->labels_number(); k++) + { + const char* text = factor->label_text(k); + draw::text* label = new draw::text(text, text_label_size, 0.5, 0.5); + label->angle(lab_angle); + + double rx1, ry1, rx2, ry2; + agg::bounding_rect_single(*label, 0, &rx1, &ry1, &rx2, &ry2); + double rh = ry2 - ry1; + if (rh > hmax) hmax = rh; + tlabels.add(label); + } + } + + double p_lab_inf = p_lab - (y_spac_top + y_spac_bot + hmax); + + for (int k = 0; k < factor->labels_number(); k++) + { + double x_lab_a = factor->mark(k); + double x_lab_b = factor->mark(k+1); + + double x_a = x_lab_a, y_a = 0.0; + user_mtx.transform(&x_a, &y_a); + double q_a = x_a; + + double x_lab = (x_lab_a + x_lab_b) / 2, y_lab = 0.0; + user_mtx.transform(&x_lab, &y_lab); + double q_lab = x_lab; + + mark.move_to(q_a, p_lab); + mark.line_to(q_a, p_lab_inf); + + if (draw_labels) + { + draw::text* label = tlabels[k]; + label->set_point(q_lab, p_lab_inf + y_spac_bot + hmax/2.0); + labels.add(label); + } + } + + double x_lab = factor->mark(factor->labels_number()); + double x_a = x_lab, y_a = 0.0; + user_mtx.transform(&x_a, &y_a); + double q_a = x_a; + mark.move_to(q_a, p_lab); + mark.line_to(q_a, p_lab_inf); + + p_lab = p_lab_inf; + } + + this->draw_grid(x_axis, u, user_mtx, ln); + + return - p_lab; +} + +static inline double approx_text_height(double text_size) +{ + return text_size * 1.5; +} + +plot_layout plot::compute_plot_layout(const agg::trans_affine& canvas_mtx, bool do_legends) +{ + plot_layout layout; + + const double sx = canvas_mtx.sx, sy = canvas_mtx.sy; + const double ppad = double(canvas_margin_prop_space) / 1000.0; + const double fpad = double(canvas_margin_fixed_space); + const double size_frac_x = 0.125, size_frac_y = 0.05; + + double dxl, dxr, dyb, dyt; + + dxl = dxr = fpad + ppad * sx; + dyb = dyt = fpad + ppad * sy; + + if (!str_is_null(&m_title)) + { + const double scale = compute_scale(canvas_mtx); + const double ptpad = double(axis_title_prop_space) / 1000.0; + const double title_text_size = get_default_font_size(text_plot_title, scale); + const double th = approx_text_height(title_text_size); + + double x = 0.5, y = 1.0; + canvas_mtx.transform(&x, &y); + y -= ptpad + dyt + title_text_size; + + layout.title_pos = plot_layout::point(x, y); + layout.title_font_size = title_text_size; + + dyt += 2 * ptpad + th; + } + + for (int k = 0; k < 4 && do_legends; k++) + { + plot* mp = m_legend[k]; + + if (mp) + { + agg::rect_base<double> bb; + mp->get_bounding_rect(bb); + + double bb_dx = bb.x2 - bb.x1, bb_dy = bb.y2 - bb.y1; + double dx, dy; + double px, py; + switch (k) + { + case right: + dx = max(sx * size_frac_x, bb_dx); + dy = dx * bb_dy / bb_dx; + px = sx - dx - ppad * sx - dxr; + py = (sy - dy) / 2; + dxr += dx + 2 * ppad * sx; + break; + case left: + dx = max(sx * size_frac_x, bb_dx); + dy = dx * bb_dy / bb_dx; + px = ppad * sx + dxr; + py = (sy - dy) / 2; + dxl += dx + 2 * ppad * sx; + break; + case bottom: + dy = sy * size_frac_y; + dx = dy * bb_dx / bb_dy; + py = ppad * sy + dyb; + px = (sx - dx) / 2; + dyb += dy + 2 * ppad * sy; + break; + case top: + dy = sy * size_frac_y; + dx = dy * bb_dx / bb_dy; + py = sy - dy - ppad * sy - dyt; + px = (sx - dx) / 2; + dyt += dy + 2 * ppad * sy; + break; + default: + /* */ + ; + } + + if (px >= 0 && py >= 0 && px + dx < sx && py + dy < sy) + { + const double x0 = canvas_mtx.tx + px, y0 = canvas_mtx.ty + py; + layout.legend_area[k] = agg::trans_affine(dx, 0.0, 0.0, dy, x0, y0); + } + else + { + plot_layout::set_area_undefined(layout.legend_area[k]); + } + } + } + + double x0 = canvas_mtx.tx + dxl, y0 = canvas_mtx.ty + dyb; + double ssx = sx - (dxl + dxr), ssy = sy - (dyb + dyt); + layout.plot_area = agg::trans_affine(ssx, 0.0, 0.0, ssy, x0, y0); + + return layout; +} + +void plot::draw_legends(canvas_type& canvas, const plot_layout& layout) +{ + if (!str_is_null(&m_title)) + { + const plot_layout::point& pos = layout.title_pos; + draw::text title(m_title.cstr(), layout.title_font_size, 0.5, 0.0); + title.set_point(pos.x, pos.y); + title.apply_transform(identity_matrix, 1.0); + canvas.draw(title, colors::black); + } + + for (int k = 0; k < 4; k++) + { + plot* mp = m_legend[k]; + const agg::trans_affine& mtx = layout.legend_area[k]; + + if (mp && plot_layout::is_area_defined(mtx)) + { + agg::rect_i clip = rect_of_slot_matrix<int>(mtx); + plot_layout mp_layout = mp->compute_plot_layout(mtx, false); + mp->draw_simple(canvas, mp_layout, &clip); + } + } +} + +// Draw the axis elements and labels and set layout.plot_active_area +// to the actual plotting are matrix. +void plot::draw_axis(canvas_type& canvas, plot_layout& layout, const agg::rect_i* clip) +{ + if (!m_use_units) + { + layout.plot_active_area = layout.plot_area; + return; + } + + double scale = compute_scale(layout.plot_area); + + if (clip) + canvas.clip_box(*clip); + + const agg::trans_affine& m = layout.plot_active_area; + + agg::path_storage box; + sg_object_gen<agg::conv_transform<agg::path_storage> > boxtr(box, m); + trans::stroke_a boxvs(&boxtr); + + box.move_to(0.0, 0.0); + box.line_to(0.0, 1.0); + box.line_to(1.0, 1.0); + box.line_to(1.0, 0.0); + box.close_polygon(); + + agg::path_storage x_mark; + sg_object_gen<agg::conv_transform<agg::path_storage> > x_mark_tr(x_mark, m); + trans::stroke_a x_mark_stroke(&x_mark_tr); + + agg::path_storage y_mark; + sg_object_gen<agg::conv_transform<agg::path_storage> > y_mark_tr(y_mark, m); + trans::stroke_a y_mark_stroke(&y_mark_tr); + + agg::path_storage ln; + sg_object_gen<agg::conv_transform<agg::path_storage> > ln_tr(ln, m); + trans::dash_a lndash(&ln_tr); + trans::stroke_a lns(&lndash); + + const double label_text_size = get_default_font_size(text_axis_title, scale); + const double plpad = double(axis_label_prop_space) / 1000.0; + const double ptpad = double(axis_title_prop_space) / 1000.0; + + ptr_list<draw::text> xlabels, ylabels; + + double dy_label = 0; + if (this->m_xaxis_hol) + dy_label = draw_xaxis_factors(m_ux, m_trans, xlabels, this->m_xaxis_hol, scale, x_mark, ln); + else + dy_label = draw_axis_m(x_axis, m_ux, m_trans, xlabels, scale, x_mark, ln); + + double dx_label = draw_axis_m(y_axis, m_uy, m_trans, ylabels, scale, y_mark, ln); + + double ppad_left = plpad, ppad_right = plpad; + double ppad_bottom = plpad, ppad_top = plpad; + double dx_left = dx_label, dx_right = 0.0; + double dy_bottom = dy_label, dy_top = 0.0; + + if (!str_is_null(&m_y_axis.title)) + { + dx_left += approx_text_height(label_text_size); + ppad_left += ptpad; + } + + if (!str_is_null(&m_x_axis.title)) + { + dy_bottom += approx_text_height(label_text_size); + ppad_bottom += ptpad; + } + + const double sx = layout.plot_area.sx, sy = layout.plot_area.sy; + const double x0 = layout.plot_area.tx, y0 = layout.plot_area.ty; + + const double xppad = (ppad_left + ppad_right); + const double lsx = (dx_left + dx_right + xppad * sx) / (1 + xppad); + + const double yppad = (ppad_bottom + ppad_top); + const double lsy = (dy_bottom + dy_top + yppad * sy) / (1 + yppad); + + const double sxr = sx - lsx; + const double syr = sy - lsy; + + const double aax = x0 + dx_left + ppad_left * sxr; + const double aay = y0 + dy_bottom + ppad_bottom * syr; + layout.set_plot_active_area(sxr, syr, aax, aay); + + agg::trans_affine m_xlabels; + if (this->m_xaxis_hol) + { + m_xlabels.sx = m.sx; + m_xlabels.tx = m.tx; + m_xlabels.ty = m.ty; + + x_mark_tr.self().transformer(m_xlabels); + } + else + { + m_xlabels = m; + } + + for (unsigned j = 0; j < xlabels.size(); j++) + { + draw::text* label = xlabels[j]; + label->apply_transform(m_xlabels, 1.0); + canvas.draw(*label, colors::black); + } + + for (unsigned j = 0; j < ylabels.size(); j++) + { + draw::text* label = ylabels[j]; + label->apply_transform(m, 1.0); + canvas.draw(*label, colors::black); + } + + lndash.add_dash(7.0, 3.0); + + lns.width(std_line_width(scale, 0.15)); + canvas.draw(lns, colors::black); + + x_mark_stroke.width(std_line_width(scale, 0.75)); + canvas.draw(x_mark_stroke, colors::black); + + y_mark_stroke.width(std_line_width(scale, 0.75)); + canvas.draw(y_mark_stroke, colors::black); + + boxvs.width(std_line_width(scale, 0.75)); + canvas.draw(boxvs, colors::black); + + if (!str_is_null(&m_x_axis.title)) + { + double labx = m.sx * 0.5 + m.tx; + double laby = y0; + + const char* text = m_x_axis.title.cstr(); + draw::text xlabel(text, label_text_size, 0.5, 0.0); + xlabel.set_point(labx, laby); + xlabel.apply_transform(identity_matrix, 1.0); + + canvas.draw(xlabel, colors::black); + } + + if (!str_is_null(&m_y_axis.title)) + { + double labx = x0; + double laby = m.sy * 0.5 + m.ty; + + const char* text = m_y_axis.title.cstr(); + draw::text ylabel(text, label_text_size, 0.5, 1.0); + ylabel.set_point(labx, laby); + ylabel.angle(M_PI/2.0); + ylabel.apply_transform(identity_matrix, 1.0); + + canvas.draw(ylabel, colors::black); + } + + if (clip) + canvas.reset_clipping(); +} + +void plot::set_axis_labels_angle(axis_e axis_dir, double angle) +{ + get_axis(axis_dir).set_labels_angle(angle); + m_need_redraw = true; + compute_user_trans(); +} + +void plot::set_units(bool use_units) +{ + if (m_use_units != use_units) + { + m_use_units = use_units; + m_need_redraw = true; + compute_user_trans(); + } +} + +void plot::update_units() +{ + if (m_rect.is_defined()) + { + const rect_base<double>& r = m_rect.rect(); + m_ux = units(r.x1, r.x2); + m_uy = units(r.y1, r.y2); + } + else + { + m_ux = units(); + m_uy = units(); + } + + compute_user_trans(); +} + +void plot::set_limits(const agg::rect_base<double>& r) +{ + m_rect.set(r); + update_units(); + m_need_redraw = true; +} + +void plot::unset_limits() +{ + m_rect.clear(); + update_units(); + m_need_redraw = true; +} + +void plot::layer_dispose_elements(plot::item_list* layer) +{ + unsigned n = layer->size(); + for (unsigned k = 0; k < n; k++) + { + RM::dispose(layer->at(k).vs); + } +} + +bool plot::push_layer() +{ + if (m_layers.size() >= max_layers) + return false; + + item_list *new_layer = new(std::nothrow) item_list(); + if (new_layer) + { + before_draw(); + push_drawing_queue(); + m_layers.add(new_layer); + return true; + } + + return false; +} + +bool plot::pop_layer() +{ + if (m_layers.size() <= 1) + return false; + + unsigned n = m_layers.size(); + item_list* layer = m_layers[n-1]; + m_layers.inc_size(-1); + layer_dispose_elements(layer); + delete layer; + + clear_drawing_queue(); + m_need_redraw = true; + + return true; +} + +void plot::clear_current_layer() +{ + item_list* current = current_layer(); + clear_drawing_queue(); + layer_dispose_elements(current); + current->clear(); + m_changes_pending = m_changes_accu; + m_changes_accu.clear(); +} + +int plot::current_layer_index() +{ + return m_layers.size(); +} diff --git a/agg-plot/plot.h b/agg-plot/plot.h index 06d0d35a..25b0ce72 100644 --- a/agg-plot/plot.h +++ b/agg-plot/plot.h @@ -36,6 +36,7 @@ #include "text.h" #include "categories.h" #include "sg_object.h" +#include "factor_labels.h" #include "agg_array.h" #include "agg_bounding_rect.h" @@ -123,7 +124,8 @@ struct plot_item { }; }; -template<class ResourceManager> +typedef manage_owner RM; + class plot { static const unsigned max_layers = 8; @@ -239,7 +241,8 @@ public: m_drawing_queue(0), m_clip_flag(true), m_need_redraw(true), m_rect(), m_use_units(use_units), m_pad_units(false), m_title(), - m_sync_mode(true), m_x_axis(x_axis), m_y_axis(y_axis) + m_sync_mode(true), m_x_axis(x_axis), m_y_axis(y_axis), + m_xaxis_hol(0) { m_layers.add(&m_root_layer); compute_user_trans(); @@ -256,6 +259,8 @@ public: if (k > 0) delete layer; } + + delete m_xaxis_hol; }; str& title() { @@ -301,6 +306,14 @@ public: void set_limits(const agg::rect_base<double>& r); void unset_limits(); + ptr_list<factor_labels>* get_xaxis_hol() { return m_xaxis_hol; } + + void set_xaxis_hol(ptr_list<factor_labels>* hol) + { + delete m_xaxis_hol; + m_xaxis_hol = hol; + } + virtual void add(sg_object* vs, agg::rgba8& color, bool outline); virtual void before_draw() { } @@ -417,10 +430,19 @@ protected: void draw_virtual_canvas(canvas_type& canvas, plot_layout& layout, const agg::rect_i* r); void draw_simple(canvas_type& canvas, plot_layout& layout, const agg::rect_i* r); + void draw_grid(const axis_e dir, const units& u, + const agg::trans_affine& user_mtx, + agg::path_storage& ln); + double draw_axis_m(axis_e dir, units& u, const agg::trans_affine& user_mtx, ptr_list<draw::text>& labels, double scale, agg::path_storage& mark, agg::path_storage& ln); + double draw_xaxis_factors(units& u, const agg::trans_affine& user_mtx, + ptr_list<draw::text>& labels, + ptr_list<factor_labels>* f_labels, double scale, + agg::path_storage& mark, agg::path_storage& ln); + void draw_elements(canvas_type &canvas, const plot_layout& layout); void draw_element(item& c, canvas_type &canvas, const agg::trans_affine& m); void draw_axis(canvas_type& can, plot_layout& layout, const agg::rect_i* clip = 0); @@ -486,144 +508,12 @@ private: axis m_x_axis, m_y_axis; plot* m_legend[4]; -}; - -static double compute_scale(const agg::trans_affine& m) -{ - return m.scale() / 480.0; -} - -static double -std_line_width(double scale, double w = 1.0) -{ -#if 0 - const double dsf = M_LN10; - double ls = log(scale) / dsf; - return exp(round(ls) * dsf) * w * 1.5; -#else - return w * 1.5; -#endif -} - -template <class RM> -void plot<RM>::commit_pending_draw() -{ - push_drawing_queue(); - m_need_redraw = false; - m_changes_pending.clear(); -} - -template <class RM> -void plot<RM>::add(sg_object* vs, agg::rgba8& color, bool outline) -{ - item d(vs, color, outline); - list<item> *new_node = new list<item>(d); - m_drawing_queue = list<item>::push_back(m_drawing_queue, new_node); - RM::acquire(vs); -} - -template <class RM> -void plot<RM>::push_drawing_queue() -{ - item_list* layer = current_layer(); - for (list<item> *c = m_drawing_queue; c != 0; c = c->next()) - { - layer->add(c->content()); - } - - while (m_drawing_queue) - m_drawing_queue = list<item>::pop(m_drawing_queue); -} - -template <class RM> -void plot<RM>::clear_drawing_queue() -{ - while (m_drawing_queue) - { - item& d = m_drawing_queue->content(); - RM::dispose(d.vs); - m_drawing_queue = list<item>::pop(m_drawing_queue); - } -} - -static bool area_is_valid(const agg::trans_affine& b) -{ - const double thresold = 40.0; - return (b.sx > thresold && b.sy > thresold); -} -template <class RM> -void plot<RM>::draw_virtual_canvas(canvas_type& canvas, plot_layout& layout, const agg::rect_i* clip) -{ - before_draw(); - draw_legends(canvas, layout); - - if (area_is_valid(layout.plot_area)) - { - draw_axis(canvas, layout, clip); - draw_elements(canvas, layout); - } -}; - -template <class RM> -void plot<RM>::draw_simple(canvas_type& canvas, plot_layout& layout, const agg::rect_i* clip) -{ - before_draw(); - draw_axis(canvas, layout, clip); - draw_elements(canvas, layout); + ptr_list<factor_labels>* m_xaxis_hol; }; -template <class RM> -void plot<RM>::draw_element(item& c, canvas_type& canvas, const agg::trans_affine& m) -{ - sg_object& vs = c.content(); - vs.apply_transform(m, 1.0); - - if (c.outline) - canvas.draw_outline(vs, c.color); - else - canvas.draw(vs, c.color); -} - -template <class RM> -agg::trans_affine plot<RM>::get_model_matrix(const plot_layout& layout) -{ - agg::trans_affine m = m_trans; - trans_affine_compose (m, layout.plot_active_area); - return m; -} - -template<class RM> -void plot<RM>::clip_plot_area(canvas_type& canvas, const agg::trans_affine& area_mtx) -{ - if (this->clip_is_active()) - { - agg::rect_base<int> clip = rect_of_slot_matrix<int>(area_mtx); - canvas.clip_box(clip); - } -} - -template <class RM> -void plot<RM>::draw_elements(canvas_type& canvas, const plot_layout& layout) -{ - const agg::trans_affine m = get_model_matrix(layout); - - this->clip_plot_area(canvas, layout.plot_active_area); - - for (unsigned k = 0; k < m_layers.size(); k++) - { - item_list& layer = *(m_layers[k]); - for (unsigned j = 0; j < layer.size(); j++) - { - draw_element(layer[j], canvas, m); - } - } - - canvas.reset_clipping(); -} - -template <class RM> -template <class Canvas> void plot<RM>::draw_queue(Canvas& _canvas, const agg::trans_affine& canvas_mtx, const plot_render_info& inf, opt_rect<double>& bb) +template <class Canvas> +void plot::draw_queue(Canvas& _canvas, const agg::trans_affine& canvas_mtx, const plot_render_info& inf, opt_rect<double>& bb) { canvas_adapter<Canvas> canvas(&_canvas); before_draw(); @@ -633,7 +523,7 @@ template <class Canvas> void plot<RM>::draw_queue(Canvas& _canvas, const agg::tr this->clip_plot_area(canvas, layout.plot_active_area); - typedef typename plot<RM>::iterator iter_type; + typedef typename plot::iterator iter_type; iter_type *c0 = m_drawing_queue; for (iter_type *c = c0; c != 0; c = c->next()) { @@ -658,483 +548,4 @@ template <class Canvas> void plot<RM>::draw_queue(Canvas& _canvas, const agg::tr canvas.reset_clipping(); } -template <class RM> -void plot<RM>::compute_user_trans() -{ - agg::rect_base<double> r; - - if (m_use_units && m_pad_units) - { - int ixi, ixs, iyi, iys; - double xd, yd; - m_ux.limits(ixi, ixs, xd); - r.x1 = ixi * xd; - r.x2 = ixs * xd; - - m_uy.limits(iyi, iys, yd); - r.y1 = iyi * yd; - r.y2 = iys * yd; - } - else - { - r = m_rect.is_defined() ? m_rect.rect() : agg::rect_base<double>(0.0, 0.0, 1.0, 1.0); - } - - double dx = r.x2 - r.x1, dy = r.y2 - r.y1; - double fx = (dx == 0 ? 1.0 : 1/dx), fy = (dy == 0 ? 1.0 : 1/dy); - this->m_trans = agg::trans_affine(fx, 0.0, 0.0, fy, -r.x1 * fx, -r.y1 * fy); -} - -template <class RM> -double plot<RM>::draw_axis_m(axis_e dir, units& u, - const agg::trans_affine& user_mtx, - ptr_list<draw::text>& labels, double scale, - agg::path_storage& mark, agg::path_storage& ln) -{ - const double ppad = double(axis_label_prop_space) / 1000.0; - const double text_label_size = get_default_font_size(text_axis_labels, scale); - const double eps = 1.0e-3; - - opt_rect<double> bb; - agg::rect_base<double> r; - - bool isx = (dir == x_axis); - - const axis& ax = get_axis(dir); - double hj = ax.labels_hjustif(), vj = ax.labels_vjustif(); - double langle = ax.labels_angle(); - - category_map::iterator clabels(ax.categories); - units_iterator ulabels(u, ax.format_tag, ax.label_format()); - - label_iterator* ilabels = (ax.use_categories ? (label_iterator*) &clabels : (label_iterator*) &ulabels); - - double uq; - const char* text; - while (ilabels->next(uq, text)) - { - double x = (isx ? uq : 0.0), y = (isx ? 0.0 : uq); - user_mtx.transform(&x, &y); - - double q = (isx ? x : y); - - if (q < -eps || q > 1.0 + eps) - continue; - - draw::text* label = new draw::text(text, text_label_size, hj, vj); - - label->set_point(isx ? q : -ppad, isx ? -ppad : q); - label->angle(langle); - - agg::bounding_rect_single(*label, 0, &r.x1, &r.y1, &r.x2, &r.y2); - bb.add<rect_union>(r); - - labels.add(label); - - mark.move_to(isx ? q : 0.0 , isx ? 0.0 : q); - mark.line_to(isx ? q : -0.01, isx ? -0.01 : q); - } - - int jinf = u.begin(), jsup = u.end(); - for (int j = jinf+1; j < jsup; j++) - { - double uq = u.mark_value(j); - double x = (isx ? uq : 0), y = (isx ? 0.0 : uq); - user_mtx.transform(&x, &y); - double q = (isx ? x : y); - - if (q >= -eps && q <= 1.0 + eps) - { - ln.move_to(isx ? q : 0.0, isx ? 0.0 : q); - ln.line_to(isx ? q : 1.0, isx ? 1.0 : q); - } - } - - double label_size; - if (bb.is_defined()) - { - const agg::rect_base<double>& br = bb.rect(); - label_size = (isx ? br.y2 - br.y1 : br.x2 - br.x1); - } - else - { - label_size = 0.0; - } - - return label_size; -} - -static inline double approx_text_height(double text_size) -{ - return text_size * 1.5; -} - -template <class RM> -plot_layout plot<RM>::compute_plot_layout(const agg::trans_affine& canvas_mtx, bool do_legends) -{ - plot_layout layout; - - const double sx = canvas_mtx.sx, sy = canvas_mtx.sy; - const double ppad = double(canvas_margin_prop_space) / 1000.0; - const double fpad = double(canvas_margin_fixed_space); - const double size_frac_x = 0.125, size_frac_y = 0.05; - - double dxl, dxr, dyb, dyt; - - dxl = dxr = fpad + ppad * sx; - dyb = dyt = fpad + ppad * sy; - - if (!str_is_null(&m_title)) - { - const double scale = compute_scale(canvas_mtx); - const double ptpad = double(axis_title_prop_space) / 1000.0; - const double title_text_size = get_default_font_size(text_plot_title, scale); - const double th = approx_text_height(title_text_size); - - double x = 0.5, y = 1.0; - canvas_mtx.transform(&x, &y); - y -= ptpad + dyt + title_text_size; - - layout.title_pos = plot_layout::point(x, y); - layout.title_font_size = title_text_size; - - dyt += 2 * ptpad + th; - } - - for (int k = 0; k < 4 && do_legends; k++) - { - plot* mp = m_legend[k]; - - if (mp) - { - agg::rect_base<double> bb; - mp->get_bounding_rect(bb); - - double bb_dx = bb.x2 - bb.x1, bb_dy = bb.y2 - bb.y1; - double dx, dy; - double px, py; - switch (k) - { - case right: - dx = max(sx * size_frac_x, bb_dx); - dy = dx * bb_dy / bb_dx; - px = sx - dx - ppad * sx - dxr; - py = (sy - dy) / 2; - dxr += dx + 2 * ppad * sx; - break; - case left: - dx = max(sx * size_frac_x, bb_dx); - dy = dx * bb_dy / bb_dx; - px = ppad * sx + dxr; - py = (sy - dy) / 2; - dxl += dx + 2 * ppad * sx; - break; - case bottom: - dy = sy * size_frac_y; - dx = dy * bb_dx / bb_dy; - py = ppad * sy + dyb; - px = (sx - dx) / 2; - dyb += dy + 2 * ppad * sy; - break; - case top: - dy = sy * size_frac_y; - dx = dy * bb_dx / bb_dy; - py = sy - dy - ppad * sy - dyt; - px = (sx - dx) / 2; - dyt += dy + 2 * ppad * sy; - break; - default: - /* */ - ; - } - - if (px >= 0 && py >= 0 && px + dx < sx && py + dy < sy) - { - const double x0 = canvas_mtx.tx + px, y0 = canvas_mtx.ty + py; - layout.legend_area[k] = agg::trans_affine(dx, 0.0, 0.0, dy, x0, y0); - } - else - { - plot_layout::set_area_undefined(layout.legend_area[k]); - } - } - } - - double x0 = canvas_mtx.tx + dxl, y0 = canvas_mtx.ty + dyb; - double ssx = sx - (dxl + dxr), ssy = sy - (dyb + dyt); - layout.plot_area = agg::trans_affine(ssx, 0.0, 0.0, ssy, x0, y0); - - return layout; -} - -template <class RM> -void plot<RM>::draw_legends(canvas_type& canvas, const plot_layout& layout) -{ - if (!str_is_null(&m_title)) - { - const plot_layout::point& pos = layout.title_pos; - draw::text title(m_title.cstr(), layout.title_font_size, 0.5, 0.0); - title.set_point(pos.x, pos.y); - title.apply_transform(identity_matrix, 1.0); - canvas.draw(title, colors::black); - } - - for (int k = 0; k < 4; k++) - { - plot* mp = m_legend[k]; - const agg::trans_affine& mtx = layout.legend_area[k]; - - if (mp && plot_layout::is_area_defined(mtx)) - { - agg::rect_i clip = rect_of_slot_matrix<int>(mtx); - plot_layout mp_layout = mp->compute_plot_layout(mtx, false); - mp->draw_simple(canvas, mp_layout, &clip); - } - } -} - -// Draw the axis elements and labels and set layout.plot_active_area -// to the actual plotting are matrix. -template <class RM> -void plot<RM>::draw_axis(canvas_type& canvas, plot_layout& layout, const agg::rect_i* clip) -{ - if (!m_use_units) - { - layout.plot_active_area = layout.plot_area; - return; - } - - double scale = compute_scale(layout.plot_area); - - if (clip) - canvas.clip_box(*clip); - - const agg::trans_affine& m = layout.plot_active_area; - - agg::path_storage box; - sg_object_gen<agg::conv_transform<agg::path_storage> > boxtr(box, m); - trans::stroke_a boxvs(&boxtr); - - box.move_to(0.0, 0.0); - box.line_to(0.0, 1.0); - box.line_to(1.0, 1.0); - box.line_to(1.0, 0.0); - box.close_polygon(); - - agg::path_storage mark; - sg_object_gen<agg::conv_transform<agg::path_storage> > mark_tr(mark, m); - trans::stroke_a mark_stroke(&mark_tr); - - agg::path_storage ln; - sg_object_gen<agg::conv_transform<agg::path_storage> > ln_tr(ln, m); - trans::dash_a lndash(&ln_tr); - trans::stroke_a lns(&lndash); - - const double label_text_size = get_default_font_size(text_axis_title, scale); - const double plpad = double(axis_label_prop_space) / 1000.0; - const double ptpad = double(axis_title_prop_space) / 1000.0; - - ptr_list<draw::text> labels; - - double dy_label = draw_axis_m(x_axis, m_ux, m_trans, labels, scale, mark, ln); - double dx_label = draw_axis_m(y_axis, m_uy, m_trans, labels, scale, mark, ln); - - double ppad_left = plpad, ppad_right = plpad; - double ppad_bottom = plpad, ppad_top = plpad; - double dx_left = dx_label, dx_right = 0.0; - double dy_bottom = dy_label, dy_top = 0.0; - - if (!str_is_null(&m_y_axis.title)) - { - dx_left += approx_text_height(label_text_size); - ppad_left += ptpad; - } - - if (!str_is_null(&m_x_axis.title)) - { - dy_bottom += approx_text_height(label_text_size); - ppad_bottom += ptpad; - } - - const double sx = layout.plot_area.sx, sy = layout.plot_area.sy; - const double x0 = layout.plot_area.tx, y0 = layout.plot_area.ty; - - const double xppad = (ppad_left + ppad_right); - const double lsx = (dx_left + dx_right + xppad * sx) / (1 + xppad); - - const double yppad = (ppad_bottom + ppad_top); - const double lsy = (dy_bottom + dy_top + yppad * sy) / (1 + yppad); - - const double sxr = sx - lsx; - const double syr = sy - lsy; - - const double aax = x0 + dx_left + ppad_left * sxr; - const double aay = y0 + dy_bottom + ppad_bottom * syr; - layout.set_plot_active_area(sxr, syr, aax, aay); - - for (unsigned j = 0; j < labels.size(); j++) - { - draw::text* label = labels[j]; - label->apply_transform(m, 1.0); - canvas.draw(*label, colors::black); - } - - lndash.add_dash(7.0, 3.0); - - lns.width(std_line_width(scale, 0.15)); - canvas.draw(lns, colors::black); - - mark_stroke.width(std_line_width(scale, 0.75)); - canvas.draw(mark_stroke, colors::black); - - boxvs.width(std_line_width(scale, 0.75)); - canvas.draw(boxvs, colors::black); - - if (!str_is_null(&m_x_axis.title)) - { - double labx = m.sx * 0.5 + m.tx; - double laby = y0; - - const char* text = m_x_axis.title.cstr(); - draw::text xlabel(text, label_text_size, 0.5, 0.0); - xlabel.set_point(labx, laby); - xlabel.apply_transform(identity_matrix, 1.0); - - canvas.draw(xlabel, colors::black); - } - - if (!str_is_null(&m_y_axis.title)) - { - double labx = x0; - double laby = m.sy * 0.5 + m.ty; - - const char* text = m_y_axis.title.cstr(); - draw::text ylabel(text, label_text_size, 0.5, 1.0); - ylabel.set_point(labx, laby); - ylabel.angle(M_PI/2.0); - ylabel.apply_transform(identity_matrix, 1.0); - - canvas.draw(ylabel, colors::black); - } - - if (clip) - canvas.reset_clipping(); -} - -template<class RM> -void plot<RM>::set_axis_labels_angle(axis_e axis_dir, double angle) -{ - get_axis(axis_dir).set_labels_angle(angle); - m_need_redraw = true; - compute_user_trans(); -} - -template<class RM> -void plot<RM>::set_units(bool use_units) -{ - if (m_use_units != use_units) - { - m_use_units = use_units; - m_need_redraw = true; - compute_user_trans(); - } -} - -template<class RM> -void plot<RM>::update_units() -{ - if (m_rect.is_defined()) - { - const rect_base<double>& r = m_rect.rect(); - m_ux = units(r.x1, r.x2); - m_uy = units(r.y1, r.y2); - } - else - { - m_ux = units(); - m_uy = units(); - } - - compute_user_trans(); -} - -template<class RM> -void plot<RM>::set_limits(const agg::rect_base<double>& r) -{ - m_rect.set(r); - update_units(); - m_need_redraw = true; -} - -template<class RM> -void plot<RM>::unset_limits() -{ - m_rect.clear(); - update_units(); - m_need_redraw = true; -} - -template<class RM> -void plot<RM>::layer_dispose_elements(plot<RM>::item_list* layer) -{ - unsigned n = layer->size(); - for (unsigned k = 0; k < n; k++) - { - RM::dispose(layer->at(k).vs); - } -} - -template<class RM> -bool plot<RM>::push_layer() -{ - if (m_layers.size() >= max_layers) - return false; - - item_list *new_layer = new(std::nothrow) item_list(); - if (new_layer) - { - before_draw(); - push_drawing_queue(); - m_layers.add(new_layer); - return true; - } - - return false; -} - -template<class RM> -bool plot<RM>::pop_layer() -{ - if (m_layers.size() <= 1) - return false; - - unsigned n = m_layers.size(); - item_list* layer = m_layers[n-1]; - m_layers.inc_size(-1); - layer_dispose_elements(layer); - delete layer; - - clear_drawing_queue(); - m_need_redraw = true; - - return true; -} - -template <class RM> -void plot<RM>::clear_current_layer() -{ - item_list* current = current_layer(); - clear_drawing_queue(); - layer_dispose_elements(current); - current->clear(); - m_changes_pending = m_changes_accu; - m_changes_accu.clear(); -} - -template <class RM> -int plot<RM>::current_layer_index() -{ - return m_layers.size(); -} - #endif diff --git a/agg-plot/units.h b/agg-plot/units.h index f315d804..b929e38d 100644 --- a/agg-plot/units.h +++ b/agg-plot/units.h @@ -90,7 +90,6 @@ public: val = m_units.mark_value(m_index); text = m_buffer; - text = m_buffer; m_index ++; return true; } diff --git a/agg-plot/utils.h b/agg-plot/utils.h index d1274d32..1e66be31 100644 --- a/agg-plot/utils.h +++ b/agg-plot/utils.h @@ -40,6 +40,10 @@ public: return m_list[k]; } + T* at(unsigned k) const { + return m_list[k]; + } + unsigned size() const { return m_list.size(); } diff --git a/benchmarks/results.csv b/benchmarks/results.csv new file mode 100644 index 00000000..a750caf7 --- /dev/null +++ b/benchmarks/results.csv @@ -0,0 +1,16 @@ +Test,Source,Time +ODE rk8pd,LuaJIT2 joff,10.408 +ODE rk8pd,C,1.449 +ODE rk8pd,LuaJIT2,0.732 +ODE rkf45,LuaJIT2 joff,22.27 +ODE rkf45,C,2.192 +ODE rkf45,LuaJIT2,0.95 +SF roots,LuaJIT2 joff,18.765 +SF roots,LuaJIT2 FFI,6.437 +SF roots,LuaJIT2,6.531 +VEGAS,LuaJIT2 joff,134.617 +VEGAS,C,2.509 +VEGAS,LuaJIT2,2.914 +QAG,LuaJIT2 joff,6.889 +QAG,C,1.886 +QAG,LuaJIT2,1.107 diff --git a/c028-cpm-sige.csv b/c028-cpm-sige.csv new file mode 100644 index 00000000..f67805f6 --- /dev/null +++ b/c028-cpm-sige.csv @@ -0,0 +1,1021 @@ +exec_time,reprod,repeat,tool,site,th_oxide,ri_sige,th_sige,GOF +0,1,1,QFX1001,1,2.8768,27.9672,91.3146,0.8911 +0,1,1,QFX1001,2,2.9174,27.962,88.7189,0.8952 +0,1,1,QFX1001,3,3.0534,27.9883,87.7529,0.8988 +0,1,1,QFX1001,4,3.0699,27.9698,88.1033,0.8952 +0,1,1,QFX1001,5,2.9877,27.9726,87.5407,0.8954 +0,1,1,QFX1001,6,2.9656,27.9725,88.654,0.8947 +0,1,1,QFX1001,7,3.1267,27.9691,90.0054,0.8927 +0,1,1,QFX1001,8,2.8226,28.0335,88.8976,0.8993 +0,1,1,QFX1001,9,3.5913,27.9602,88.2237,0.8939 +0,1,1,QFX1001,10,3.7521,27.9873,87.9821,0.8976 +0,1,1,QFX1001,11,3.9671,27.9711,87.4903,0.8972 +0,1,1,QFX1001,12,4.0065,27.9778,88.3878,0.8972 +0,1,1,QFX1001,13,3.768,27.9675,87.6378,0.8972 +0,1,1,QFX1001,14,2.6454,28.03,89.3415,0.8988 +0,1,1,QFX1001,15,2.9999,27.9852,88.1469,0.8949 +0,1,1,QFX1001,16,3.3563,27.9788,87.1844,0.8972 +0,1,1,QFX1001,17,3.1252,27.9697,87.9573,0.8957 +0,1,2,QFX1001,1,2.955,27.9746,91.2626,0.8915 +0,1,2,QFX1001,2,2.949,27.9771,88.6664,0.896 +0,1,2,QFX1001,3,3.0596,27.9909,87.8157,0.8987 +0,1,2,QFX1001,4,3.1502,27.9802,88.0928,0.8973 +0,1,2,QFX1001,5,3.0944,27.9695,87.5523,0.8972 +0,1,2,QFX1001,6,2.9575,27.9684,88.7325,0.8932 +0,1,2,QFX1001,7,3.1959,27.9633,89.9479,0.8932 +0,1,2,QFX1001,8,2.8787,28.0329,89.0195,0.8984 +0,1,2,QFX1001,9,3.6279,27.9679,88.2854,0.8963 +0,1,2,QFX1001,10,3.8151,27.9858,87.9602,0.8978 +0,1,2,QFX1001,11,3.993,27.9785,87.4471,0.8979 +0,1,2,QFX1001,12,3.9557,27.9851,88.3645,0.8962 +0,1,2,QFX1001,13,3.7671,27.9628,87.6516,0.8966 +0,1,2,QFX1001,14,2.6523,28.0441,89.3495,0.8989 +0,1,2,QFX1001,15,3.0374,27.978,88.2228,0.8951 +0,1,2,QFX1001,16,3.3506,27.9861,87.1881,0.896 +0,1,2,QFX1001,17,3.1066,27.964,87.9809,0.8955 +0,1,3,QFX1001,1,2.9953,27.9603,91.2843,0.8916 +0,1,3,QFX1001,2,2.9117,27.9719,88.7788,0.8946 +0,1,3,QFX1001,3,3.024,27.991,87.8271,0.8982 +0,1,3,QFX1001,4,3.1542,27.978,88.1864,0.8959 +0,1,3,QFX1001,5,3.1174,27.9671,87.5671,0.8958 +0,1,3,QFX1001,6,3.0921,27.9663,88.4532,0.8913 +0,1,3,QFX1001,7,3.2308,27.9621,89.9923,0.8934 +0,1,3,QFX1001,8,2.9012,28.0332,88.8756,0.8973 +0,1,3,QFX1001,9,3.6262,27.9676,88.2522,0.8944 +0,1,3,QFX1001,10,3.824,27.9823,87.9936,0.8985 +0,1,3,QFX1001,11,3.9913,27.9767,87.463,0.8966 +0,1,3,QFX1001,12,4.0578,27.9668,88.4117,0.8961 +0,1,3,QFX1001,13,3.854,27.9617,87.6832,0.8964 +0,1,3,QFX1001,14,2.6532,28.0362,89.4173,0.8991 +0,1,3,QFX1001,15,3.1181,27.9777,88.0958,0.8942 +0,1,3,QFX1001,16,3.4308,27.9891,87.1482,0.8971 +0,1,3,QFX1001,17,3.128,27.9793,87.937,0.8968 +0,1,4,QFX1001,1,3.0215,27.9606,91.3557,0.8909 +0,1,4,QFX1001,2,3.004,27.9715,88.7782,0.8962 +0,1,4,QFX1001,3,3.0416,27.9941,87.8659,0.8987 +0,1,4,QFX1001,4,3.2381,27.9768,88.1452,0.8968 +0,1,4,QFX1001,5,3.1712,27.9697,87.4901,0.8964 +0,1,4,QFX1001,6,3.1154,27.9625,88.659,0.8927 +0,1,4,QFX1001,7,3.2603,27.9761,89.9834,0.894 +0,1,4,QFX1001,8,2.9306,28.0387,88.9388,0.8988 +0,1,4,QFX1001,9,3.6187,27.9691,88.2616,0.895 +0,1,4,QFX1001,10,3.8866,27.9886,87.9686,0.8984 +0,1,4,QFX1001,11,4.0177,27.9766,87.5191,0.8976 +0,1,4,QFX1001,12,4.0878,27.974,88.4209,0.8957 +0,1,4,QFX1001,13,3.9321,27.9595,87.6478,0.8958 +0,1,4,QFX1001,14,2.6994,28.0291,89.3712,0.8985 +0,1,4,QFX1001,15,3.1535,27.9759,88.0372,0.8942 +0,1,4,QFX1001,16,3.4852,27.9873,87.2236,0.8976 +0,1,4,QFX1001,17,3.1766,27.9789,87.884,0.8964 +0,1,5,QFX1001,1,3.0805,27.9639,91.3832,0.8924 +0,1,5,QFX1001,2,3.0537,27.9711,88.7136,0.8952 +0,1,5,QFX1001,3,3.1078,27.993,87.8438,0.8984 +0,1,5,QFX1001,4,3.1981,27.9764,88.2034,0.8946 +0,1,5,QFX1001,5,3.1666,27.9647,87.5171,0.8961 +0,1,5,QFX1001,6,3.152,27.9733,88.5211,0.8927 +0,1,5,QFX1001,7,3.2746,27.9676,90.0312,0.894 +0,1,5,QFX1001,8,2.943,28.0406,88.9989,0.8987 +0,1,5,QFX1001,9,3.6822,27.9794,88.3033,0.895 +0,1,5,QFX1001,10,3.883,27.9903,87.9885,0.8982 +0,1,5,QFX1001,11,4.1017,27.9772,87.5236,0.8981 +0,1,5,QFX1001,12,4.1151,27.9804,88.4124,0.8968 +0,1,5,QFX1001,13,3.9181,27.9569,87.6754,0.8966 +0,1,5,QFX1001,14,2.7444,28.0296,89.3347,0.8985 +0,1,5,QFX1001,15,3.2079,27.9794,88.1296,0.8958 +0,1,5,QFX1001,16,3.497,27.9877,87.1329,0.8962 +0,1,5,QFX1001,17,3.2174,27.9782,87.9624,0.8967 +15668,1,1,QFX1002,1,3.5344,28.3869,89.946,0.913 +15668,1,1,QFX1002,2,3.4285,28.4125,87.8389,0.9165 +15668,1,1,QFX1002,3,3.5632,28.418,86.7361,0.9153 +15668,1,1,QFX1002,4,3.7042,28.4051,87.0678,0.9148 +15668,1,1,QFX1002,5,3.5974,28.4135,86.7576,0.9201 +15668,1,1,QFX1002,6,3.6503,28.4147,87.4717,0.919 +15668,1,1,QFX1002,7,3.7414,28.3964,88.6632,0.9112 +15668,1,1,QFX1002,8,3.3847,28.494,87.9582,0.9195 +15668,1,1,QFX1002,9,4.07,28.4181,87.4459,0.9198 +15668,1,1,QFX1002,10,4.3719,28.4296,86.9052,0.9156 +15668,1,1,QFX1002,11,4.67,28.4145,86.2776,0.9139 +15668,1,1,QFX1002,12,4.5882,28.4231,87.5132,0.9163 +15668,1,1,QFX1002,13,4.4483,28.4166,86.9351,0.92 +15668,1,1,QFX1002,14,3.2902,28.4891,88.541,0.9204 +15668,1,1,QFX1002,15,3.7966,28.4193,86.9925,0.9185 +15668,1,1,QFX1002,16,3.9139,28.4304,86.3021,0.9178 +15668,1,1,QFX1002,17,3.684,28.4266,86.9431,0.9173 +15668,1,2,QFX1002,1,3.6346,28.4031,89.9827,0.9131 +15668,1,2,QFX1002,2,3.5204,28.4332,87.9745,0.9187 +15668,1,2,QFX1002,3,3.6547,28.4229,86.7915,0.9166 +15668,1,2,QFX1002,4,3.8034,28.4044,87.1383,0.9148 +15668,1,2,QFX1002,5,3.7149,28.4159,86.7996,0.9198 +15668,1,2,QFX1002,6,3.7414,28.4187,87.4598,0.919 +15668,1,2,QFX1002,7,3.7858,28.4061,88.771,0.9115 +15668,1,2,QFX1002,8,3.4572,28.4953,87.9905,0.9199 +15668,1,2,QFX1002,9,4.1355,28.4348,87.4807,0.9204 +15668,1,2,QFX1002,10,4.4424,28.4307,86.944,0.9166 +15668,1,2,QFX1002,11,4.758,28.4165,86.2745,0.9142 +15668,1,2,QFX1002,12,4.6733,28.4265,87.5469,0.9168 +15668,1,2,QFX1002,13,4.5609,28.4157,86.9024,0.9199 +15668,1,2,QFX1002,14,3.3631,28.4913,88.5203,0.9198 +15668,1,2,QFX1002,15,3.9076,28.4166,86.9758,0.9188 +15668,1,2,QFX1002,16,3.993,28.4287,86.3137,0.9175 +15668,1,2,QFX1002,17,3.765,28.4279,87.0151,0.9181 +15668,1,3,QFX1002,1,3.7466,28.3957,89.9671,0.9134 +15668,1,3,QFX1002,2,3.6292,28.4264,87.9137,0.9186 +15668,1,3,QFX1002,3,3.7666,28.4223,86.7568,0.917 +15668,1,3,QFX1002,4,3.9184,28.4093,87.1013,0.9159 +15668,1,3,QFX1002,5,3.8258,28.4177,86.7652,0.9197 +15668,1,3,QFX1002,6,3.8881,28.4144,87.4745,0.9187 +15668,1,3,QFX1002,7,3.8816,28.4066,88.7573,0.9113 +15668,1,3,QFX1002,8,3.5213,28.4929,88.0383,0.9204 +15668,1,3,QFX1002,9,4.2215,28.4324,87.5498,0.921 +15668,1,3,QFX1002,10,4.5271,28.4336,86.9991,0.9174 +15668,1,3,QFX1002,11,4.858,28.4228,86.3228,0.9149 +15668,1,3,QFX1002,12,4.7633,28.4308,87.5165,0.9173 +15668,1,3,QFX1002,13,4.6466,28.4158,86.8704,0.9195 +15668,1,3,QFX1002,14,3.46,28.4903,88.516,0.9203 +15668,1,3,QFX1002,15,4.047,28.4236,86.9895,0.9183 +15668,1,3,QFX1002,16,4.0734,28.4369,86.3026,0.9184 +15668,1,3,QFX1002,17,3.8354,28.4259,87.0301,0.9176 +15668,1,4,QFX1002,1,3.8566,28.3992,89.9716,0.9139 +15668,1,4,QFX1002,2,3.7344,28.4226,87.9006,0.9172 +15668,1,4,QFX1002,3,3.8655,28.4273,86.7936,0.918 +15668,1,4,QFX1002,4,4.0318,28.4113,87.0749,0.9159 +15668,1,4,QFX1002,5,3.9383,28.417,86.772,0.92 +15668,1,4,QFX1002,6,3.9938,28.4114,87.4473,0.9188 +15668,1,4,QFX1002,7,3.9786,28.4071,88.7519,0.9124 +15668,1,4,QFX1002,8,3.5741,28.4991,88.0367,0.9205 +15668,1,4,QFX1002,9,4.2802,28.4332,87.5529,0.921 +15668,1,4,QFX1002,10,4.6117,28.4336,86.977,0.9167 +15668,1,4,QFX1002,11,4.9344,28.4216,86.2895,0.9146 +15668,1,4,QFX1002,12,4.8745,28.4323,87.5649,0.9163 +15668,1,4,QFX1002,13,4.7521,28.4219,86.8795,0.9199 +15668,1,4,QFX1002,14,3.5296,28.4936,88.5072,0.9208 +15668,1,4,QFX1002,15,4.1312,28.4157,86.9782,0.9192 +15668,1,4,QFX1002,16,4.1644,28.4325,86.2612,0.9179 +15668,1,4,QFX1002,17,3.9318,28.4334,87.0445,0.9188 +15668,1,5,QFX1002,1,3.9676,28.4014,89.9875,0.9142 +15668,1,5,QFX1002,2,3.8157,28.4338,87.9367,0.919 +15668,1,5,QFX1002,3,3.9638,28.4222,86.7768,0.9169 +15668,1,5,QFX1002,4,4.1403,28.4181,87.092,0.9167 +15668,1,5,QFX1002,5,4.04,28.4161,86.752,0.9192 +15668,1,5,QFX1002,6,4.0887,28.4201,87.4481,0.919 +15668,1,5,QFX1002,7,4.0494,28.4087,88.7256,0.9123 +15668,1,5,QFX1002,8,3.653,28.497,88.0188,0.9205 +15668,1,5,QFX1002,9,4.3706,28.4356,87.5308,0.9204 +15668,1,5,QFX1002,10,4.7131,28.4407,87.0456,0.9196 +15668,1,5,QFX1002,11,5.0237,28.4208,86.3198,0.915 +15668,1,5,QFX1002,12,4.9419,28.4239,87.4936,0.9172 +15668,1,5,QFX1002,13,4.8562,28.4181,86.8931,0.9194 +15668,1,5,QFX1002,14,3.6119,28.4971,88.4901,0.92 +15668,1,5,QFX1002,15,4.2284,28.423,86.9452,0.9185 +15668,1,5,QFX1002,16,4.227,28.4355,86.3044,0.9178 +15668,1,5,QFX1002,17,4.0184,28.4332,87.0216,0.919 +10795,1,1,QFX1003,1,3.4723,28.0508,91.3229,0.9265 +10795,1,1,QFX1003,2,3.3573,28.054,88.8815,0.9291 +10795,1,1,QFX1003,3,3.4757,28.0709,87.8251,0.9304 +10795,1,1,QFX1003,4,3.6554,28.0475,87.7957,0.9274 +10795,1,1,QFX1003,5,3.5493,28.0462,87.464,0.929 +10795,1,1,QFX1003,6,3.5554,28.0352,88.2893,0.9286 +10795,1,1,QFX1003,7,3.6763,28.0389,89.8706,0.9259 +10795,1,1,QFX1003,8,3.2501,28.1166,89.0179,0.9334 +10795,1,1,QFX1003,9,4.0106,28.0519,88.4196,0.9309 +10795,1,1,QFX1003,10,4.2888,28.0614,87.9148,0.9309 +10795,1,1,QFX1003,11,4.5449,28.0263,87.0872,0.9275 +10795,1,1,QFX1003,12,4.4947,28.08,88.4083,0.9299 +10795,1,1,QFX1003,13,4.3564,28.0414,87.5276,0.9297 +10795,1,1,QFX1003,14,3.0736,28.1166,89.5014,0.9313 +10795,1,1,QFX1003,15,3.6501,28.0488,87.9801,0.9298 +10795,1,1,QFX1003,16,3.7799,28.0681,87.5228,0.9304 +10795,1,1,QFX1003,17,3.5549,28.0581,87.9861,0.9311 +10795,1,2,QFX1003,1,3.4832,28.0493,91.3169,0.9262 +10795,1,2,QFX1003,2,3.359,28.0561,88.9536,0.929 +10795,1,2,QFX1003,3,3.4658,28.0656,87.8223,0.9295 +10795,1,2,QFX1003,4,3.6778,28.0423,87.7865,0.927 +10795,1,2,QFX1003,5,3.5807,28.0403,87.4706,0.9289 +10795,1,2,QFX1003,6,3.5927,28.0347,88.2702,0.928 +10795,1,2,QFX1003,7,3.7102,28.0407,89.8536,0.9265 +10795,1,2,QFX1003,8,3.2797,28.1216,89.0255,0.9326 +10795,1,2,QFX1003,9,4.0615,28.0511,88.3612,0.9297 +10795,1,2,QFX1003,10,4.2889,28.0595,87.9323,0.9313 +10795,1,2,QFX1003,11,4.5627,28.0475,87.1074,0.9285 +10795,1,2,QFX1003,12,4.519,28.0608,88.3895,0.9291 +10795,1,2,QFX1003,13,4.3847,28.0459,87.5418,0.9302 +10795,1,2,QFX1003,14,3.1133,28.1193,89.5057,0.9319 +10795,1,2,QFX1003,15,3.6951,28.0514,87.947,0.9296 +10795,1,2,QFX1003,16,3.8165,28.0774,87.5022,0.9299 +10795,1,2,QFX1003,17,3.5904,28.0576,87.956,0.9301 +10795,1,3,QFX1003,1,3.5122,28.0533,91.2874,0.9262 +10795,1,3,QFX1003,2,3.4016,28.0551,88.9233,0.9286 +10795,1,3,QFX1003,3,3.5196,28.0646,87.8187,0.9302 +10795,1,3,QFX1003,4,3.7183,28.0408,87.7283,0.9275 +10795,1,3,QFX1003,5,3.6403,28.0453,87.4574,0.9298 +10795,1,3,QFX1003,6,3.6499,28.042,88.2862,0.9286 +10795,1,3,QFX1003,7,3.7276,28.0539,89.7892,0.9258 +10795,1,3,QFX1003,8,3.3244,28.1139,88.9994,0.9317 +10795,1,3,QFX1003,9,4.0787,28.0508,88.3853,0.929 +10795,1,3,QFX1003,10,4.3261,28.0715,87.8964,0.9309 +10795,1,3,QFX1003,11,4.595,28.0409,87.0578,0.9288 +10795,1,3,QFX1003,12,4.5473,28.0536,88.3543,0.9293 +10795,1,3,QFX1003,13,4.4454,28.0485,87.5195,0.9289 +10795,1,3,QFX1003,14,3.1859,28.1174,89.4144,0.9315 +10795,1,3,QFX1003,15,3.7194,28.0401,87.8987,0.9294 +10795,1,3,QFX1003,16,3.8423,28.0695,87.5171,0.9314 +10795,1,3,QFX1003,17,3.6372,28.0497,87.9623,0.9301 +10795,1,4,QFX1003,1,3.5351,28.0496,91.3043,0.9261 +10795,1,4,QFX1003,2,3.4517,28.0589,88.9228,0.9276 +10795,1,4,QFX1003,3,3.5617,28.0683,87.8745,0.9301 +10795,1,4,QFX1003,4,3.7777,28.0451,87.7938,0.9266 +10795,1,4,QFX1003,5,3.6553,28.0463,87.3951,0.9297 +10795,1,4,QFX1003,6,3.682,28.0386,88.2427,0.9291 +10795,1,4,QFX1003,7,3.7599,28.0436,89.8383,0.9254 +10795,1,4,QFX1003,8,3.3993,28.1164,88.9733,0.9331 +10795,1,4,QFX1003,9,4.1127,28.0558,88.4303,0.93 +10795,1,4,QFX1003,10,4.3716,28.0757,87.9291,0.9313 +10795,1,4,QFX1003,11,4.6412,28.0374,87.0764,0.9281 +10795,1,4,QFX1003,12,4.5935,28.0713,88.3896,0.9292 +10795,1,4,QFX1003,13,4.4729,28.0461,87.5429,0.9299 +10795,1,4,QFX1003,14,3.2787,28.1284,89.4101,0.9321 +10795,1,4,QFX1003,15,3.7718,28.0451,87.8461,0.9292 +10795,1,4,QFX1003,16,3.8822,28.0716,87.5226,0.9301 +10795,1,4,QFX1003,17,3.6463,28.0546,88.0163,0.9295 +10795,1,5,QFX1003,1,3.614,28.0485,91.2679,0.9254 +10795,1,5,QFX1003,2,3.5014,28.054,88.8668,0.9285 +10795,1,5,QFX1003,3,3.6001,28.0638,87.862,0.9301 +10795,1,5,QFX1003,4,3.7947,28.0355,87.6992,0.9261 +10795,1,5,QFX1003,5,3.6965,28.0425,87.4475,0.9291 +10795,1,5,QFX1003,6,3.7019,28.0318,88.2724,0.9292 +10795,1,5,QFX1003,7,3.769,28.0426,89.8728,0.9258 +10795,1,5,QFX1003,8,3.4401,28.1207,88.9686,0.9328 +10795,1,5,QFX1003,9,4.1257,28.051,88.3983,0.9291 +10795,1,5,QFX1003,10,4.3961,28.0607,87.9256,0.9307 +10795,1,5,QFX1003,11,4.6936,28.0598,87.0744,0.9283 +10795,1,5,QFX1003,12,4.5974,28.061,88.3358,0.9297 +10795,1,5,QFX1003,13,4.5206,28.0472,87.4774,0.93 +10795,1,5,QFX1003,14,3.3197,28.1225,89.442,0.9313 +10795,1,5,QFX1003,15,3.8202,28.0548,87.8863,0.9297 +10795,1,5,QFX1003,16,3.9422,28.0676,87.4522,0.9301 +10795,1,5,QFX1003,17,3.6663,28.0492,87.9947,0.9296 +18994,1,1,QFX1006,1,4.1242,28.138,90.7455,0.9225 +18994,1,1,QFX1006,2,4.0108,28.1456,88.2548,0.9246 +18994,1,1,QFX1006,3,4.124,28.119,86.9429,0.9188 +18994,1,1,QFX1006,4,4.2862,28.1507,87.7271,0.9256 +18994,1,1,QFX1006,5,4.2196,28.1636,87.2865,0.9283 +18994,1,1,QFX1006,6,4.3585,28.1398,87.5883,0.9212 +18994,1,1,QFX1006,7,4.1391,28.1481,89.711,0.9239 +18994,1,1,QFX1006,8,3.735,28.2101,88.4601,0.927 +18994,1,1,QFX1006,9,4.5696,28.1183,87.6029,0.9219 +18994,1,1,QFX1006,10,4.828,28.1294,87.2363,0.9207 +18994,1,1,QFX1006,11,5.1295,28.1632,87.2191,0.929 +18994,1,1,QFX1006,12,5.0473,28.1643,88.1587,0.9263 +18994,1,1,QFX1006,13,5.0018,28.1597,87.3464,0.9284 +18994,1,1,QFX1006,14,3.7234,28.2518,89.1957,0.9313 +18994,1,1,QFX1006,15,4.491,28.1328,87.1663,0.923 +18994,1,1,QFX1006,16,4.3996,28.1551,86.7471,0.9253 +18994,1,1,QFX1006,17,4.1692,28.1437,87.3661,0.9244 +18994,1,2,QFX1006,1,4.1733,28.1421,90.852,0.9236 +18994,1,2,QFX1006,2,4.0525,28.1451,88.3643,0.9257 +18994,1,2,QFX1006,3,4.1406,28.1254,87.1886,0.9226 +18994,1,2,QFX1006,4,4.3466,28.1596,87.82,0.9263 +18994,1,2,QFX1006,5,4.2872,28.1644,87.2894,0.9275 +18994,1,2,QFX1006,6,4.4137,28.1321,87.6051,0.9224 +18994,1,2,QFX1006,7,4.1762,28.1487,89.775,0.9235 +18994,1,2,QFX1006,8,3.7781,28.2149,88.4538,0.9286 +18994,1,2,QFX1006,9,4.6168,28.1282,87.7008,0.9234 +18994,1,2,QFX1006,10,4.8559,28.1321,87.3552,0.9216 +18994,1,2,QFX1006,11,5.1881,28.1706,87.2042,0.9282 +18994,1,2,QFX1006,12,5.0883,28.1733,88.2233,0.928 +18994,1,2,QFX1006,13,5.0401,28.1607,87.3647,0.9283 +18994,1,2,QFX1006,14,3.7269,28.25,89.1477,0.9308 +18994,1,2,QFX1006,15,4.5524,28.1381,87.2689,0.9228 +18994,1,2,QFX1006,16,4.4497,28.1544,86.7604,0.9264 +18994,1,2,QFX1006,17,4.2257,28.1403,87.4095,0.925 +18994,1,3,QFX1006,1,4.2642,28.14,90.8266,0.922 +18994,1,3,QFX1006,2,4.0975,28.149,88.3696,0.925 +18994,1,3,QFX1006,3,4.1966,28.1205,87.0586,0.9191 +18994,1,3,QFX1006,4,4.4498,28.1626,87.8551,0.927 +18994,1,3,QFX1006,5,4.3547,28.1656,87.3208,0.9279 +18994,1,3,QFX1006,6,4.4697,28.1303,87.5948,0.9221 +18994,1,3,QFX1006,7,4.2603,28.1492,89.7682,0.9239 +18994,1,3,QFX1006,8,3.8182,28.2197,88.5628,0.9288 +18994,1,3,QFX1006,9,4.6654,28.1356,87.7788,0.9233 +18994,1,3,QFX1006,10,4.9204,28.1406,87.4073,0.924 +18994,1,3,QFX1006,11,5.2422,28.1653,87.2459,0.9303 +18994,1,3,QFX1006,12,5.157,28.1747,88.2213,0.9269 +18994,1,3,QFX1006,13,5.1235,28.1567,87.3416,0.9281 +18994,1,3,QFX1006,14,3.8079,28.2472,89.1665,0.931 +18994,1,3,QFX1006,15,4.6728,28.1384,87.2072,0.9229 +18994,1,3,QFX1006,16,4.5021,28.15,86.7277,0.9258 +18994,1,3,QFX1006,17,4.3266,28.1485,87.4118,0.9252 +18994,1,4,QFX1006,1,4.3668,28.1334,90.8237,0.9219 +18994,1,4,QFX1006,2,4.1952,28.1462,88.3571,0.9243 +18994,1,4,QFX1006,3,4.3118,28.1356,87.2098,0.9233 +18994,1,4,QFX1006,4,4.5439,28.1552,87.855,0.9262 +18994,1,4,QFX1006,5,4.4627,28.1714,87.3551,0.9301 +18994,1,4,QFX1006,6,4.5798,28.13,87.634,0.9219 +18994,1,4,QFX1006,7,4.325,28.1495,89.7917,0.9244 +18994,1,4,QFX1006,8,3.8767,28.2176,88.526,0.9297 +18994,1,4,QFX1006,9,4.7356,28.1365,87.7713,0.9241 +18994,1,4,QFX1006,10,4.9956,28.1475,87.5268,0.9257 +18994,1,4,QFX1006,11,5.3279,28.1749,87.2734,0.9299 +18994,1,4,QFX1006,12,5.2324,28.1698,88.2157,0.9274 +18994,1,4,QFX1006,13,5.2029,28.1552,87.3535,0.9275 +18994,1,4,QFX1006,14,3.8929,28.2456,89.1678,0.9316 +18994,1,4,QFX1006,15,4.7236,28.1378,87.2176,0.9227 +18994,1,4,QFX1006,16,4.5446,28.1547,86.7129,0.9254 +18994,1,4,QFX1006,17,4.3557,28.1429,87.4052,0.9255 +18994,1,5,QFX1006,1,4.4374,28.1367,90.8308,0.9226 +18994,1,5,QFX1006,2,4.2628,28.1511,88.3601,0.9246 +18994,1,5,QFX1006,3,4.3589,28.1318,87.2035,0.9229 +18994,1,5,QFX1006,4,4.6039,28.1582,87.7931,0.927 +18994,1,5,QFX1006,5,4.5203,28.1674,87.3258,0.9284 +18994,1,5,QFX1006,6,4.6707,28.1315,87.556,0.9214 +18994,1,5,QFX1006,7,4.3913,28.1446,89.7514,0.9235 +18994,1,5,QFX1006,8,3.9521,28.2233,88.5833,0.9284 +18994,1,5,QFX1006,9,4.7637,28.1261,87.7943,0.9228 +18994,1,5,QFX1006,10,5.0523,28.1511,87.5287,0.9242 +18994,1,5,QFX1006,11,5.3908,28.175,87.2544,0.9297 +18994,1,5,QFX1006,12,5.3312,28.1746,88.2038,0.9272 +18994,1,5,QFX1006,13,5.2867,28.1632,87.3215,0.9276 +18994,1,5,QFX1006,14,3.9509,28.248,89.1568,0.9308 +18994,1,5,QFX1006,15,4.8434,28.1374,87.1955,0.9235 +18994,1,5,QFX1006,16,4.6106,28.1504,86.7345,0.9246 +18994,1,5,QFX1006,17,4.4527,28.153,87.446,0.9261 +31020,2,1,QFX1001,1,4.8775,27.9332,90.4024,0.888 +31020,2,1,QFX1001,2,4.7037,27.9321,87.8458,0.8912 +31020,2,1,QFX1001,3,4.8318,27.9536,86.973,0.8939 +31020,2,1,QFX1001,4,5.1065,27.9353,87.2663,0.8917 +31020,2,1,QFX1001,5,4.9963,27.9427,86.6666,0.8936 +31020,2,1,QFX1001,6,4.9973,27.9357,87.65,0.8897 +31020,2,1,QFX1001,7,4.7887,27.949,89.1303,0.891 +31020,2,1,QFX1001,8,4.2573,28.028,88.2,0.8965 +31020,2,1,QFX1001,9,5.1465,27.9408,87.5917,0.8923 +31020,2,1,QFX1001,10,5.4625,27.9691,87.3816,0.8952 +31020,2,1,QFX1001,11,5.737,27.9604,86.8929,0.8958 +31020,2,1,QFX1001,12,5.7317,27.9669,87.8337,0.8945 +31020,2,1,QFX1001,13,5.6196,27.9585,86.949,0.8966 +31020,2,1,QFX1001,14,4.2464,28.0236,88.5171,0.8952 +31020,2,1,QFX1001,15,5.1813,27.9435,87.2044,0.8913 +31020,2,1,QFX1001,16,5.0215,27.9674,86.4908,0.896 +31020,2,1,QFX1001,17,4.8672,27.9447,87.1922,0.893 +31020,2,2,QFX1001,1,4.8606,27.9315,90.5315,0.887 +31020,2,2,QFX1001,2,4.7499,27.9449,87.9474,0.8923 +31020,2,2,QFX1001,3,4.8548,27.965,86.9852,0.8953 +31020,2,2,QFX1001,4,5.1255,27.941,87.2348,0.8927 +31020,2,2,QFX1001,5,5.0218,27.9362,86.6698,0.892 +31020,2,2,QFX1001,6,4.9502,27.9367,87.8506,0.8908 +31020,2,2,QFX1001,7,4.8271,27.9443,89.2232,0.8907 +31020,2,2,QFX1001,8,4.2972,28.0136,88.1984,0.8966 +31020,2,2,QFX1001,9,5.2089,27.9558,87.5123,0.894 +31020,2,2,QFX1001,10,5.4613,27.9629,87.4263,0.8955 +31020,2,2,QFX1001,11,5.6937,27.9658,87.0205,0.8953 +31020,2,2,QFX1001,12,5.7042,27.9685,87.7337,0.8948 +31020,2,2,QFX1001,13,5.6167,27.9565,87.0788,0.8953 +31020,2,2,QFX1001,14,4.2888,28.0089,88.5498,0.8947 +31020,2,2,QFX1001,15,5.158,27.9517,87.3143,0.8925 +31020,2,2,QFX1001,16,5.0269,27.9692,86.5345,0.8955 +31020,2,2,QFX1001,17,4.812,27.9565,87.213,0.893 +31020,2,3,QFX1001,1,4.9524,27.9302,90.4331,0.8883 +31020,2,3,QFX1001,2,4.7564,27.9431,87.976,0.8922 +31020,2,3,QFX1001,3,4.8808,27.9652,87.053,0.8955 +31020,2,3,QFX1001,4,5.033,27.9358,87.5369,0.8916 +31020,2,3,QFX1001,5,4.9731,27.9405,86.7878,0.8925 +31020,2,3,QFX1001,6,4.993,27.9426,87.7899,0.8901 +31020,2,3,QFX1001,7,4.8889,27.9386,89.3319,0.8894 +31020,2,3,QFX1001,8,4.3101,28.0132,88.2764,0.896 +31020,2,3,QFX1001,9,5.2127,27.9491,87.6182,0.8934 +31020,2,3,QFX1001,10,5.4532,27.9712,87.4685,0.8951 +31020,2,3,QFX1001,11,5.6923,27.9677,87.1112,0.8961 +31020,2,3,QFX1001,12,5.7047,27.9545,87.8215,0.8927 +31020,2,3,QFX1001,13,5.6566,27.9516,87.0655,0.8945 +31020,2,3,QFX1001,14,4.3812,28.0139,88.4982,0.8957 +31020,2,3,QFX1001,15,5.172,27.949,87.2606,0.8918 +31020,2,3,QFX1001,16,4.9956,27.9682,86.4981,0.8946 +31020,2,3,QFX1001,17,4.8654,27.9521,87.2064,0.8927 +31020,2,4,QFX1001,1,4.9328,27.9321,90.4738,0.8883 +31020,2,4,QFX1001,2,4.7609,27.9464,87.98,0.8916 +31020,2,4,QFX1001,3,4.8327,27.9658,87.0863,0.8954 +31020,2,4,QFX1001,4,5.1202,27.9349,87.411,0.8922 +31020,2,4,QFX1001,5,5.0045,27.9452,86.8106,0.8917 +31020,2,4,QFX1001,6,5.0284,27.9454,87.723,0.8902 +31020,2,4,QFX1001,7,4.9156,27.9454,89.2425,0.8906 +31020,2,4,QFX1001,8,4.3431,28.0213,88.2731,0.8971 +31020,2,4,QFX1001,9,5.1925,27.9544,87.7247,0.8926 +31020,2,4,QFX1001,10,5.514,27.9724,87.5006,0.8955 +31020,2,4,QFX1001,11,5.7199,27.9677,87.0548,0.8952 +31020,2,4,QFX1001,12,5.741,27.9638,87.916,0.8939 +31020,2,4,QFX1001,13,5.6802,27.9538,87.0237,0.8954 +31020,2,4,QFX1001,14,4.3639,28.0134,88.4549,0.8956 +31020,2,4,QFX1001,15,5.2249,27.9477,87.196,0.8925 +31020,2,4,QFX1001,16,5.0276,27.963,86.4799,0.8944 +31020,2,4,QFX1001,17,4.8905,27.9502,87.2895,0.8936 +31020,2,5,QFX1001,1,4.9085,27.9411,90.5834,0.888 +31020,2,5,QFX1001,2,4.7716,27.9501,88.0331,0.8918 +31020,2,5,QFX1001,3,4.8963,27.9575,87.0613,0.8938 +31020,2,5,QFX1001,4,5.1354,27.9293,87.4289,0.8909 +31020,2,5,QFX1001,5,5.0353,27.95,86.8058,0.8934 +31020,2,5,QFX1001,6,5.0482,27.9443,87.7894,0.8908 +31020,2,5,QFX1001,7,4.8967,27.9457,89.3531,0.8909 +31020,2,5,QFX1001,8,4.3331,28.0346,88.2524,0.8963 +31020,2,5,QFX1001,9,5.2473,27.9556,87.6989,0.893 +31020,2,5,QFX1001,10,5.4932,27.9756,87.4766,0.8958 +31020,2,5,QFX1001,11,5.773,27.9658,87.0189,0.8942 +31020,2,5,QFX1001,12,5.7628,27.9639,87.8788,0.8936 +31020,2,5,QFX1001,13,5.7285,27.949,87.0677,0.8952 +31020,2,5,QFX1001,14,4.3713,28.0168,88.4218,0.8956 +31020,2,5,QFX1001,15,5.1863,27.9565,87.2974,0.8919 +31020,2,5,QFX1001,16,5.065,27.9678,86.5154,0.8936 +31020,2,5,QFX1001,17,4.9287,27.9453,87.17,0.8933 +37175,2,1,QFX1002,1,5.1819,28.3732,89.4643,0.9126 +37175,2,1,QFX1002,2,4.9743,28.411,87.3517,0.9178 +37175,2,1,QFX1002,3,5.0935,28.3983,86.2565,0.9153 +37175,2,1,QFX1002,4,5.3273,28.4015,86.6372,0.9146 +37175,2,1,QFX1002,5,5.1785,28.4015,86.2846,0.9189 +37175,2,1,QFX1002,6,5.2722,28.3987,86.9863,0.9183 +37175,2,1,QFX1002,7,5.0701,28.391,88.3,0.9114 +37175,2,1,QFX1002,8,4.4875,28.4905,87.5594,0.9198 +37175,2,1,QFX1002,9,5.3319,28.4157,87.0721,0.9192 +37175,2,1,QFX1002,10,5.6881,28.4215,86.5686,0.917 +37175,2,1,QFX1002,11,6.0075,28.4181,85.9592,0.9145 +37175,2,1,QFX1002,12,5.8822,28.423,87.259,0.9173 +37175,2,1,QFX1002,13,5.879,28.4133,86.5581,0.9193 +37175,2,1,QFX1002,14,4.5517,28.4854,88.0568,0.92 +37175,2,1,QFX1002,15,5.4933,28.4122,86.4663,0.9182 +37175,2,1,QFX1002,16,5.2136,28.4182,85.8969,0.9173 +37175,2,1,QFX1002,17,5.089,28.4147,86.5207,0.9159 +37175,2,2,QFX1002,1,5.2475,28.3835,89.51,0.9136 +37175,2,2,QFX1002,2,5.0486,28.4106,87.415,0.9182 +37175,2,2,QFX1002,3,5.1646,28.4072,86.3205,0.9166 +37175,2,2,QFX1002,4,5.3852,28.4035,86.6383,0.9152 +37175,2,2,QFX1002,5,5.2745,28.3996,86.3648,0.9193 +37175,2,2,QFX1002,6,5.3131,28.3989,87.0361,0.9192 +37175,2,2,QFX1002,7,5.1537,28.3882,88.3825,0.9118 +37175,2,2,QFX1002,8,4.5267,28.4856,87.5985,0.9192 +37175,2,2,QFX1002,9,5.4116,28.4138,87.1026,0.92 +37175,2,2,QFX1002,10,5.7596,28.418,86.6585,0.9166 +37175,2,2,QFX1002,11,6.0906,28.422,85.9772,0.9147 +37175,2,2,QFX1002,12,5.9543,28.4281,87.249,0.9169 +37175,2,2,QFX1002,13,5.9629,28.4147,86.4866,0.9193 +37175,2,2,QFX1002,14,4.6144,28.4793,88.0689,0.9199 +37175,2,2,QFX1002,15,5.5814,28.4069,86.4638,0.9179 +37175,2,2,QFX1002,16,5.273,28.4245,85.9266,0.918 +37175,2,2,QFX1002,17,5.1519,28.4193,86.609,0.9176 +37175,2,3,QFX1002,1,5.3463,28.3819,89.5002,0.9133 +37175,2,3,QFX1002,2,5.096,28.4102,87.4542,0.9185 +37175,2,3,QFX1002,3,5.2178,28.4095,86.3476,0.916 +37175,2,3,QFX1002,4,5.4931,28.3974,86.6423,0.9151 +37175,2,3,QFX1002,5,5.331,28.4018,86.3441,0.9191 +37175,2,3,QFX1002,6,5.4061,28.4031,86.9929,0.9189 +37175,2,3,QFX1002,7,5.2018,28.3968,88.3638,0.9118 +37175,2,3,QFX1002,8,4.5582,28.4949,87.6108,0.9209 +37175,2,3,QFX1002,9,5.4582,28.4108,87.1475,0.9194 +37175,2,3,QFX1002,10,5.8016,28.4323,86.6742,0.9166 +37175,2,3,QFX1002,11,6.0922,28.4197,85.9724,0.9141 +37175,2,3,QFX1002,12,6.0102,28.4286,87.2222,0.9163 +37175,2,3,QFX1002,13,6.0104,28.4043,86.4432,0.9188 +37175,2,3,QFX1002,14,4.6535,28.4807,88.0199,0.9193 +37175,2,3,QFX1002,15,5.625,28.4002,86.4998,0.9187 +37175,2,3,QFX1002,16,5.3297,28.4221,85.9603,0.918 +37175,2,3,QFX1002,17,5.2212,28.4163,86.5862,0.9187 +37175,2,4,QFX1002,1,5.4044,28.3861,89.4974,0.9134 +37175,2,4,QFX1002,2,5.1655,28.4127,87.4441,0.9179 +37175,2,4,QFX1002,3,5.2751,28.4044,86.3238,0.9158 +37175,2,4,QFX1002,4,5.5263,28.4037,86.6831,0.9156 +37175,2,4,QFX1002,5,5.3847,28.4044,86.3104,0.9195 +37175,2,4,QFX1002,6,5.4692,28.4058,87.0175,0.9192 +37175,2,4,QFX1002,7,5.2585,28.3947,88.3388,0.9118 +37175,2,4,QFX1002,8,4.6355,28.4895,87.6177,0.9212 +37175,2,4,QFX1002,9,5.5063,28.4185,87.1723,0.9196 +37175,2,4,QFX1002,10,5.8584,28.4253,86.6554,0.9173 +37175,2,4,QFX1002,11,6.2104,28.4263,85.965,0.9142 +37175,2,4,QFX1002,12,6.0458,28.4254,87.2637,0.9173 +37175,2,4,QFX1002,13,6.0661,28.4143,86.5012,0.9197 +37175,2,4,QFX1002,14,4.7303,28.4833,88.047,0.9195 +37175,2,4,QFX1002,15,5.7018,28.4125,86.4992,0.9183 +37175,2,4,QFX1002,16,5.3926,28.4232,85.9321,0.9167 +37175,2,4,QFX1002,17,5.2551,28.4201,86.561,0.918 +37175,2,5,QFX1002,1,5.5034,28.3873,89.5209,0.9131 +37175,2,5,QFX1002,2,5.219,28.4131,87.4683,0.918 +37175,2,5,QFX1002,3,5.3583,28.4144,86.3712,0.9162 +37175,2,5,QFX1002,4,5.5881,28.4006,86.6743,0.9148 +37175,2,5,QFX1002,5,5.4693,28.4006,86.3226,0.9196 +37175,2,5,QFX1002,6,5.5327,28.4071,87.0415,0.9196 +37175,2,5,QFX1002,7,5.3308,28.3914,88.3386,0.9123 +37175,2,5,QFX1002,8,4.6634,28.487,87.6183,0.9203 +37175,2,5,QFX1002,9,5.5473,28.4223,87.1603,0.9203 +37175,2,5,QFX1002,10,5.8937,28.4251,86.6911,0.9174 +37175,2,5,QFX1002,11,6.2548,28.4246,86.0145,0.9145 +37175,2,5,QFX1002,12,6.1091,28.4334,87.2882,0.9169 +37175,2,5,QFX1002,13,6.1024,28.4166,86.5607,0.9188 +37175,2,5,QFX1002,14,4.7657,28.4918,88.0892,0.9192 +37175,2,5,QFX1002,15,5.7516,28.4098,86.5425,0.9185 +37175,2,5,QFX1002,16,5.454,28.4268,85.9507,0.9181 +37175,2,5,QFX1002,17,5.347,28.4147,86.5607,0.9176 +34318,2,1,QFX1003,1,5.1042,28.0328,90.5455,0.9239 +34318,2,1,QFX1003,2,4.8874,28.0237,88.2311,0.9265 +34318,2,1,QFX1003,3,5.0175,28.0531,87.1499,0.9264 +34318,2,1,QFX1003,4,5.2908,28.016,87.0952,0.9236 +34318,2,1,QFX1003,5,5.172,28.0195,86.7924,0.927 +34318,2,1,QFX1003,6,5.2216,28.0243,87.6795,0.927 +34318,2,1,QFX1003,7,5.0578,28.0219,89.2142,0.9229 +34318,2,1,QFX1003,8,4.4249,28.097,88.3406,0.93 +34318,2,1,QFX1003,9,5.318,28.0265,87.857,0.9281 +34318,2,1,QFX1003,10,5.6535,28.0536,87.4034,0.9295 +34318,2,1,QFX1003,11,5.9811,28.0257,86.589,0.9246 +34318,2,1,QFX1003,12,5.8421,28.0487,87.8544,0.9273 +34318,2,1,QFX1003,13,5.8494,28.0249,87.0027,0.9276 +34318,2,1,QFX1003,14,4.4411,28.1083,88.7908,0.9294 +34318,2,1,QFX1003,15,5.4067,28.0213,87.3073,0.9275 +34318,2,1,QFX1003,16,5.1391,28.0489,86.9717,0.9308 +34318,2,1,QFX1003,17,4.9951,28.0338,87.3927,0.9281 +34318,2,2,QFX1003,1,5.1164,28.0239,90.6335,0.9237 +34318,2,2,QFX1003,2,4.8915,28.0253,88.2426,0.9258 +34318,2,2,QFX1003,3,5.0358,28.0689,87.1699,0.927 +34318,2,2,QFX1003,4,5.2847,28.0193,87.1079,0.9239 +34318,2,2,QFX1003,5,5.1864,28.0307,86.7913,0.928 +34318,2,2,QFX1003,6,5.2382,28.0092,87.6452,0.9261 +34318,2,2,QFX1003,7,5.0485,28.0253,89.2716,0.9237 +34318,2,2,QFX1003,8,4.4437,28.1044,88.38,0.9307 +34318,2,2,QFX1003,9,5.3208,28.0432,87.8492,0.9283 +34318,2,2,QFX1003,10,5.6631,28.0564,87.3567,0.9295 +34318,2,2,QFX1003,11,5.9783,28.0225,86.5435,0.9261 +34318,2,2,QFX1003,12,5.8642,28.0476,87.8673,0.9267 +34318,2,2,QFX1003,13,5.8469,28.0214,86.992,0.9269 +34318,2,2,QFX1003,14,4.4795,28.1067,88.7762,0.9299 +34318,2,2,QFX1003,15,5.4167,28.0276,87.2391,0.9271 +34318,2,2,QFX1003,16,5.1585,28.0584,86.916,0.9301 +34318,2,2,QFX1003,17,4.9978,28.0312,87.3455,0.9274 +34318,2,3,QFX1003,1,5.1526,28.0232,90.5632,0.9233 +34318,2,3,QFX1003,2,4.9377,28.0243,88.1725,0.9254 +34318,2,3,QFX1003,3,5.0463,28.0427,87.1809,0.9285 +34318,2,3,QFX1003,4,5.332,28.0139,87.0982,0.9242 +34318,2,3,QFX1003,5,5.2076,28.018,86.7429,0.9253 +34318,2,3,QFX1003,6,5.2322,28.0123,87.6399,0.9258 +34318,2,3,QFX1003,7,5.056,28.0187,89.2389,0.924 +34318,2,3,QFX1003,8,4.4819,28.1188,88.3598,0.931 +34318,2,3,QFX1003,9,5.366,28.038,87.8905,0.9283 +34318,2,3,QFX1003,10,5.7063,28.0676,87.3679,0.929 +34318,2,3,QFX1003,11,6.0235,28.0305,86.6061,0.9262 +34318,2,3,QFX1003,12,5.922,28.0446,87.8742,0.9278 +34318,2,3,QFX1003,13,5.9074,28.0318,87.0203,0.9283 +34318,2,3,QFX1003,14,4.5001,28.1045,88.7731,0.9299 +34318,2,3,QFX1003,15,5.446,28.024,87.2528,0.9269 +34318,2,3,QFX1003,16,5.1971,28.0671,86.9277,0.9282 +34318,2,3,QFX1003,17,5.0306,28.0332,87.3703,0.9276 +34318,2,4,QFX1003,1,5.1602,28.0275,90.614,0.9235 +34318,2,4,QFX1003,2,4.9766,28.0316,88.3003,0.9263 +34318,2,4,QFX1003,3,5.0588,28.0646,87.2017,0.9271 +34318,2,4,QFX1003,4,5.3729,28.0204,87.1157,0.9244 +34318,2,4,QFX1003,5,5.2415,28.0204,86.7958,0.9263 +34318,2,4,QFX1003,6,5.282,28.0125,87.6437,0.9262 +34318,2,4,QFX1003,7,5.07,28.0175,89.2552,0.9231 +34318,2,4,QFX1003,8,4.511,28.1046,88.4346,0.9307 +34318,2,4,QFX1003,9,5.3793,28.0426,87.8915,0.9281 +34318,2,4,QFX1003,10,5.7108,28.0611,87.4177,0.9299 +34318,2,4,QFX1003,11,6.0261,28.0316,86.6004,0.9266 +34318,2,4,QFX1003,12,5.9285,28.041,87.8389,0.9278 +34318,2,4,QFX1003,13,5.9092,28.0179,86.9097,0.9271 +34318,2,4,QFX1003,14,4.5398,28.1041,88.7972,0.9302 +34318,2,4,QFX1003,15,5.4743,28.0365,87.2771,0.9282 +34318,2,4,QFX1003,16,5.2046,28.0586,86.9251,0.9287 +34318,2,4,QFX1003,17,5.0456,28.0352,87.4223,0.9269 +34318,2,5,QFX1003,1,5.2111,28.0296,90.6095,0.9239 +34318,2,5,QFX1003,2,4.9694,28.0279,88.2709,0.9255 +34318,2,5,QFX1003,3,5.0863,28.0388,87.1657,0.9276 +34318,2,5,QFX1003,4,5.3924,28.0244,87.1139,0.9256 +34318,2,5,QFX1003,5,5.2682,28.0341,86.7642,0.9257 +34318,2,5,QFX1003,6,5.3205,28.0134,87.6504,0.9257 +34318,2,5,QFX1003,7,5.1266,28.0331,89.2443,0.9237 +34318,2,5,QFX1003,8,4.5462,28.1187,88.3811,0.931 +34318,2,5,QFX1003,9,5.4078,28.0392,87.9412,0.9284 +34318,2,5,QFX1003,10,5.7272,28.0575,87.4595,0.9305 +34318,2,5,QFX1003,11,6.0711,28.0354,86.5565,0.9261 +34318,2,5,QFX1003,12,5.9536,28.0448,87.8436,0.9273 +34318,2,5,QFX1003,13,5.9807,28.0329,87.0178,0.9288 +34318,2,5,QFX1003,14,4.5956,28.1053,88.7135,0.9305 +34318,2,5,QFX1003,15,5.5147,28.0239,87.2745,0.9269 +34318,2,5,QFX1003,16,5.2343,28.0545,86.9921,0.9294 +34318,2,5,QFX1003,17,5.1026,28.0379,87.3977,0.9278 +39858,2,1,QFX1006,1,5.5416,28.133,90.5185,0.9227 +39858,2,1,QFX1006,2,5.3573,28.1523,88.1074,0.9263 +39858,2,1,QFX1006,3,5.4345,28.1334,87.0008,0.9237 +39858,2,1,QFX1006,4,5.7036,28.1519,87.501,0.9272 +39858,2,1,QFX1006,5,5.5989,28.1644,87.0924,0.9292 +39858,2,1,QFX1006,6,5.7025,28.1218,87.236,0.9217 +39858,2,1,QFX1006,7,5.3489,28.1533,89.5226,0.9249 +39858,2,1,QFX1006,8,4.7576,28.2137,88.1637,0.928 +39858,2,1,QFX1006,9,5.6956,28.1364,87.5157,0.9249 +39858,2,1,QFX1006,10,5.9639,28.1478,87.382,0.9266 +39858,2,1,QFX1006,11,6.2668,28.1603,87.0287,0.9281 +39858,2,1,QFX1006,12,6.187,28.1898,88.123,0.9299 +39858,2,1,QFX1006,13,6.1905,28.1796,87.3441,0.9304 +39858,2,1,QFX1006,14,4.8292,28.2546,88.9652,0.932 +39858,2,1,QFX1006,15,5.9355,28.1277,86.9463,0.9234 +39858,2,1,QFX1006,16,5.555,28.1553,86.7096,0.9277 +39858,2,1,QFX1006,17,5.4178,28.1286,87.2167,0.9241 +39858,2,2,QFX1006,1,5.5801,28.1341,90.5619,0.9218 +39858,2,2,QFX1006,2,5.3899,28.1412,88.089,0.925 +39858,2,2,QFX1006,3,5.4675,28.1317,87.0086,0.9246 +39858,2,2,QFX1006,4,5.7158,28.1541,87.5135,0.9257 +39858,2,2,QFX1006,5,5.6617,28.17,87.0177,0.9288 +39858,2,2,QFX1006,6,5.7634,28.1275,87.3317,0.9213 +39858,2,2,QFX1006,7,5.4001,28.1519,89.583,0.9243 +39858,2,2,QFX1006,8,4.7889,28.214,88.2031,0.928 +39858,2,2,QFX1006,9,5.7268,28.1496,87.6168,0.925 +39858,2,2,QFX1006,10,5.9893,28.1558,87.3941,0.9271 +39858,2,2,QFX1006,11,6.286,28.1658,87.0375,0.9297 +39858,2,2,QFX1006,12,6.2249,28.1931,88.1188,0.9289 +39858,2,2,QFX1006,13,6.2207,28.1849,87.3801,0.931 +39858,2,2,QFX1006,14,4.8542,28.256,88.9563,0.9323 +39858,2,2,QFX1006,15,5.9648,28.1279,86.9099,0.9228 +39858,2,2,QFX1006,16,5.5515,28.1562,86.6955,0.9271 +39858,2,2,QFX1006,17,5.476,28.1485,87.2712,0.9262 +39858,2,3,QFX1006,1,5.6187,28.1236,90.5162,0.922 +39858,2,3,QFX1006,2,5.4391,28.1473,88.1262,0.9247 +39858,2,3,QFX1006,3,5.5233,28.1245,86.9595,0.9226 +39858,2,3,QFX1006,4,5.7585,28.1314,87.3965,0.9235 +39858,2,3,QFX1006,5,5.6814,28.1577,86.9557,0.9286 +39858,2,3,QFX1006,6,5.7938,28.1113,87.2198,0.9197 +39858,2,3,QFX1006,7,5.3992,28.142,89.5355,0.9234 +39858,2,3,QFX1006,8,4.793,28.2089,88.1949,0.9276 +39858,2,3,QFX1006,9,5.7634,28.1314,87.5819,0.9242 +39858,2,3,QFX1006,10,6.0371,28.1444,87.3516,0.9264 +39858,2,3,QFX1006,11,6.3102,28.1525,86.9858,0.9285 +39858,2,3,QFX1006,12,6.2395,28.1711,88.0474,0.9273 +39858,2,3,QFX1006,13,6.2833,28.1761,87.2855,0.93 +39858,2,3,QFX1006,14,4.9309,28.2505,88.8825,0.931 +39858,2,3,QFX1006,15,6.0046,28.1193,86.8373,0.9211 +39858,2,3,QFX1006,16,5.5748,28.1515,86.6764,0.9271 +39858,2,3,QFX1006,17,5.5076,28.1424,87.1939,0.9245 +39858,2,4,QFX1006,1,5.6562,28.1261,90.4943,0.921 +39858,2,4,QFX1006,2,5.4906,28.1382,88.1441,0.9252 +39858,2,4,QFX1006,3,5.6055,28.1328,87.0138,0.9241 +39858,2,4,QFX1006,4,5.8192,28.1365,87.4317,0.9246 +39858,2,4,QFX1006,5,5.7315,28.1483,86.9541,0.9281 +39858,2,4,QFX1006,6,5.8454,28.1122,87.2509,0.9204 +39858,2,4,QFX1006,7,5.443,28.1518,89.5789,0.9253 +39858,2,4,QFX1006,8,4.8241,28.2086,88.1974,0.9287 +39858,2,4,QFX1006,9,5.7803,28.132,87.5413,0.9244 +39858,2,4,QFX1006,10,6.0774,28.1472,87.3799,0.926 +39858,2,4,QFX1006,11,6.3902,28.1502,86.9442,0.9286 +39858,2,4,QFX1006,12,6.2886,28.1731,88.0655,0.9275 +39858,2,4,QFX1006,13,6.337,28.1733,87.2658,0.9304 +39858,2,4,QFX1006,14,4.9602,28.247,88.8608,0.9315 +39858,2,4,QFX1006,15,6.057,28.128,86.8591,0.9216 +39858,2,4,QFX1006,16,5.6446,28.1546,86.6829,0.9263 +39858,2,4,QFX1006,17,5.5501,28.1377,87.1797,0.9254 +39858,2,5,QFX1006,1,5.733,28.1347,90.5715,0.9231 +39858,2,5,QFX1006,2,5.5239,28.1545,88.176,0.9269 +39858,2,5,QFX1006,3,5.6231,28.1396,87.0783,0.925 +39858,2,5,QFX1006,4,5.8869,28.1567,87.5331,0.9258 +39858,2,5,QFX1006,5,5.8069,28.1601,87.0841,0.9296 +39858,2,5,QFX1006,6,5.8873,28.1261,87.3123,0.9211 +39858,2,5,QFX1006,7,5.526,28.163,89.6227,0.9254 +39858,2,5,QFX1006,8,4.8619,28.2256,88.3671,0.931 +39858,2,5,QFX1006,9,5.8497,28.1435,87.6408,0.9254 +39858,2,5,QFX1006,10,6.1228,28.1533,87.4439,0.9275 +39858,2,5,QFX1006,11,6.4223,28.1578,87.0388,0.9283 +39858,2,5,QFX1006,12,6.3361,28.1848,88.1106,0.9285 +39858,2,5,QFX1006,13,6.3672,28.1753,87.2823,0.9298 +39858,2,5,QFX1006,14,4.9993,28.2536,88.904,0.9328 +39858,2,5,QFX1006,15,6.1288,28.1365,86.8746,0.9232 +39858,2,5,QFX1006,16,5.6888,28.1644,86.7059,0.928 +39858,2,5,QFX1006,17,5.5963,28.1469,87.227,0.9262 +53998,3,1,QFX1001,1,6.063,27.9308,90.1249,0.8863 +53998,3,1,QFX1001,2,5.921,27.9304,87.5722,0.89 +53998,3,1,QFX1001,3,6.0127,27.9589,86.583,0.8929 +53998,3,1,QFX1001,4,6.2308,27.9363,87.0652,0.8905 +53998,3,1,QFX1001,5,6.1301,27.9264,86.5211,0.8911 +53998,3,1,QFX1001,6,6.0797,27.9298,87.3542,0.8875 +53998,3,1,QFX1001,7,5.8431,27.9403,88.8927,0.8884 +53998,3,1,QFX1001,8,5.1698,28.017,87.9569,0.8942 +53998,3,1,QFX1001,9,6.0919,27.9543,87.3788,0.8924 +53998,3,1,QFX1001,10,6.442,27.9744,87.1144,0.8945 +53998,3,1,QFX1001,11,6.6555,27.9696,86.7074,0.8946 +53998,3,1,QFX1001,12,6.596,27.9621,87.6543,0.8922 +53998,3,1,QFX1001,13,6.6512,27.9438,86.6527,0.8945 +53998,3,1,QFX1001,14,5.3617,28.0079,88.1159,0.8933 +53998,3,1,QFX1001,15,6.3454,27.9434,86.9638,0.8908 +53998,3,1,QFX1001,16,6.0104,27.9531,86.2276,0.8924 +53998,3,1,QFX1001,17,5.9715,27.9331,86.8963,0.8902 +53998,3,2,QFX1001,1,6.1519,27.9263,90.0644,0.8858 +53998,3,2,QFX1001,2,5.9259,27.944,87.6335,0.8905 +53998,3,2,QFX1001,3,6.0453,27.9585,86.7362,0.8937 +53998,3,2,QFX1001,4,6.2836,27.9266,87.0894,0.8891 +53998,3,2,QFX1001,5,6.1519,27.9236,86.5601,0.89 +53998,3,2,QFX1001,6,6.112,27.9235,87.5551,0.8858 +53998,3,2,QFX1001,7,5.8472,27.9372,88.9502,0.8876 +53998,3,2,QFX1001,8,5.2518,28.0094,88.0161,0.8955 +53998,3,2,QFX1001,9,6.1442,27.9538,87.433,0.8907 +53998,3,2,QFX1001,10,6.4702,27.9773,87.1728,0.8947 +53998,3,2,QFX1001,11,6.7255,27.9707,86.6602,0.8955 +53998,3,2,QFX1001,12,6.6497,27.9574,87.6781,0.8908 +53998,3,2,QFX1001,13,6.6907,27.9423,86.6928,0.8932 +53998,3,2,QFX1001,14,5.3663,28.0038,88.2686,0.8943 +53998,3,2,QFX1001,15,6.327,27.9351,86.942,0.8882 +53998,3,2,QFX1001,16,6.0265,27.9588,86.2049,0.8919 +53998,3,2,QFX1001,17,5.9293,27.9339,86.7973,0.8896 +53998,3,3,QFX1001,1,6.1237,27.9417,90.2269,0.888 +53998,3,3,QFX1001,2,5.9534,27.9311,87.6477,0.8902 +53998,3,3,QFX1001,3,6.0353,27.9575,86.8107,0.8933 +53998,3,3,QFX1001,4,6.3007,27.9386,87.123,0.8898 +53998,3,3,QFX1001,5,6.2386,27.9335,86.4954,0.891 +53998,3,3,QFX1001,6,6.1424,27.9371,87.4937,0.8879 +53998,3,3,QFX1001,7,5.8965,27.9369,89,0.888 +53998,3,3,QFX1001,8,5.1868,28.0126,87.9242,0.8935 +53998,3,3,QFX1001,9,6.1461,27.948,87.4508,0.8906 +53998,3,3,QFX1001,10,6.4711,27.9779,87.1779,0.8943 +53998,3,3,QFX1001,11,6.675,27.9662,86.673,0.8941 +53998,3,3,QFX1001,12,6.6107,27.9639,87.643,0.8936 +53998,3,3,QFX1001,13,6.6618,27.9384,86.7621,0.892 +53998,3,3,QFX1001,14,5.3553,28.0051,88.2805,0.8928 +53998,3,3,QFX1001,15,6.4265,27.937,86.9783,0.8894 +53998,3,3,QFX1001,16,6.0903,27.9563,86.2278,0.8933 +53998,3,3,QFX1001,17,5.9504,27.9417,86.8879,0.8907 +53998,3,4,QFX1001,1,6.1556,27.9206,90.1895,0.886 +53998,3,4,QFX1001,2,5.9652,27.9362,87.6528,0.8901 +53998,3,4,QFX1001,3,6.0649,27.9562,86.7421,0.8933 +53998,3,4,QFX1001,4,6.3379,27.9378,87.1656,0.891 +53998,3,4,QFX1001,5,6.1716,27.9296,86.5173,0.8895 +53998,3,4,QFX1001,6,6.1704,27.9268,87.502,0.887 +53998,3,4,QFX1001,7,5.9078,27.9371,89.0605,0.8895 +53998,3,4,QFX1001,8,5.2436,28.0064,87.9402,0.8928 +53998,3,4,QFX1001,9,6.2042,27.9482,87.5182,0.8921 +53998,3,4,QFX1001,10,6.4618,27.9749,87.1804,0.8938 +53998,3,4,QFX1001,11,6.7023,27.9674,86.7386,0.8937 +53998,3,4,QFX1001,12,6.6321,27.9567,87.7552,0.8914 +53998,3,4,QFX1001,13,6.6893,27.9472,86.8433,0.8929 +53998,3,4,QFX1001,14,5.3767,27.9946,88.3507,0.8917 +53998,3,4,QFX1001,15,6.423,27.9384,86.9731,0.8892 +53998,3,4,QFX1001,16,6.0631,27.951,86.2724,0.8923 +53998,3,4,QFX1001,17,6.0059,27.9494,86.8792,0.8914 +53998,3,5,QFX1001,1,6.1936,27.9324,90.315,0.8872 +53998,3,5,QFX1001,2,5.9996,27.9368,87.6721,0.8888 +53998,3,5,QFX1001,3,6.1517,27.9618,86.7941,0.8941 +53998,3,5,QFX1001,4,6.3122,27.9186,87.0949,0.888 +53998,3,5,QFX1001,5,6.171,27.9282,86.5885,0.8894 +53998,3,5,QFX1001,6,6.2083,27.9439,87.4519,0.8888 +53998,3,5,QFX1001,7,5.9427,27.9373,89.0112,0.8884 +53998,3,5,QFX1001,8,5.2796,28.0221,87.978,0.8944 +53998,3,5,QFX1001,9,6.1644,27.9559,87.5291,0.8924 +53998,3,5,QFX1001,10,6.5456,27.9808,87.1714,0.8949 +53998,3,5,QFX1001,11,6.7407,27.9598,86.7664,0.8938 +53998,3,5,QFX1001,12,6.7041,27.9574,87.7793,0.8922 +53998,3,5,QFX1001,13,6.7285,27.9397,86.793,0.8939 +53998,3,5,QFX1001,14,5.3918,28.0038,88.322,0.8915 +53998,3,5,QFX1001,15,6.3933,27.9411,87.0027,0.8892 +53998,3,5,QFX1001,16,6.087,27.9614,86.261,0.8933 +53998,3,5,QFX1001,17,6.0123,27.9504,86.9431,0.8922 +57172,3,1,QFX1002,1,6.2852,28.3813,89.14,0.9128 +57172,3,1,QFX1002,2,6.0709,28.4086,87.1078,0.9171 +57172,3,1,QFX1002,3,6.1884,28.4045,85.922,0.9144 +57172,3,1,QFX1002,4,6.4083,28.3959,86.335,0.914 +57172,3,1,QFX1002,5,6.2236,28.3892,85.9164,0.9174 +57172,3,1,QFX1002,6,6.2766,28.3977,86.661,0.9185 +57172,3,1,QFX1002,7,6.0445,28.391,88.0136,0.9108 +57172,3,1,QFX1002,8,5.3079,28.4837,87.3015,0.9188 +57172,3,1,QFX1002,9,6.2246,28.4156,86.8532,0.9194 +57172,3,1,QFX1002,10,6.5786,28.4319,86.3434,0.9159 +57172,3,1,QFX1002,11,6.8809,28.4124,85.6334,0.9129 +57172,3,1,QFX1002,12,6.7189,28.4253,86.9426,0.9156 +57172,3,1,QFX1002,13,6.7824,28.414,86.303,0.919 +57172,3,1,QFX1002,14,5.4998,28.4765,87.6832,0.9195 +57172,3,1,QFX1002,15,6.5448,28.4073,86.1777,0.9169 +57172,3,1,QFX1002,16,6.1174,28.4146,85.6236,0.9162 +57172,3,1,QFX1002,17,6.087,28.4204,86.2617,0.917 +57172,3,2,QFX1002,1,6.3281,28.3776,89.169,0.9122 +57172,3,2,QFX1002,2,6.1163,28.4069,87.1372,0.917 +57172,3,2,QFX1002,3,6.2115,28.408,85.947,0.9146 +57172,3,2,QFX1002,4,6.4676,28.3981,86.2692,0.9139 +57172,3,2,QFX1002,5,6.2953,28.3941,85.9886,0.9177 +57172,3,2,QFX1002,6,6.3403,28.3945,86.6967,0.9177 +57172,3,2,QFX1002,7,6.0893,28.39,88.0289,0.91 +57172,3,2,QFX1002,8,5.3466,28.4896,87.3104,0.9193 +57172,3,2,QFX1002,9,6.2692,28.4181,86.9184,0.9194 +57172,3,2,QFX1002,10,6.6445,28.4282,86.3217,0.9157 +57172,3,2,QFX1002,11,6.9187,28.4202,85.6898,0.9125 +57172,3,2,QFX1002,12,6.8136,28.4248,86.9505,0.9161 +57172,3,2,QFX1002,13,6.8284,28.4154,86.2447,0.9195 +57172,3,2,QFX1002,14,5.5346,28.4775,87.6939,0.9191 +57172,3,2,QFX1002,15,6.6091,28.4047,86.1832,0.9162 +57172,3,2,QFX1002,16,6.1622,28.4173,85.6517,0.9169 +57172,3,2,QFX1002,17,6.1309,28.4078,86.2488,0.9177 +57172,3,3,QFX1002,1,6.375,28.3828,89.2125,0.9128 +57172,3,3,QFX1002,2,6.1447,28.4098,87.1534,0.9174 +57172,3,3,QFX1002,3,6.2566,28.4081,86.0481,0.9149 +57172,3,3,QFX1002,4,6.4929,28.3985,86.3542,0.9141 +57172,3,3,QFX1002,5,6.354,28.3985,85.9886,0.9185 +57172,3,3,QFX1002,6,6.3885,28.4008,86.7271,0.918 +57172,3,3,QFX1002,7,6.1207,28.3905,88.0729,0.9117 +57172,3,3,QFX1002,8,5.377,28.4936,87.3578,0.9204 +57172,3,3,QFX1002,9,6.3282,28.4152,86.8983,0.9191 +57172,3,3,QFX1002,10,6.6616,28.4262,86.4234,0.9167 +57172,3,3,QFX1002,11,6.9687,28.4193,85.7293,0.9135 +57172,3,3,QFX1002,12,6.8502,28.4296,86.9874,0.9158 +57172,3,3,QFX1002,13,6.8651,28.41,86.2589,0.9185 +57172,3,3,QFX1002,14,5.5706,28.4794,87.7318,0.9198 +57172,3,3,QFX1002,15,6.6497,28.4079,86.139,0.917 +57172,3,3,QFX1002,16,6.1969,28.4236,85.6751,0.9171 +57172,3,3,QFX1002,17,6.1573,28.4167,86.3186,0.918 +57172,3,4,QFX1002,1,6.4329,28.3823,89.2043,0.9122 +57172,3,4,QFX1002,2,6.2011,28.4099,87.168,0.9173 +57172,3,4,QFX1002,3,6.3037,28.4051,86.0609,0.9159 +57172,3,4,QFX1002,4,6.556,28.4072,86.3939,0.9147 +57172,3,4,QFX1002,5,6.4006,28.3961,86.0121,0.9184 +57172,3,4,QFX1002,6,6.4182,28.395,86.7243,0.9181 +57172,3,4,QFX1002,7,6.1483,28.3966,88.0828,0.9119 +57172,3,4,QFX1002,8,5.4078,28.4888,87.3584,0.9208 +57172,3,4,QFX1002,9,6.3213,28.4175,86.8847,0.9205 +57172,3,4,QFX1002,10,6.7181,28.4297,86.4172,0.9162 +57172,3,4,QFX1002,11,7.0155,28.4228,85.7559,0.9149 +57172,3,4,QFX1002,12,6.8811,28.4296,86.9994,0.916 +57172,3,4,QFX1002,13,6.8966,28.4093,86.2526,0.9182 +57172,3,4,QFX1002,14,5.6048,28.4772,87.6818,0.9196 +57172,3,4,QFX1002,15,6.6777,28.4072,86.1796,0.9175 +57172,3,4,QFX1002,16,6.231,28.4197,85.6705,0.9171 +57172,3,4,QFX1002,17,6.202,28.4197,86.3125,0.9182 +57172,3,5,QFX1002,1,6.487,28.3822,89.2332,0.9139 +57172,3,5,QFX1002,2,6.2352,28.4066,87.1942,0.918 +57172,3,5,QFX1002,3,6.3535,28.4172,86.0816,0.9165 +57172,3,5,QFX1002,4,6.575,28.4079,86.4061,0.9149 +57172,3,5,QFX1002,5,6.4487,28.398,85.9882,0.9182 +57172,3,5,QFX1002,6,6.4623,28.4,86.7216,0.9183 +57172,3,5,QFX1002,7,6.2012,28.3978,88.134,0.9122 +57172,3,5,QFX1002,8,5.4406,28.5008,87.4464,0.9214 +57172,3,5,QFX1002,9,6.3835,28.4216,86.9577,0.9196 +57172,3,5,QFX1002,10,6.7267,28.4342,86.439,0.9168 +57172,3,5,QFX1002,11,7.0416,28.4243,85.782,0.9142 +57172,3,5,QFX1002,12,6.9134,28.4316,87.0385,0.9167 +57172,3,5,QFX1002,13,6.9408,28.4175,86.3092,0.9182 +57172,3,5,QFX1002,14,5.6225,28.4817,87.7127,0.9202 +57172,3,5,QFX1002,15,6.7195,28.4018,86.2258,0.917 +57172,3,5,QFX1002,16,6.2605,28.4242,85.7488,0.9178 +57172,3,5,QFX1002,17,6.2254,28.4212,86.3068,0.9186 +51362,3,1,QFX1003,1,6.1306,28.0204,90.3197,0.9231 +51362,3,1,QFX1003,2,5.9243,28.0321,87.9327,0.9252 +51362,3,1,QFX1003,3,6.0437,28.0392,86.9109,0.9274 +51362,3,1,QFX1003,4,6.3242,28.0161,86.8626,0.9241 +51362,3,1,QFX1003,5,6.1613,28.0256,86.5276,0.9263 +51362,3,1,QFX1003,6,6.1917,28.0174,87.416,0.9264 +51362,3,1,QFX1003,7,5.8974,28.0146,88.966,0.9227 +51362,3,1,QFX1003,8,5.2241,28.1049,88.1464,0.9311 +51362,3,1,QFX1003,9,6.1518,28.0392,87.6721,0.9266 +51362,3,1,QFX1003,10,6.5317,28.0567,87.166,0.9285 +51362,3,1,QFX1003,11,6.8399,28.0364,86.3877,0.9266 +51362,3,1,QFX1003,12,6.6944,28.0548,87.718,0.9272 +51362,3,1,QFX1003,13,6.7277,28.0311,86.8226,0.9271 +51362,3,1,QFX1003,14,5.3608,28.1064,88.5243,0.93 +51362,3,1,QFX1003,15,6.4489,28.0294,86.9928,0.927 +51362,3,1,QFX1003,16,5.9954,28.0525,86.7073,0.9283 +51362,3,1,QFX1003,17,5.9331,28.0472,87.1316,0.9266 +51362,3,2,QFX1003,1,6.1443,28.0259,90.341,0.922 +51362,3,2,QFX1003,2,5.9032,28.0289,87.9456,0.9251 +51362,3,2,QFX1003,3,6.0175,28.0435,86.9122,0.9272 +51362,3,2,QFX1003,4,6.3352,28.0111,86.8486,0.9236 +51362,3,2,QFX1003,5,6.1837,28.0221,86.5385,0.9271 +51362,3,2,QFX1003,6,6.1999,28.011,87.3673,0.9263 +51362,3,2,QFX1003,7,5.9244,28.0215,89.0182,0.9226 +51362,3,2,QFX1003,8,5.2397,28.1024,88.1043,0.9297 +51362,3,2,QFX1003,9,6.1811,28.0475,87.6957,0.9277 +51362,3,2,QFX1003,10,6.5184,28.0553,87.2303,0.9291 +51362,3,2,QFX1003,11,6.8285,28.0249,86.4233,0.9262 +51362,3,2,QFX1003,12,6.6902,28.0556,87.7259,0.9271 +51362,3,2,QFX1003,13,6.7341,28.0269,86.8272,0.928 +51362,3,2,QFX1003,14,5.3648,28.1067,88.5281,0.9298 +51362,3,2,QFX1003,15,6.4391,28.028,87.0332,0.9256 +51362,3,2,QFX1003,16,6.0279,28.0465,86.7336,0.9274 +51362,3,2,QFX1003,17,5.9566,28.0389,87.1333,0.9272 +51362,3,3,QFX1003,1,6.1744,28.0327,90.3375,0.9226 +51362,3,3,QFX1003,2,5.9412,28.0267,88.0121,0.926 +51362,3,3,QFX1003,3,6.0711,28.0434,86.9111,0.9266 +51362,3,3,QFX1003,4,6.354,28.0265,86.8646,0.9243 +51362,3,3,QFX1003,5,6.197,28.0199,86.6037,0.9259 +51362,3,3,QFX1003,6,6.2208,28.0123,87.3944,0.9248 +51362,3,3,QFX1003,7,5.9415,28.021,89.0377,0.9224 +51362,3,3,QFX1003,8,5.244,28.1099,88.1534,0.9312 +51362,3,3,QFX1003,9,6.1646,28.0454,87.6883,0.9273 +51362,3,3,QFX1003,10,6.519,28.053,87.2068,0.929 +51362,3,3,QFX1003,11,6.8529,28.0331,86.4113,0.9259 +51362,3,3,QFX1003,12,6.7169,28.0556,87.682,0.9273 +51362,3,3,QFX1003,13,6.7355,28.0286,86.7942,0.9273 +51362,3,3,QFX1003,14,5.4141,28.1115,88.5414,0.9301 +51362,3,3,QFX1003,15,6.4567,28.0259,87.0226,0.9268 +51362,3,3,QFX1003,16,6.0101,28.0489,86.7619,0.9282 +51362,3,3,QFX1003,17,5.9484,28.0352,87.1088,0.9275 +51362,3,4,QFX1003,1,6.1756,28.0189,90.4056,0.923 +51362,3,4,QFX1003,2,5.9591,28.0375,88.0084,0.9253 +51362,3,4,QFX1003,3,6.0894,28.0369,86.97,0.9266 +51362,3,4,QFX1003,4,6.3383,28.0214,86.9037,0.9245 +51362,3,4,QFX1003,5,6.2336,28.0191,86.527,0.9263 +51362,3,4,QFX1003,6,6.229,28.013,87.3764,0.9254 +51362,3,4,QFX1003,7,5.9501,28.0163,89.0627,0.923 +51362,3,4,QFX1003,8,5.2678,28.1024,88.1489,0.9301 +51362,3,4,QFX1003,9,6.1921,28.0433,87.6793,0.9281 +51362,3,4,QFX1003,10,6.5453,28.0559,87.2235,0.9286 +51362,3,4,QFX1003,11,6.8991,28.0397,86.4454,0.9281 +51362,3,4,QFX1003,12,6.7577,28.0496,87.6881,0.9272 +51362,3,4,QFX1003,13,6.7761,28.0312,86.7819,0.9277 +51362,3,4,QFX1003,14,5.4354,28.1093,88.537,0.9311 +51362,3,4,QFX1003,15,6.4656,28.0286,87.0867,0.9271 +51362,3,4,QFX1003,16,6.0527,28.0649,86.7618,0.9286 +51362,3,4,QFX1003,17,5.9802,28.03,87.1555,0.9266 +51362,3,5,QFX1003,1,6.216,28.0286,90.3768,0.9225 +51362,3,5,QFX1003,2,5.9629,28.0246,88.0389,0.9256 +51362,3,5,QFX1003,3,6.1209,28.0553,86.9655,0.9275 +51362,3,5,QFX1003,4,6.3851,28.0201,86.9382,0.9241 +51362,3,5,QFX1003,5,6.239,28.0215,86.54,0.9254 +51362,3,5,QFX1003,6,6.2516,28.0107,87.401,0.9254 +51362,3,5,QFX1003,7,5.9611,28.022,89.0102,0.9224 +51362,3,5,QFX1003,8,5.2665,28.1226,88.1926,0.931 +51362,3,5,QFX1003,9,6.2035,28.0435,87.7066,0.9276 +51362,3,5,QFX1003,10,6.5771,28.0695,87.2242,0.9293 +51362,3,5,QFX1003,11,6.8974,28.0405,86.4042,0.9267 +51362,3,5,QFX1003,12,6.7407,28.0584,87.6899,0.9283 +51362,3,5,QFX1003,13,6.781,28.0369,86.7997,0.928 +51362,3,5,QFX1003,14,5.444,28.103,88.5257,0.9296 +51362,3,5,QFX1003,15,6.4951,28.0246,87.0243,0.9257 +51362,3,5,QFX1003,16,6.0465,28.0601,86.7494,0.9292 +51362,3,5,QFX1003,17,5.9825,28.0394,87.1802,0.927 +59933,3,1,QFX1006,1,6.5118,28.1258,90.1079,0.9213 +59933,3,1,QFX1006,2,6.3084,28.1381,87.7426,0.9248 +59933,3,1,QFX1006,3,6.3966,28.1179,86.561,0.9226 +59933,3,1,QFX1006,4,6.6072,28.1448,87.1286,0.9259 +59933,3,1,QFX1006,5,6.5303,28.1467,86.6339,0.9263 +59933,3,1,QFX1006,6,6.6019,28.1019,86.842,0.918 +59933,3,1,QFX1006,7,6.1835,28.143,89.1663,0.9237 +59933,3,1,QFX1006,8,5.5167,28.2089,87.8463,0.9272 +59933,3,1,QFX1006,9,6.4759,28.1279,87.2773,0.9234 +59933,3,1,QFX1006,10,6.7705,28.1416,87.0215,0.9259 +59933,3,1,QFX1006,11,7.0393,28.145,86.6124,0.9267 +59933,3,1,QFX1006,12,6.9404,28.1722,87.7492,0.9275 +59933,3,1,QFX1006,13,7.0008,28.1694,86.9778,0.9294 +59933,3,1,QFX1006,14,5.6815,28.2427,88.4919,0.9305 +59933,3,1,QFX1006,15,6.8554,28.1282,86.5031,0.9217 +59933,3,1,QFX1006,16,6.3634,28.153,86.2951,0.9262 +59933,3,1,QFX1006,17,6.3428,28.1293,86.8017,0.9243 +59933,3,2,QFX1006,1,6.5093,28.1271,90.1336,0.9215 +59933,3,2,QFX1006,2,6.3365,28.1398,87.8078,0.925 +59933,3,2,QFX1006,3,6.4222,28.13,86.7097,0.9242 +59933,3,2,QFX1006,4,6.6375,28.139,87.1242,0.9242 +59933,3,2,QFX1006,5,6.558,28.1486,86.6385,0.9263 +59933,3,2,QFX1006,6,6.6577,28.1061,86.9045,0.9184 +59933,3,2,QFX1006,7,6.1949,28.149,89.2504,0.9241 +59933,3,2,QFX1006,8,5.4934,28.2166,87.8879,0.9295 +59933,3,2,QFX1006,9,6.5135,28.139,87.3468,0.9248 +59933,3,2,QFX1006,10,6.7842,28.1571,87.1622,0.9259 +59933,3,2,QFX1006,11,7.0609,28.1548,86.6967,0.9266 +59933,3,2,QFX1006,12,6.9509,28.1846,87.8033,0.9281 +59933,3,2,QFX1006,13,7.0376,28.1722,86.9021,0.9301 +59933,3,2,QFX1006,14,5.7016,28.2362,88.4806,0.93 +59933,3,2,QFX1006,15,6.8634,28.1154,86.4893,0.9207 +59933,3,2,QFX1006,16,6.3707,28.1524,86.3869,0.926 +59933,3,2,QFX1006,17,6.3607,28.1388,86.9301,0.9256 +59933,3,3,QFX1006,1,6.5419,28.1272,90.2437,0.9218 +59933,3,3,QFX1006,2,6.3475,28.1456,87.817,0.925 +59933,3,3,QFX1006,3,6.4368,28.1388,86.7566,0.9246 +59933,3,3,QFX1006,4,6.6685,28.1352,87.1234,0.924 +59933,3,3,QFX1006,5,6.5957,28.1514,86.6178,0.9266 +59933,3,3,QFX1006,6,6.6543,28.113,86.9286,0.9188 +59933,3,3,QFX1006,7,6.2133,28.139,89.2522,0.9237 +59933,3,3,QFX1006,8,5.5249,28.2014,87.8694,0.9274 +59933,3,3,QFX1006,9,6.5054,28.1333,87.3752,0.9247 +59933,3,3,QFX1006,10,6.8129,28.1506,87.159,0.9268 +59933,3,3,QFX1006,11,7.0898,28.1537,86.7068,0.9275 +59933,3,3,QFX1006,12,7.0209,28.1746,87.7585,0.927 +59933,3,3,QFX1006,13,7.0477,28.1633,86.903,0.9287 +59933,3,3,QFX1006,14,5.718,28.2365,88.4159,0.9296 +59933,3,3,QFX1006,15,6.8728,28.1155,86.5217,0.9201 +59933,3,3,QFX1006,16,6.3673,28.1444,86.3785,0.9255 +59933,3,3,QFX1006,17,6.3535,28.1333,86.9326,0.9242 +59933,3,4,QFX1006,1,6.5915,28.1431,90.244,0.9225 +59933,3,4,QFX1006,2,6.3765,28.1516,87.9259,0.9256 +59933,3,4,QFX1006,3,6.4767,28.1452,86.8024,0.9254 +59933,3,4,QFX1006,4,6.7079,28.1373,87.1779,0.9241 +59933,3,4,QFX1006,5,6.6175,28.1435,86.5769,0.9265 +59933,3,4,QFX1006,6,6.7041,28.1136,86.9516,0.9189 +59933,3,4,QFX1006,7,6.2433,28.1488,89.3373,0.9246 +59933,3,4,QFX1006,8,5.5563,28.2162,88.0048,0.93 +59933,3,4,QFX1006,9,6.5513,28.1373,87.352,0.9248 +59933,3,4,QFX1006,10,6.8275,28.1624,87.1891,0.927 +59933,3,4,QFX1006,11,7.1067,28.1557,86.7443,0.9277 +59933,3,4,QFX1006,12,7.0275,28.1842,87.8124,0.9288 +59933,3,4,QFX1006,13,7.0777,28.1626,86.8159,0.9271 +59933,3,4,QFX1006,14,5.7437,28.2312,88.4971,0.9302 +59933,3,4,QFX1006,15,6.9101,28.1219,86.5248,0.9204 +59933,3,4,QFX1006,16,6.4051,28.155,86.3809,0.927 +59933,3,4,QFX1006,17,6.407,28.1457,86.9448,0.9257 +59933,3,5,QFX1006,1,6.614,28.1308,90.2775,0.9229 +59933,3,5,QFX1006,2,6.3949,28.1468,87.9244,0.9252 +59933,3,5,QFX1006,3,6.4942,28.1449,86.8603,0.925 +59933,3,5,QFX1006,4,6.7219,28.1446,87.1839,0.9247 +59933,3,5,QFX1006,5,6.6411,28.1477,86.6367,0.9253 +59933,3,5,QFX1006,6,6.7131,28.1108,86.9418,0.9183 +59933,3,5,QFX1006,7,6.293,28.1522,89.3425,0.9241 +59933,3,5,QFX1006,8,5.5788,28.2124,88.0038,0.9289 +59933,3,5,QFX1006,9,6.5493,28.1508,87.4244,0.9254 +59933,3,5,QFX1006,10,6.8354,28.1622,87.2303,0.9275 +59933,3,5,QFX1006,11,7.1293,28.1591,86.7217,0.9277 +59933,3,5,QFX1006,12,7.0297,28.1813,87.7996,0.9272 +59933,3,5,QFX1006,13,7.1088,28.1652,86.8698,0.9274 +59933,3,5,QFX1006,14,5.7861,28.2282,88.4165,0.9304 +59933,3,5,QFX1006,15,6.9299,28.1126,86.5176,0.92 +59933,3,5,QFX1006,16,6.4173,28.1512,86.4596,0.9263 +59933,3,5,QFX1006,17,6.4158,28.1422,86.9479,0.9252 diff --git a/cgdt.lua b/cgdt.lua new file mode 100644 index 00000000..1c3e6293 --- /dev/null +++ b/cgdt.lua @@ -0,0 +1,88 @@ +ffi = require 'ffi' + +ffi.cdef [[ +struct char_buffer { + char *data; + size_t length; + size_t size; +}; + +typedef struct { + struct char_buffer names[1]; + int length; + int size; + int index[4]; +} gdt_index; + +extern gdt_index * gdt_index_new (int alloc_size); +extern void gdt_index_free (gdt_index *g); +extern gdt_index * gdt_index_resize (gdt_index *g); +extern int gdt_index_add (gdt_index *g, const char *str); +extern const char * gdt_index_get (gdt_index *g, int index); +extern int gdt_index_lookup (gdt_index *g, const char *req); + +enum { + TAG_STRING = 0xffff0000, + TAG_UNDEF = 0xfffe0000, + TAG_NUMBER = 0xfff80000, +}; + +typedef union { + double number; + struct { + unsigned int lo; + unsigned int hi; + } word; +} gdt_element; + +typedef struct { + int size; + gdt_element *data; + int ref_count; +} gdt_block; + +struct string_array { + struct char_buffer buffer[1]; + int *offset_data; + int offset_len; +}; + +struct __gdt_table; + +typedef struct { + int __index; + struct __gdt_table *__table; +} gdt_table_cursor; + +struct __gdt_table { + int size1; + int size2; + int tda; + gdt_element *data; + gdt_block *block; + gdt_index *strings; + struct string_array __headers[1]; + gdt_table_cursor __cursor[1]; +}; + +typedef struct __gdt_table gdt_table; + +extern gdt_table * gdt_table_new (int nb_rows, int nb_columns, int nb_rows_alloc); +extern void gdt_table_free (gdt_table *t); +extern const gdt_element * gdt_table_get (gdt_table *t, int i, int j); +extern const gdt_element * gdt_table_get_by_name (gdt_table *t, int i, const char* col_name); +extern const char * gdt_table_element_get_string (gdt_table *t, const gdt_element *e); +extern void gdt_table_set_number (gdt_table *t, int i, int j, double num); +extern void gdt_table_set_string (gdt_table *t, int i, int j, const char *s); +extern void gdt_table_set_undef (gdt_table *t, int i, int j); +extern const char * gdt_table_get_header (gdt_table *t, int j); +extern void gdt_table_set_header (gdt_table *t, int j, const char *str); +extern int gdt_table_header_index (gdt_table *t, const char* col_name); +extern int gdt_table_insert_columns (gdt_table *t, int j_in, int n); +extern int gdt_table_insert_rows (gdt_table *t, int i_in, int n); +extern const gdt_element * gdt_table_cursor_get (gdt_table_cursor *c, const char *key); +extern gdt_table_cursor * gdt_table_get_cursor (gdt_table *t); + +]] + +return ffi.C diff --git a/demo-init.lua b/demo-init.lua index a435c531..57ce6a22 100644 --- a/demo-init.lua +++ b/demo-init.lua @@ -16,7 +16,7 @@ local function load_demo(name) end local demo_files = { - 'fft', 'bspline', 'wave-particle', 'plot', 'fractals', 'ode', 'nlinfit', 'integ', 'anim', 'linfit', 'contour', 'svg', 'graphics', 'sf', 'vegas'} + 'fft', 'bspline', 'wave-particle', 'plot', 'fractals', 'ode', 'nlinfit', 'integ', 'anim', 'linfit', 'contour', 'svg', 'graphics', 'sf', 'vegas', 'gdt-lm'} for i, name in ipairs(demo_files) do load_demo(name) diff --git a/demos/gdt-lm.lua b/demos/gdt-lm.lua new file mode 100644 index 00000000..01416f54 --- /dev/null +++ b/demos/gdt-lm.lua @@ -0,0 +1,50 @@ + +local function lm_demo() + local r = rng.new() + + local a, b = 2.3, 1.2 + local sigma = 0.3 + + local tool_effect = {0.4, 0.7, -1.3} + local tools = {"tool A", "tool B", "tool C"} + + local N, P = 30, #tool_effect + local dx = 3.0 + + local t = gdt.alloc(N * P, {"tool", "x", "y"}) + + for k, tool in ipairs(tools) do + for i = 1, N do + local x = dx * (i - 1) / N + local y = a + b * x + rnd.gaussian(r, sigma) + tool_effect[k] + local ip = (k-1)*N + i + t:set(ip, 1, tool) + t:set(ip, 2, x) + t:set(ip, 3, y) + end + end + + local p = gdt.plot(t, "y ~ x | tool", {show= false}) + + p.title = "Linear Fit example" + p.xtitle = "time, s" + p.ytitle = "thickness, mm" + + local fit = gdt.lm(t, "y ~ x, tool", {predict= true}) + fit:summary() + + for k = 1, P do + local ln = graph.fxline(|x| fit:eval {tool= tools[k], x= x}, 0, dx) + p:addline(ln, graph.webcolor(k), {{'dash', 7, 3}}) + end + + p:show() +end + +return {'Linear Regression', { + { + name= 'linreg1', + f = lm_demo, + description = 'Mixed model regression example' + }, +}} diff --git a/expr-parser.lua b/expr-parser.lua new file mode 100644 index 00000000..936e48a1 --- /dev/null +++ b/expr-parser.lua @@ -0,0 +1,229 @@ + +local len, match = string.len, string.match + +local mini_lexer = {} + +local mini_lexer_mt = { + __index = mini_lexer, +} + +local literal_chars = {['('] = 1, [')'] = 1, ['~'] = 1, [','] = 1, ['|'] = 1} +local oper_table = {['+'] = 0, ['-'] = 0, ['*'] = 1, ['/'] = 1, ['^'] = 2, ['%'] = -1} + +local function new_lexer(src) + local lexer = {n = 1, src= src} + setmetatable(lexer, mini_lexer_mt) + lexer:next() + return lexer +end + +function mini_lexer.char(lexer) + local n = lexer.n + return lexer.src:sub(n, n) +end + +function mini_lexer.incr(lexer, n) + lexer.n_current = lexer.n + lexer.n = lexer.n + (n or 1) +end + +function mini_lexer.match(lexer, pattern) + return match(lexer.src, '^' .. pattern, lexer.n) +end + +function mini_lexer.consume(lexer, pattern) + local m = match(lexer.src, '^' .. pattern, lexer.n) + if m then + lexer.n_current = lexer.n + lexer.n = lexer.n + len(m) + return m + end +end + +function mini_lexer.skip(lexer, pattern) + local m = match(lexer.src, '^' .. pattern, lexer.n) + if m then lexer.n = lexer.n + len(m) end +end + +function mini_lexer.next_token(lexer) + lexer:skip('%s*') + if lexer.n > len(lexer.src) then return {type= 'EOF'} end + local c = lexer:char() + if c == '[' then + local str = lexer:consume('%b[]') + return {type= 'ident', value= str:sub(2,-2)} + end + if oper_table[c] then + local prio = oper_table[c] + lexer:incr() + return {type= 'operator', symbol= c, priority = prio} + end + if literal_chars[c] then + lexer:incr() + return {type= c} + end + if lexer:match('[%l%u_]') then + local str = lexer:consume('[%l%u_][%l%u%d_.$]*') + return {type= 'ident', value= str} + end + if lexer:match('%d') then + local str = lexer:consume('%d+%.%d*[Ee]%+?%d+') + str = str or lexer:consume('%d+%.%d*[Ee]%-?%d+') + str = str or lexer:consume('%d+%.%d*') + str = str or lexer:consume('%d+') + return {type= 'number', value= tonumber(str)} + end + lexer:local_error("syntax error in expression:", lexer.n) +end + +function mini_lexer.next(lexer) + lexer.token = lexer:next_token() +end + +function mini_lexer.local_error(lexer, msg, n_pos) + n_pos = n_pos or lexer.n_current + local line = string.format(' %s', lexer.src) + local pos = string.format(' %s^', string.rep(' ', n_pos - 1)) + error(string.format("%s\n%s\n%s", msg, line, pos)) +end + +local function accept(lexer, token_type) + if lexer.token.type == token_type then + lexer:next() + return true + end + return false +end + +local function expect(lexer, token_type) + if not accept(lexer, token_type) then + lexer:local_error("expecting " .. token_type) + end +end + +local expr + +local function factor(lexer, actions) + local token = lexer.token + if token.type == 'ident' then + local id = token.value + lexer:next() + if accept(lexer, '(') then + local arg = expr(lexer, actions, 0) + expect(lexer, ')') + return actions.func_eval(id, arg) + else + return actions.ident(id) + end + elseif token.type == 'number' then + local x = token.value + lexer:next() + return actions.number(x) + elseif token.type == '(' then + lexer:next() + local a = expr(lexer, actions, 0) + expect(lexer, ')') + return a + elseif token.type == 'operator' and token.symbol == '%' then + lexer:next() + if lexer.token.type ~= 'ident' then + lexer:local_error("expecting identifier:") + end + local id = lexer.token.value + lexer:next() + return actions.enum(id) + end + lexer:local_error('unexpected symbol:') +end + +local function ident_singleton(lexer, actions) + local token = lexer.token + if token.type == 'ident' then + local id = token.value + lexer:next() + if accept(lexer, '(') then + lexer:local_error('expecting simple identifier') + end + return actions.ident(id) + else + lexer:local_error('expecting simple identifier') + end +end + +expr = function(lexer, actions, prio) + if prio > 2 then + return factor(lexer, actions) + end + + local a + local token = lexer.token + if prio == 0 and token.type == 'operator' and token.symbol == '-' then + local symbol = token.symbol + lexer:next() + local b = expr(lexer, actions, prio + 1) + a = actions.prefix(symbol, b) + else + a = expr(lexer, actions, prio + 1) + end + + token = lexer.token + while token.type == 'operator' and token.priority >= prio do + local symbol = token.symbol + accept(lexer, 'operator') + local b = expr(lexer, actions, prio + 1) + a, token = actions.infix(symbol, a, b), lexer.token + end + return a +end + +local function expr_list(lexer, actions) + local a = expr(lexer, actions, 0) + local els = actions.exprlist(a) + while accept(lexer, ',') do + local b = expr(lexer, actions, 0) + els = actions.exprlist(b, els) + end + return els +end + +local function ident_list(lexer, actions) + local a = ident_singleton(lexer, actions) + local els = actions.exprlist(a) + while accept(lexer, ',') do + local b = ident_singleton(lexer, actions) + els = actions.exprlist(b, els) + end + return els +end + +local function schema(lexer, actions) + local y = expr(lexer, actions, 0) + expect(lexer, '~') + local x = expr_list(lexer, actions) + if lexer.token.type ~= 'EOF' then + lexer:local_error('unexpected symbol:') + end + return actions.schema(x, y) +end + +local function gschema(lexer, actions) + local y = expr_list(lexer, actions) + expect(lexer, '~') + local x = expr_list(lexer, actions) + local enums + if accept(lexer, '|') then + enums = ident_list(lexer, actions) + else + enums = {} + end + if lexer.token.type ~= 'EOF' then + lexer:local_error('unexpected symbol:') + end + return actions.schema(x, y, enums) +end + +local function parse_expr(lexer, actions) + return expr(lexer, actions, 0) +end + +return {lexer = new_lexer, schema= schema, gschema= gschema, parse = parse_expr} diff --git a/expr-print.lua b/expr-print.lua new file mode 100644 index 00000000..17f0f6f6 --- /dev/null +++ b/expr-print.lua @@ -0,0 +1,90 @@ +local format, concat = string.format, table.concat + +local oper_table = {['+'] = 0, ['-'] = 0, ['*'] = 1, ['/'] = 1, ['^'] = 2, ['%'] = -1} + +local ex_print + +local function is_ident_simple(s) + return s:match('^[%l%u_][%w_]*$') +end + +local function op_print(e, prio) + if #e == 1 then + local c, c_prio = ex_print(e[1]) + if c_prio < prio then c = format('(%s)', c) end + return format("%s%s", e.operator, c) + else + local a, a_prio = ex_print(e[1]) + local b, b_prio = ex_print(e[2]) + if a_prio < prio then a = format('(%s)', a) end + if b_prio < prio then b = format('(%s)', b) end + local temp = (prio < 2 and "%s %s %s" or "%s%s%s") + return format(temp, a, e.operator, b) + end +end + +local function exlist_print(e) + local t = {} + for k = 1, #e do t[k] = ex_print(e[k]) end + return concat(t, ', ') +end + +ex_print = function(e) + if type(e) == 'number' then + return e, 3 + elseif e.name then + local s = e.name + if not is_ident_simple(s) then s = format('[%s]', s) end + return s, 3 + elseif e.func then + local arg_str = ex_print(e.arg) + return format('%s(%s)', e.func, arg_str), 3 + else + local prio = oper_table[e.operator] + local s = op_print(e, prio) + return s, prio + end +end + +local function schema_print(e) + local ys = exlist_print(e.y) + local xs = exlist_print(e.x) + return format("%s ~ %s", ys, xs) +end + +local function eval_operator(op, a, b) + if op == '+' then return a + b + elseif op == '-' then return a - b + elseif op == '*' then return a * b + elseif op == '/' then return a / b + elseif op == '^' then return a ^ b + else error('unkown operation: ' .. op) end +end + +local function eval(expr, scope) + if type(expr) == 'number' then + return expr + elseif expr.name then + return scope.ident(expr) + elseif expr.func then + local arg_value = eval(expr.arg, scope) + if arg_value then + local f = scope.func(expr) + if not f then error('unknown function: '..expr.func) end + return f(arg_value) + end + else + if #expr == 1 then + local v = eval(expr[1], scope) + if v then return -v end + else + local a = eval(expr[1], scope) + local b = eval(expr[2], scope) + if a and b then + return eval_operator(expr.operator, a, b) + end + end + end +end + +return {schema = schema_print, expr = ex_print, expr_list = exlist_print, eval = eval} diff --git a/fox-gui/Makefile b/fox-gui/Makefile index c4738519..af622c2c 100644 --- a/fox-gui/Makefile +++ b/fox-gui/Makefile @@ -29,7 +29,7 @@ GSL_SHELL_GUI = gsl-shell-gui$(EXE_EXT) LUADIR = $(GSH_BASE_DIR)/luajit2 -GSL_SHELL_LIBS = $(LUADIR)/src/libluajit.a $(GSH_BASE_DIR)/agg-plot/libaggplot.a $(GSH_BASE_DIR)/lua-gsl/libluagsl.a +GSL_SHELL_LIBS = $(LUADIR)/src/libluajit.a $(GSH_BASE_DIR)/agg-plot/libaggplot.a $(GSH_BASE_DIR)/lua-gsl/libluagsl.a $(GSH_BASE_DIR)/gdt/libgdt.a INCLUDES += -I$(GSH_BASE_DIR) -I$(GSH_BASE_DIR)/lua-gsl -I$(GSH_BASE_DIR)/agg-plot -I$(LUADIR)/src -I$(GSH_BASE_DIR)/cpp-utils @@ -55,7 +55,7 @@ all: $(TARGETS) $(GSL_SHELL_GUI): $(FOXGUI_OBJ_FILES) $(GSL_SHELL_LIBS) @echo Linking $@ - @$(LINK_EXE) -o $@ $(FOXGUI_OBJ_FILES) $(LIBS) $(LDFLAGS) + @$(LINK_EXE) -o $@ $(FOXGUI_OBJ_FILES) $(LIBS) include $(GSH_BASE_DIR)/makerules diff --git a/fox-gui/lua_plot_window.cpp b/fox-gui/lua_plot_window.cpp index 15a3107e..f327aef7 100644 --- a/fox-gui/lua_plot_window.cpp +++ b/fox-gui/lua_plot_window.cpp @@ -40,7 +40,7 @@ static const struct luaL_Reg fox_window_methods[] = __END_DECLS -typedef plot<manage_owner> sg_plot; +typedef plot sg_plot; class window_mutex { public: diff --git a/gdt-eval.lua b/gdt-eval.lua new file mode 100644 index 00000000..f42bdafb --- /dev/null +++ b/gdt-eval.lua @@ -0,0 +1,79 @@ + +local ipairs = ipairs + +local function mult(a, b) + if a == 1 then return b end + if b == 1 then return a end + return {operator= '*', a, b} +end + +local function scalar_infix(sym, a, b) + if sym == '*' then + return mult(a, b) + else + return {operator= sym, a, b} + end +end + +local function factor_infix(sym, a, b) + if not (a or b) then return nil end + if sym ~= '*' then + error('non multiplicative opeation on factors') + end + local c = {} + if a then for i, f in ipairs(a) do c[#c+1] = f end end + if b then for i, f in ipairs(b) do c[#c+1] = f end end + return c +end + +local function infix_action(sym, a, b) + local c = {} + c.scalar = scalar_infix(sym, a.scalar, b.scalar) + c.factor = factor_infix(sym, a.factor, b.factor) + return c +end + +local function prefix_action(sym, a) + if a.factor then error('non multiplicative opeation on factors') end + return {scalar= {operator= sym, a}} +end + +local function enum_action(id) + return {scalar= 1, factor= {id}} +end + +local function func_eval_action(func_name, arg_expr) + if arg_expr.factor then + error('applying function ' .. func_name .. ' to an enumerated factor') + end + return {scalar= {func = func_name, arg = arg_expr.scalar}} +end + +local function gdt_eval_actions(t) + local n, m = t:dim() + + local column_class = {} + for j = 1, m do column_class[j] = t:col_type(j) end + + local function ident_action(id) + local index = t:col_index(id) + if column_class[index] == 'factor' then + return {scalar= 1, factor= {id}} + else + return {scalar= {name= id, index= t:col_index(id)}} + end + end + + return { + infix = infix_action, + ident = ident_action, + prefix = prefix_action, + enum = enum_action, + func_eval = func_eval_action, + number = function(x) return {scalar= x} end, + exprlist = function(a, ls) if ls then ls[#ls+1] = a else ls = {a} end; return ls end, + schema = function(x, y) return {x= x, y= y} end, + } +end + +return gdt_eval_actions diff --git a/gdt-hist.lua b/gdt-hist.lua new file mode 100644 index 00000000..d5e9c53a --- /dev/null +++ b/gdt-hist.lua @@ -0,0 +1,80 @@ + +local ffi = require 'ffi' +local gsl = require 'gsl' + +local rect = graph.rect + +local function compare_float(a, b) + return a < b +end + +local function gdt_table_hist(t, col_name, opt) + local j + if type(col_name) == 'string' then + j = t:col_index(col_name) + if not j then error(string.format("invalid column name: %s", col_name)) end + else + if type(col_name) ~= 'number' then error("invalid column index") end + j = col_name + end + + local n = #t + + local dv = matrix.alloc(n, 1) + for i = 1, n do dv.data[i - 1] = t:get(i, j) end + + dv:sort(compare_float) + + local Q1 = gsl.gsl_stats_quantile_from_sorted_data(dv.data, dv.tda, n, 0.25) + local Q3 = gsl.gsl_stats_quantile_from_sorted_data(dv.data, dv.tda, n, 0.75) + local IQR = Q3 - Q1 + + local a, b + if opt and opt.a and opt.b then + a, b = opt.a, opt.b + else + a, b = dv.data[0], dv.data[n - 1] + end + + -- Freedman-Diaconis rule from http://stats.stackexchange.com/questions/798/calculating-optimal-number-of-bins-in-a-histogram-for-n-where-n-ranges-from-30 + -- corresponds to GNU R with breaks='FD' + local h_FD = 2 * IQR * n^(-1/3) + local nbins = (b - a) / h_FD + + if nbins < 2 then error("not enough data to produce an histogram") end + + local h = ffi.gc(gsl.gsl_histogram_alloc(nbins), gsl.gsl_histogram_free) + assert(h, "error creating histogram") + + local eps = (b - a) * 1e-5 + gsl.gsl_histogram_set_ranges_uniform(h, a - eps, b + eps) + + for i, x in t:column(j) do + if x then + gsl.gsl_histogram_increment(h, x) + end + end + + local name = t:header(j) + local title = (opt and opt.title) and opt.title or (name .. ' histogram') + local color = (opt and opt.color) and opt.color or 'green' + local p = graph.plot(title) + p.xtitle = name + p.ytitle = 'count' + p.pad = true + + local lim = ffi.new('double[2]') + for k = 0, nbins - 1 do + gsl.gsl_histogram_get_range(h, k, lim, lim + 1) + local y = gsl.gsl_histogram_get(h, k) + local r = rect(lim[0], 0, lim[1], y) + p:add(r, color) + p:addline(r, 'darkgray') + end + + p:show() + + return p +end + +gdt.hist = gdt_table_hist diff --git a/gdt-lm.lua b/gdt-lm.lua new file mode 100644 index 00000000..26d76909 --- /dev/null +++ b/gdt-lm.lua @@ -0,0 +1,440 @@ + +local mini = require 'expr-parser' +local expr_print = require 'expr-print' + +local sqrt, abs = math.sqrt, math.abs +local type, pairs, ipairs = type, pairs, ipairs + +local function add_unique(t, val) + for k, x in ipairs(t) do + if x == val then return k end + end + local n = #t + 1 + t[n] = val + return n +end + +local function level_number(factors, levels) + if not factors then return 0 end + local nb = 1 + for _, factor_name in ipairs(factors) do + nb = nb * #levels[factor_name] + end + return nb +end + +local function enum_levels(factors, levels) + local ls, ks, ms = {}, {}, {} + local n = #factors + for i, name in ipairs(factors) do + ks[i], ms[i] = 0, #levels[name] + end + + local first = true + while true do + local lev = {} + for i, name in ipairs(factors) do + lev[i] = levels[name][ks[i] + 1] + end + if not (factors.omit_ref_level and first) then ls[#ls + 1] = lev end + first = false + + for i = n, 0, -1 do + if i == 0 then return ls end + ks[i] = (ks[i] + 1) % ms[i] + if ks[i] > 0 then break end + end + end +end + +local function factors_defined(t, i, factors) + for k, factor_name in ipairs(factors) do + local y = t:get(i, t:col_index(factor_name)) + if not y then return false end + end + return true +end + +local function level_does_match(t, i, factors, req_levels) + for k, factor_name in ipairs(factors) do + local y = t:get(i, t:col_index(factor_name)) + if y ~= req_levels[k] then return 0 end + end + return 1 +end + +local function expr_are_equal(a, b) + if a == b then + return true + elseif type(a) == 'table' and type(b) == 'table' then + if a.operator == b.operator then + return expr_are_equal(a[1], b[1]) and expr_are_equal(a[2], b[2]) + end + end + return false +end + +local function scalar_term_exists(expr_list, s) + for i, expr in ipairs(expr_list) do + if not expr.factor and expr_are_equal(expr.scalar, s) then + return true + end + end + return false +end + +local function print_expr_level(factors, levels) + local t = {} + for i, f in ipairs(factors) do + t[i] = string.format("%s%s", f, levels[i]) + end + return table.concat(t, ':') +end + +local function expr_is_unit(e) + return type(e) == 'number' and e == 1 +end + +local function eval_scalar_gen(t) + local i + local id_res = function(expr) return t:get(i, expr.index) end + local func_res = function(expr) return math[expr.func] end + local set = function(ix) i = ix end + return set, {ident= id_res, func= func_res} +end + +local function eval_lm_matrix(t, expr_list, y_expr) + local eval_set, eval_scope = eval_scalar_gen(t) + local eval_scalar = expr_print.eval + + local N = #t + local NE = #expr_list + local XM = 0 + for k, e in ipairs(expr_list) do XM = XM + e.mult end + + local X = matrix.alloc(N, XM) + local Y = y_expr and matrix.alloc(N, 1) + local index_map, index_map_start, index_map_len = {}, 1, 0 + local row_index = 1 + for i = 1, N do + eval_set(i) + local row_undef = false + local col_index = 1 + for k = 1, NE do + local expr = expr_list[k] + local xs = eval_scalar(expr.scalar, eval_scope) + local is_undef = (not xs) or (expr.factor and not factors_defined(t, i, expr.factor)) + row_undef = row_undef or is_undef + if not is_undef then + if not expr.factor then + X:set(row_index, col_index, xs) + else + local j0 = col_index + for j, req_lev in ipairs(expr.levels) do + local match = level_does_match(t, i, expr.factor, req_lev) + X:set(row_index, j0 + (j - 1), match * xs) + end + end + end + col_index = col_index + expr.mult + end + + if y_expr and not row_undef then + local y_val = eval_scalar(y_expr, eval_scope) + row_undef = (not y_val) + if y_val then Y:set(row_index, 1, y_val) end + end + + if row_undef then + local kk = #index_map + index_map[kk+1] = index_map_start + index_map[kk+2] = index_map_len + index_map_start = i + 1 + index_map_len = 0 + else + row_index = row_index + 1 + index_map_len = index_map_len + 1 + end + end + + if index_map_len > 0 then + local kk = #index_map + index_map[kk+1] = index_map_start + index_map[kk+2] = index_map_len + end + + local nb_rows = row_index - 1 + assert(nb_rows > 0, "undefined model") + + -- resize X to take into account the rows really defined + X.size1 = nb_rows + if y_expr then + Y.size1 = nb_rows + return X, Y, index_map + end + + return X +end + +local check = require 'check' +local mon = require 'monomial' + +local function monomial_to_expr(m, context) + local coeff = m[1] + local prod + for k, sym, pow in mon.terms(m) do + local base = context[sym] + local t = (pow == 1 and base or {operator='^', base, pow}) + prod = (prod and {operator='*', t, prod} or t) + end + return coeff == 1 and (prod or 1) or (prod and {operator='*', coeff, prod} or coeff) +end + +local function expr_to_monomial(expr, context) + if type(expr) == 'number' then + return {expr} + elseif expr.operator == '*' then + local a = expr_to_monomial(expr[1], context) + local b = expr_to_monomial(expr[2], context) + mon.mult(a, b) + return a + elseif expr.operator == '^' and check.is_integer(expr[2]) then + local base = expr_to_monomial(expr[1], context) + mon.power(base, expr[2]) + return base + else + local s = expr_print.expr(expr) + context[s] = expr + return mon.symbol(s) + end +end + +local function build_lm_model(t, expr_list, y_expr) + local N, M = t:dim() + + -- list of unique factors referenced in expr_list + local used_factors = {} + for k, expr in ipairs(expr_list) do + if expr.factor then + for _, f_name in ipairs(expr.factor) do + add_unique(used_factors, f_name) + end + end + end + + -- flag the factors whose scalar part is already used + -- in the model. In these cases the first level of the + -- factor will be omitted from the model matrix. + for k, expr in ipairs(expr_list) do + if expr.factor then + local s = expr.scalar + if scalar_term_exists(expr_list, s) then + expr.factor.omit_ref_level = true + end + end + end + + -- for each unique used factor prepare the levels list and + -- set the column index + local levels, factor_index = {}, {} + for k, name in ipairs(used_factors) do + levels[name] = {} + factor_index[name] = t:col_index(name) + end + + -- find the levels for each of the used factors + local get = t.get + for i = 1, N do + for _, name in ipairs(used_factors) do + local v = get(t, i, factor_index[name]) + add_unique(levels[name], v) + end + end + + for k, expr in ipairs(expr_list) do + if expr.factor then + local lnb = level_number(expr.factor, levels) + local inn = expr.factor.omit_ref_level and lnb - 1 or lnb + expr.mult = inn + else + expr.mult = 1 + end + end + + -- first pass to find coefficient names and levels by expression + local names = {} + local col_index = 1 + for k, expr in ipairs(expr_list) do + local j0 = col_index + local scalar_repr = expr_print.expr(expr.scalar) + if not expr.factor then + names[j0] = scalar_repr + else + local flevels = enum_levels(expr.factor, levels) + for j, req_lev in ipairs(flevels) do + local level_repr = print_expr_level(expr.factor, req_lev) + local nm + if expr_is_unit(expr.scalar) then + nm = level_repr + else + nm = scalar_repr .. ' * ' .. level_repr + end + names[j0 + (j - 1)] = nm + end + expr.levels = flevels + end + col_index = col_index + expr.mult + end + + return names +end + +local function t_test(xm, s, n, df) + local t = xm / s + local at = abs(t) + local p_value = 2 * (1 - randist.tdist_P(at, df)) + return t, (p_value >= 2e-16 and p_value or '< 2e-16') +end + +local function compute_fit(X, y, names) + local n = #y + local c, chisq, cov = num.linfit(X, y) + local coeff = gdt.alloc(#c, {"term", "estimate", "std error", "t value" ,"Pr(>|t|)"}) + for i = 1, #c do + coeff:set(i, 1, names[i]) + local xm, s = c[i], cov:get(i,i) + coeff:set(i, 2, xm) + coeff:set(i, 3, sqrt(s)) + local t, p_value = t_test(xm, sqrt(s), n, n - #c) + coeff:set(i, 4, t) + coeff:set(i, 5, p_value) + end + return {coeff = coeff, c = c, chisq = chisq, cov = cov, n = n, p = #c} +end + +local function fit_compute_Rsquare(fit, X, y) + local n, p = fit.n, fit.p + local y_pred = X * fit.c + + local y_mean = 0 + for k = 1, #y do y_mean = y_mean + y:get(k, 1) end + y_mean = y_mean / #y + + local SS_tot, SS_reg = 0, 0 + for k = 1, #y do + SS_reg = SS_reg + (y:get(k, 1) - y_pred:get(k, 1))^2 + SS_tot = SS_tot + (y:get(k, 1) - y_mean)^2 + end + + local R2 = 1 - SS_reg/SS_tot + local R2_adj = R2 - (1 - R2) * p / (n - p - 1) + local SE = sqrt(SS_reg / (n - p)) + + return SE, R2, R2_adj +end + +local function fit_add_predicted(t, param_name, X, fit, index_map) + local cname = string.format("%s (PREDICTED)", param_name) + if not t:col_index(cname) then t:append(cname) end + local cindex = t:col_index(cname) + + local y_pred = X * fit.c + local jy = 1 + for k = 1, #index_map - 1, 2 do + local idx, len = index_map[k], index_map[k+1] + for j = 0, len - 1 do + t:set(idx + j, cindex, y_pred[jy + j]) + end + jy = jy + len + end +end + +local function monomial_exists(ls, e) + local n = #ls + for k = 1, n do + if mon.equal(ls[k], e) then return true end + end + return false +end + +local function expand_exprs(expr_list) + local lsm, lsexp, j = {}, {}, 1 + for k, e in ipairs(expr_list) do + local context = {} + local m = expr_to_monomial(e.scalar, context) + local ls = mon.combine(m) + for _, mexp in ipairs(ls) do + if not monomial_exists(lsm, mexp) then + lsm[j], j = mexp, j+1 + local eexp = monomial_to_expr(mexp, context) + lsexp[#lsexp+1] = {scalar= eexp} + end + end + if e.factor then lsexp[#lsexp+1] = e end + end + + return lsexp +end + +local FIT = {} + +function FIT.model(fit, t_alt) + return eval_lm_matrix(t_alt, fit.x_exprs) +end + +function FIT.predict(fit, t_alt) + local X = eval_lm_matrix(t_alt, fit.x_exprs) + return X * fit.c +end + +function FIT.summary(fit) + print(fit.coeff) + print() + print(string.format("Standard Error: %g, R2: %g, Adjusted R2: %g", fit.SE, fit.R2, fit.R2_adj)) +end + +local FIT_MT = {__index = FIT} + +-- used to eval a model for a single entry +function FIT.eval(fit, tn) + local eval_table = fit.eval_table + for k, name in ipairs(fit.headers) do + eval_table:set(1, k, tn[name]) + end + local coeff = fit.c + local sX = eval_lm_matrix(eval_table, fit.x_exprs) + local sy = 0 + for k = 0, #coeff - 1 do + sy = sy + sX.data[k] * coeff.data[k] + end + return sy +end + +local function lm(t, model_formula, options) + local gdt_eval_actions = require('gdt-eval') + local actions = gdt_eval_actions(t) + local l = mini.lexer(model_formula) + local schema = mini.schema(l, actions) + + local expand = not options or (options.expand == nil or options.expand) + local x_exprs = expand and expand_exprs(schema.x) or schema.x + + local names = build_lm_model(t, x_exprs, schema.y.scalar) + local X, y, index_map = eval_lm_matrix(t, x_exprs, schema.y.scalar) + local fit = compute_fit(X, y, names) + + if options and options.predict then + local y_name = expr_print.expr(schema.y.scalar) + fit_add_predicted(t, y_name, X, fit, index_map) + end + + fit.schema = schema + fit.x_exprs = x_exprs + fit.SE, fit.R2, fit.R2_adj = fit_compute_Rsquare(fit, X, y) + fit.eval_table = gdt.alloc(1, t:headers()) + fit.headers = t:headers() + + return setmetatable(fit, FIT_MT) +end + +gdt.lm = lm diff --git a/gdt-parse-csv.lua b/gdt-parse-csv.lua new file mode 100644 index 00000000..9781fde5 --- /dev/null +++ b/gdt-parse-csv.lua @@ -0,0 +1,120 @@ +local ffi = require 'ffi' +local gdt = require 'gdt' +local csv = require 'csv' + +local max = math.max +local match, gsub = string.match, string.gsub + +local function is_string_only(ls) + for _, s in ipairs(ls) do + if tonumber(s) then return false end + end + return true +end + +local function pre_parse_csv(source) + local head_vs = source() + local nrows, ncols = 1, #head_vs + local all_strings = true + local header_dup = {} + for vs in source do + if #vs == 0 then break end + if all_strings then all_strings = is_string_only(vs) end + for k= 1, #vs do + if head_vs[k] == vs[k] then header_dup[k] = true end + end + ncols = max(ncols, #vs) + nrows = nrows + 1 + end + + local header_dup_count = 0 + for k= 1, ncols do + if header_dup[k] then header_dup_count = header_dup_count + 1 end + end + local header_stand = (header_dup_count < ncols/2) + + local head_all_string = is_string_only(head_vs) + local has_header = head_all_string and (header_stand or (not all_strings)) + + if has_header then nrows = nrows - 1 end + + return nrows, ncols, has_header +end + +local function is_not_empty(s) + return (match(s, '^%s*$') == nil) +end + +local function gdt_parse(source_init) + local source = source_init() + local nrows, ncols, has_header = pre_parse_csv(source) + + local t = gdt.alloc(nrows, ncols) + source = source_init() + + if has_header then + local vs = source() + for k, s in ipairs(vs) do + t:set_header(k, s) + end + end + + local i = 1 + for vs in source do + if #vs == 0 then break end + for j = 1, ncols do + local v = (is_not_empty(vs[j]) and vs[j] or nil) + gdt.set(t, i, j, v) + end + i = i + 1 + end + + return t +end + +local function trim_spaces(line) + for j = 1, #line do + if type(line[j]) == 'string' then + local a = gsub(line[j], "^%s+", "") + line[j] = gsub(a, "%s+$", "") + end + end +end + +local function source_csv(filename, options) + local strip_spaces = true + if options and (options.strip_spaces ~= nil) then + strip_spaces = options.strip_spaces + end + local f + local it, s, i + local source = function() + local line = it(s, i) + if line then + local ls = csv.line(line) + if strip_spaces then trim_spaces(ls) end + return ls + else + f:close() + end + end + return function() + f = assert(io.open(filename, 'r'), 'cannot open file: ' .. filename) + it, s, i = f:lines() + return source + end +end + +local function source_def(def) + local n, i = #def, 0 + local source = function() + if i + 1 <= n then + i = i + 1 + return def[i] + end + end + return function() i = 0; return source end +end + +gdt.read_csv = function(filename, options) return gdt_parse(source_csv(filename, options)) end +gdt.def = function(def) return gdt_parse(source_def(def)) end diff --git a/gdt-plot.lua b/gdt-plot.lua new file mode 100644 index 00000000..09761f0d --- /dev/null +++ b/gdt-plot.lua @@ -0,0 +1,585 @@ +local mini = require 'expr-parser' +local expr_print = require 'expr-print' + +local concat = table.concat +local select, unpack = select, unpack +local sqrt = math.sqrt + +local line_width = 2.5 + +local function collate(ls, sep) + return concat(ls, sep or ' ') +end + +-- recursive algorithm to computer the standard deviation from +-- wikipedia: http://en.wikipedia.org/wiki/Standard_deviation. +-- Welford, BP. "Note on a Method for Calculating Corrected Sums of +-- Squares and Products". Technometrics 4 (3): 419–420 +local function f_stddev(accu, x, n) + local A, Q, km = unpack(accu) + accu[1] = A + (x - A) / (km + 1) + accu[2] = Q + km / (km + 1) * (x - A)^2 + accu[3] = km + 1 + return accu +end + +local function f_stddevp_fini(accu) + local A, Q, n = unpack(accu) + if n > 0 then return sqrt(Q / n) end +end + +local function f_stddev_fini(accu) + local A, Q, n = unpack(accu) + if n > 1 then return sqrt(Q / (n - 1)) end +end + +local function f_var_fini(accu) + local A, Q, n = unpack(accu) + if n > 0 then return Q / n end +end + +local stat_lookup = { + mean = {f = function(accu, x, n) return (accu * (n-1) + x) / n end}, + stddev = {f = f_stddev, f0 = || {0, 0, 0}, fini = f_stddev_fini}, + stddevp = {f = f_stddev, f0 = || {0, 0, 0}, fini = f_stddevp_fini}, + var = {f = f_stddev, f0 = || {0, 0, 0}, fini = f_var_fini}, + sum = {f = function(accu, x, n) return accu + x end}, + count = {f = function(accu, x, n) return n end}, +} + +local function quicksort_mirror(t, f, mirror) + + local function quicksort(start, endi) + if start >= endi then return end + local pivot = start + for i = start + 1, endi do + if f(t[i], t[pivot]) then + local temp = t[pivot + 1] + local temp_m = mirror[pivot + 1] + t[pivot + 1] = t[pivot] + mirror[pivot + 1] = mirror[pivot] + if(i == pivot + 1) then + t[pivot] = temp + mirror[pivot] = temp_m + else + t[pivot] = t[i] + t[i] = temp + mirror[pivot] = mirror[i] + mirror[i] = temp_m + end + pivot = pivot + 1 + end + end + + quicksort(start, pivot - 1) + quicksort(pivot + 1, endi) + end + + quicksort(1, #t) +end + +local function sort_labels_func(lab_a, lab_b) + local n = #lab_a + for k = 1, n do + local a, b = lab_a[k], lab_b[k] + if a ~= b then return a < b end + end + return false +end + +local function compare_list(a, b) + local n = #a + for k = 1, n do + if a[k] ~= b[k] then return false end + end + return true +end + +local function has_undef_values(ls) + local n = #ls + for k = 1, n do + if not ls[k] then return true end + end + return false +end + +local function add_unique(ls, e) + if has_undef_values(e) then return 0 end + + local n = #ls + for i = 1, n do + if compare_list(ls[i], e) then return i end + end + ls[n + 1] = e + return n + 1 +end + +local function collate_factors(t, i, js) + local c = {} + local n = #js + for k = 1, n do + c[k] = t:get(i, js[k]) + end + return c +end + +local function vec2d_get(r, i, j) + if r[i] and r[i][j] then + return r[i][j] + end +end + +local function vec2d_set(r, i, j, v) + if not r[i] then r[i] = {} end + r[i][j] = v +end + +local function vec2d_incr(r, i, j) + if not r[i] then r[i] = {} end + local v = r[i][j] or 0 + r[i][j] = v + 1 + return v + 1 +end + +local function eval_scalar_gen(t) + local i + local id_res = function(expr) return t:get(i, expr.index) end + local func_res = function(expr) return math[expr.func] end + local set = function(ix) i = ix end + return set, {ident= id_res, func= func_res} +end + +local function rect_funcbin(t, jxs, jys, jes) + local eval_set, eval_scope = eval_scalar_gen(t) + local eval = expr_print.eval + + local n = #t + local val, count = {}, {} + local enums, labels = {}, {} + local fini_table = {} + for i = 1, n do + eval_set(i) + local c = collate_factors(t, i, jxs) + for p = 1, #jys do + local jp = jys[p] + local fy, fini = jp.f, jp.fini + local f0 = jp.f0 and jp.f0() or 0 + local e = collate_factors(t, i, jes) + e[#e+1] = jp.name + + local v = eval(jp.expr, eval_scope) + if v then + local ie = add_unique(enums, e) + local ix = ie > 0 and add_unique(labels, c) or 0 + if ix > 0 then + local cc = vec2d_incr(count, ix, ie) + local v_accu = vec2d_get(val, ix, ie) or f0 + vec2d_set(val, ix, ie, fy(v_accu, v, cc)) + fini_table[ie] = fini + end + end + end + end + + for ie, enum in ipairs(enums) do + local fini = fini_table[ie] + if fini then + for ix = 1, #labels do + local v = vec2d_get(val, ix, ie) + local v_fin = fini(v) + vec2d_set(val, ix, ie, v_fin) + end + end + end + + quicksort_mirror(labels, sort_labels_func, val) + + return labels, enums, val +end + +local function infix_ast(sym, a, b) + return {operator= sym, a, b} +end + +local function prefix_ast(sym, a) + return {operator= sym, a} +end + +local function func_eval_ast(func_name, arg_expr) + return {func= func_name, arg= arg_expr} +end + +local function itself(x) return x end + +local function plot_actions_gen(t) + + local function ident_ast(id) + local i = t:col_index(id) + if not i then error('unknown column name: '..id) end + return {name= id, index= i} + end + + return { + infix = infix_ast, + prefix = prefix_ast, + ident = ident_ast, + enum = ident_ast, + func_eval = func_eval_ast, + number = itself, + exprlist = function(a, ls) if ls then ls[#ls+1] = a else ls = {a} end; return ls end, + schema = function(x, y, enums) return {x= x, y= y, enums= enums} end, + } +end + +local stat_lookup = { + mean = {f = function(accu, x, n) return (accu * (n-1) + x) / n end}, + stddev = {f = f_stddev, f0 = || {0, 0, 0}, fini = f_stddev_fini}, + stddevp = {f = f_stddev, f0 = || {0, 0, 0}, fini = f_stddevp_fini}, + var = {f = f_stddev, f0 = || {0, 0, 0}, fini = f_var_fini}, + sum = {f = function(accu, x, n) return accu + x end}, + count = {f = function(accu, x, n) return n end}, +} + +local function get_stat(expr) + if expr.func and stat_lookup[expr.func]then + return expr.func, expr.arg + else + return 'mean', expr + end +end + +local rect, webcolor, path = graph.rect, graph.webcolor, graph.path + +function gen_xlabels(plt, labels) + local lab0 = labels[1] + local n = #lab0 + local lspecs, accu = {}, {} + for k = 1, n do lspecs[k], accu[k] = {}, {1, lab0[k]} end + for j = 2, #labels do + local lab = labels[j] + for k = 1, n do + local f = lab[k] + local accu_k = accu[k] + if f ~= accu_k[2] then + local ls = lspecs[k] + ls[#ls+1] = accu_k[1] - 1 + ls[#ls+1] = accu_k[2] + accu_k[1] = j + accu_k[2] = f + end + end + end + + for k = 1, n do + local ls = lspecs[k] + local accu_k = accu[k] + ls[#ls+1] = accu_k[1] - 1 + ls[#ls+1] = accu_k[2] + ls[#ls+1] = #labels + + plt:set_multi_labels(1, ls) + end +end + +local barplot = {xlabels = gen_xlabels} + +function barplot.create(labels, enums, val) + local plt = graph.plot() + local pad = 0.1 + local dx = (1 - 2*pad) / #enums + for p, lab in ipairs(labels) do + for q, _ in ipairs(enums) do + local v = val[p][q] + if v then + local x = (p - 1) + pad + dx * (q - 1) + local r = rect(x, 0, x + dx, val[p][q]) + plt:add(r, webcolor(q)) + end + end + end + return plt +end + +function barplot.legend(plt, labels, enums) + if #enums > 1 then + for k = 1, #enums do + plt:legend(collate(enums[k], '/'), webcolor(k), 'square') + end + end +end + +local lineplot = {xlabels = gen_xlabels} + +local function legend_symbol(sym, dx, dy) + if sym == 'square' then + return graph.rect(5+dx, 5+dy, 15+dx, 15+dy) + elseif sym == 'line' then + return graph.segment(dx, 10+dy, 20+dx, 10+dy), {{'stroke', width=line_width}} + else + return graph.marker(10+dx, 10+dy, sym, 8) + end +end + +local function add_legend(lg, k, symspec, color, text) + local y = -k * 20 + local sym, tr = legend_symbol(symspec, 0, y) + lg:add(sym, color, tr) + if text then + lg:add(graph.textshape(25, y + 6, text, 14), 'black') + end +end + +function lineplot.create(labels, enums, val) + local plt = graph.plot() + plt.pad, plt.clip = true, false + + for q, en in ipairs(enums) do + local ln = path() + local path_method = ln.move_to + for p, lab in ipairs(labels) do + local y = val[p][q] + if y then + path_method(ln, p - 0.5, y) + path_method = ln.line_to + else + path_method = ln.move_to + end + end + plt:add(ln, webcolor(q), {{'stroke', width=line_width}}) + plt:add(ln, webcolor(q), {{'marker', size=8, mark=q}}) + end + + return plt +end + +function lineplot.legend(plt, labels, enums) + if #enums > 1 then + local lg = graph.plot() + lg.units, lg.clip = false, false + for q, en in ipairs(enums) do + local label = collate(en) + add_legend(lg, q, 'line', webcolor(q), label) + add_legend(lg, q, q, webcolor(q)) + end + plt:set_legend(lg) + end +end + +local function idents_get_column_indexes(t, exprs) + local jxs = {} + for i, expr in ipairs(exprs) do + if not expr.name then error('invalid enumeration factor') end + jxs[i] = t:col_index(expr.name) + end + return jxs +end + +local function stat_expr_get_functions(exprs) + local jys = {} + for i, expr in ipairs(exprs) do + local stat_name, yexpr = get_stat(expr) + local s = stat_lookup[stat_name] + jys[i] = { + f = s.f, + f0 = s.f0, + fini = s.fini, + name = expr_print.expr(expr), + expr = yexpr, + } + end + return jys +end + +local function expr_get_functions(exprs) + local jys = {} + for i, expr in ipairs(exprs) do + jys[i] = { + name = expr_print.expr(expr), + expr = expr, + } + end + return jys +end + +local function schema_from_plot_descr(plot_descr, t) + local l = mini.lexer(plot_descr) + local actions = plot_actions_gen(t) + return mini.gschema(l, actions) +end + +local function gdt_table_category_plot(plotter, t, plot_descr, opt) + local show_plot = true + if opt then show_plot = (opt.show ~= false) end + + local schema = schema_from_plot_descr(plot_descr, t) + local jxs = idents_get_column_indexes(t, schema.x) + local jys = stat_expr_get_functions(schema.y) + local jes = idents_get_column_indexes(t, schema.enums) + + local labels, enums, val = rect_funcbin(t, jxs, jys, jes) + + local plt = plotter.create(labels, enums, val) + plotter.xlabels(plt, labels) + plotter.legend(plt, labels, enums) + + if show_plot then plt:show() end + return plt +end + +function gdt.xyline(t, plot_descr) + local schema = schema_from_plot_descr(plot_descr, t) + local jxs = expr_get_functions(schema.x) + local jys = expr_get_functions(schema.y) + + assert(#jys == 1, "single y expression required") + + local jx, jy = jxs[1], jys[1] + local n = #t + + local eval_set, eval_scope = eval_scalar_gen(t) + local eval = expr_print.eval + + local ln = path() + local path_method = ln.move_to + for i = 1, n do + eval_set(i) + local x, y = eval(jx.expr, eval_scope), eval(jy.expr, eval_scope) + if x and y then + path_method(ln, x, y) + path_method = ln.line_to + else + path_method = ln.move_to + end + end + + return ln +end + +local function gdt_table_xyplot(t, plot_descr, opt) + local show_plot = true + if opt then show_plot = (opt.show ~= false) end + + local use_lines = opt and opt.lines + local use_markers = opt and (opt.markers ~= false) or true + + local schema = schema_from_plot_descr(plot_descr, t) + local jxs = expr_get_functions(schema.x) + local jys = expr_get_functions(schema.y) + local jes = idents_get_column_indexes(t, schema.enums) + local jx = jxs[1] + + local eval_set, eval_scope = eval_scalar_gen(t) + local eval = expr_print.eval + + local enums = {} + local n = #t + for i = 1, n do + local e = collate_factors(t, i, jes) + add_unique(enums, e) + end + + local plt, lg = graph.plot(), graph.plot() + plt.pad, plt.clip = true, false + lg.units, lg.clip = false, false + local mult = #enums * #jys + for p = 1, #jys do + local name = jys[p].name + for q, enum in ipairs(enums) do + local ln = path() + local path_method = ln.move_to + for i = 1, n do + eval_set(i) + local e = collate_factors(t, i, jes) + if compare_list(enum, e) then + local x, y = eval(jx.expr, eval_scope), eval(jys[p].expr, eval_scope) + if x and y then + path_method(ln, x, y) + path_method = ln.line_to + else + path_method = ln.move_to + end + end + end + + local iqs = {} + if #enums > 1 then iqs[#iqs+1] = collate(enum) end + if #jys > 1 then iqs[#iqs+1] = name end + local ienum = concat(iqs, " ") + local iq = (q - 1) * #jys + p + if mult > 1 then + add_legend(lg, iq, iq, webcolor(iq), ienum) + end + + if use_lines then + plt:add(ln, webcolor(iq), {{'stroke', width=3}}) + end + if use_markers then + plt:add(ln, webcolor(iq), {{'marker', size=6, mark=iq}}) + end + end + end + + if mult > 1 then plt:set_legend(lg) end + + if show_plot then plt:show() end + return plt +end + +function gdt.reduce(t_src, schema_descr) + local schema = schema_from_plot_descr(schema_descr, t_src) + local jxs = idents_get_column_indexes(t_src, schema.x) + local jys = stat_expr_get_functions(schema.y) + local jes = idents_get_column_indexes(t_src, schema.enums) + + local labels, enums, val = rect_funcbin(t_src, jxs, jys, jes) + + local n, p, q = #labels, #enums, #labels[1] + local t = gdt.alloc(n, q + p) + + for k = 1, q do + t:set_header(k, t_src:header(jxs[k])) + end + for k, en in ipairs(enums) do + t:set_header(q + k, collate(en, "/")) + end + + local set = t.set + for i = 1, n do + for k = 1, q do + set(t, i, k, labels[i][k]) + end + for k = 1, p do + set(t, i, q + k, val[i][k]) + end + end + + return t +end + +local function is_simple_numeric(t, plot_descr) + local gdt_eval_actions = require('gdt-eval') + local actions = gdt_eval_actions(t) + local l = mini.lexer(plot_descr) + local schema = mini.gschema(l, actions) + if #schema.x == 1 then + local expr = schema.x[1] + return (expr.factor == nil) + end + return false +end + +function gdt.plot(t, plot_descr, opts) + if is_simple_numeric(t, plot_descr) then + return gdt_table_xyplot(t, plot_descr, opts) + else + return gdt_table_category_plot(lineplot, t, plot_descr, opts) + end +end + +function gdt.lineplot(t, plot_descr, opts) + return gdt_table_category_plot(lineplot, t, plot_descr, opts) +end + +function gdt.barplot(t, plot_descr, opts) + return gdt_table_category_plot(barplot, t, plot_descr, opts) +end diff --git a/gdt.lua b/gdt.lua new file mode 100644 index 00000000..1a1add67 --- /dev/null +++ b/gdt.lua @@ -0,0 +1,315 @@ +local cgdt = require 'cgdt' + +local format = string.format +local concat = table.concat +local max = math.max +local assert = assert + +local gdt_table = ffi.typeof("gdt_table") +local gdt_table_cursor = ffi.typeof("gdt_table_cursor") + +local TAG_STRING = tonumber(cgdt.TAG_STRING) +local TAG_NUMBER = tonumber(cgdt.TAG_NUMBER) + +local function element_is_number(e) + return (e.word.hi <= TAG_NUMBER) +end + +local function gdt_element(t, e) + local val + if e.word.hi <= TAG_NUMBER then + val = e.number + elseif e.word.hi == TAG_STRING then + local s = cgdt.gdt_table_element_get_string(t, e) + assert(s ~= nil, "invalid gdt element string refernce") + return ffi.string(s) + end + return val +end + +local function gdt_table_get(t, i, j) + assert(i > 0 and i <= t.size1, 'invalid row index') + local e + if type(j) == 'string' then + e = cgdt.gdt_table_get_by_name(t, i - 1, j) + assert(e ~= nil, "invalid column name") + else + assert(j > 0 and j <= t.size2, 'invalid column index') + e = cgdt.gdt_table_get(t, i - 1, j - 1) + end + return gdt_element(t, e) +end + +local function gdt_table_get_number_unsafe(t, i, j) + local e = cgdt.gdt_table_get(t, i - 1, j - 1) + if e.word.hi <= TAG_NUMBER then return e.number end +end + +local function gdt_table_set_unsafe(t, i, j, val) + local tp = type(val) + if tp == 'number' then + cgdt.gdt_table_set_number(t, i - 1, j - 1, val) + elseif tp == 'string' then + cgdt.gdt_table_set_string(t, i - 1, j - 1, val) + else + assert(tp ~= nil, 'expect a number, string or nil value') + cgdt.gdt_table_set_undef(t, i - 1, j - 1) + end +end + +local function gdt_table_set(t, i, j_name, val) + assert(i > 0 and i <= t.size1, 'invalid row index') + local j + if type(j_name) == 'string' then + local index = cgdt.gdt_table_header_index(t, j_name) + assert(index >= 0, 'invalid column index') + j = index + 1 + else + assert(type(j_name) == 'number', 'invalid column index') + j = j_name + assert(j > 0 and j <= t.size2, 'invalid column index') + end + gdt_table_set_unsafe(t, i, j, val) +end + +local function gdt_table_alloc(nrows, ncols, nalloc_rows) + nalloc_rows = nalloc_rows or nrows + local headers + if type(ncols) == 'table' then + headers = ncols + ncols = #headers + end + local t = cgdt.gdt_table_new(nrows, ncols, nalloc_rows) + if headers then + for k, str in ipairs(headers) do + cgdt.gdt_table_set_header(t, k - 1, str) + end + end + if t == nil then error('cannot allocate table: not enough memory') end + return ffi.gc(t, cgdt.gdt_table_free) +end + +local function gdt_table_new(nrows, cols_spec) + local t = gdt_table_alloc(nrows, cols_spec) + local ncols = t.size2 + for i = 1, nrows do + for j = 1, ncols do + cgdt.gdt_table_set_undef(t, i - 1, j - 1) + end + end + return t +end + +local function gdt_table_dim(t) return t.size1, t.size2 end + +local function gdt_table_get_header(t, k) + assert(k > 0 and k <= t.size2, 'invalid column index') + local s = cgdt.gdt_table_get_header(t, k - 1) + return (s == nil and 'V' .. k or ffi.string(s)) +end + +local function gdt_table_set_header(t, k, str) + assert(k > 0 and k <= t.size2, 'invalid column index') + cgdt.gdt_table_set_header(t, k - 1, str) +end + +local function gdt_table_header_index(t, name) + local j = cgdt.gdt_table_header_index(t, name) + return (j >= 0 and j + 1 or nil) +end + +local function gdt_table_len(t) + return t.size1 +end + +local function gdt_table_column_iter(t, j) + local n = #t + local f = function(_t, i) + if i + 1 > n then return nil else return i + 1, _t:get(i + 1, j) end + end + return f, t, 0 +end + +local function gdt_table_insert_column(t, col_name, j, f) + cgdt.gdt_table_insert_columns(t, j - 1, 1) + + local n = #t + if not f then + for i = 1, n do + cgdt.gdt_table_set_undef(t, i - 1, j - 1) + end + else + for i, row in t:rows() do + local status, x = pcall(f, row, i) + t:set(i, j, status and x or nil) + end + end + + t:set_header(j, col_name) +end + +local function gdt_table_append_column(t, col_name, f) + gdt_table_insert_column(t, col_name, t.size2 + 1, f) +end + +local function val_tostr(e) + if type(e) == "number" then + return format("%g", e) + else + return e or 'NA' + end +end + +local function gdt_table_show(dt) + local field_lens = {} + local r, c = gdt_table_dim(dt) + for k = 1, c do + field_lens[k] = # gdt_table_get_header(dt, k) + end + for i = 1, r do + for j = 1, c do + local len = #val_tostr(gdt_table_get(dt, i, j)) + field_lens[j] = max(field_lens[j], len) + end + end + + local field_fmts = {} + for j = 1, c do + field_fmts[j] = format('%%%ds', field_lens[j]) + end + + local lines = {} + + local row_ndig = #tostring(#dt) + local t = {string.rep(" ", row_ndig)} + for j = 1, c do + t[#t+1] = format(field_fmts[j], gdt_table_get_header(dt, j)) + end + lines[1] = concat(t, ' ') + + for i = 1, r do + local t = {format("%-" .. row_ndig .. "d", i)} + for j = 1, c do + local x = gdt_table_get(dt, i, j) + t[#t+1] = format(field_fmts[j], val_tostr(x)) + end + lines[#lines + 1] = concat(t, ' ') + end + return concat(lines, '\n') +end + +local function gdt_table_get_cursor(t) + local c = cgdt.gdt_table_get_cursor(t) + c.__index = 0 + return c +end + +local function gdt_table_headers(t) + local m = t.size2 + local name = {} + for k = 1, m do name[k] = gdt_table_get_header(t, k) end + return name +end + +local function gdt_table_rows(t) + local n = #t + local cursor = cgdt.gdt_table_get_cursor(t) + local function f(t, i) + i = i + 1 + if i <= n then + cursor.__index = i - 1 + return i, cursor + end + end + return f, t, 0 +end + +local function gdt_table_filter(t, f) + local n, m = t:dim() + local n_curr = 0 + local new = gdt.alloc(n_curr, m, 16) + for i, row in t:rows() do + if f(row, i) then + n_curr = n_curr + 1 + cgdt.gdt_table_insert_rows(new, n_curr - 1, 1) + for j = 1, m do + local e = cgdt.gdt_table_get(t, i - 1, j - 1) + local v = gdt_element(t, e) + gdt.set(new, n_curr, j, v) + end + end + end + for j = 1, m do + new:set_header(j, t:header(j)) + end + return new +end + +local function find_column_type(t, j) + local n = #t + for i = 1, n do + local x = t:get(i, j) + if type(x) == 'string' then return 'factor' end + end + return 'scalar' +end + +local function gdt_table_column_type(t, col) + local j = (type(col) == 'string') and gdt_table_header_index(t, col) or col + assert(type(j) == 'number', 'invalid column') + return find_column_type(t, j) +end + +local gdt_methods = { + dim = gdt_table_dim, + get = gdt_table_get, + set = gdt_table_set, + header = gdt_table_get_header, + set_header = gdt_table_set_header, + headers = gdt_table_headers, + show = gdt_table_show, + column = gdt_table_column_iter, + col_index = gdt_table_header_index, + col_type = gdt_table_column_type, + insert = gdt_table_insert_column, + append = gdt_table_append_column, + cursor = gdt_table_get_cursor, + rows = gdt_table_rows, +} + +local gdt_mt = { + __index = gdt_methods, + __len = gdt_table_len, +} + +ffi.metatype(gdt_table, gdt_mt) + +local function gdt_table_cursor_get(c, k) + local e = cgdt.gdt_table_cursor_get(c, k) + if e ~= nil then + local t = c.__table + return gdt_element(t, e) + end + return nil +end + +local cursor_mt = { + __index = gdt_table_cursor_get, +} + +ffi.metatype(gdt_table_cursor, cursor_mt) + +local register_ffi_type = debug.getregistry().__gsl_reg_ffi_type +register_ffi_type(gdt_table, "data table") + +gdt = { + new = gdt_table_new, + alloc = gdt_table_alloc, + get = gdt_table_get, + set = gdt_table_set, + filter = gdt_table_filter, + + get_number_unsafe = gdt_table_get_number_unsafe, +} + +return gdt diff --git a/gdt/Makefile b/gdt/Makefile new file mode 100644 index 00000000..c0c3b630 --- /dev/null +++ b/gdt/Makefile @@ -0,0 +1,57 @@ + +# Makefile +# +# Copyright (C) 2009 Francesco Abbate +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or (at +# your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +GSH_BASE_DIR = .. + +include $(GSH_BASE_DIR)/makeconfig +include $(GSH_BASE_DIR)/make-system-detect +include $(GSH_BASE_DIR)/makepackages +include $(GSH_BASE_DIR)/makedefs + +INCLUDES += -I$(GSH_BASE_DIR) + +CFLAGS += -std=c99 + +GDT_SRC_FILES = char_buffer.c gdt_index.c gdt_table.c +GDT_OBJ_FILES := $(GDT_SRC_FILES:%.c=%.o) + +DEP_FILES := $(GDT_SRC_FILES:%.c=.deps/%.P) + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +COMPILE = $(CC) $(CFLAGS) $(LUA_CFLAGS) $(DEFS) $(INCLUDES) + +TARGETS = libgdt.a + +all: $(TARGETS) + +libgdt.a: $(GDT_OBJ_FILES) + @echo Archive $@ + @$(AR) $@ $? + @$(RANLIB) $@ + +include $(GSH_BASE_DIR)/makerules + +.PHONY: clean all + +clean: + $(HOST_RM) *.o *.a *$(DLL_EXT) $(TARGETS) + +-include $(DEP_FILES) diff --git a/gdt/char_buffer.c b/gdt/char_buffer.c new file mode 100644 index 00000000..8e434cde --- /dev/null +++ b/gdt/char_buffer.c @@ -0,0 +1,71 @@ +#include <string.h> +#include "char_buffer.h" +#include "xmalloc.h" + +#define CHAR_BUFFER_ALIGN_SHIFT 2 +#define CHAR_BUFFER_ALIGN (1 << CHAR_BUFFER_ALIGN_SHIFT) +#define CHAR_BUFFER_ALIGN_MASK (CHAR_BUFFER_ALIGN - 1) + +static inline size_t roundup_size(size_t s) +{ + return (s + CHAR_BUFFER_ALIGN_MASK) & ~CHAR_BUFFER_ALIGN_MASK; +} + +/* copy data like memcpy but assume that data are aligned with + CHAR_BUFFER_ALIGN and padded with zeros at the end of buffer. */ +static inline void bufcopy(char* _dst, const char* _src, size_t _sz) +{ + int* dst = (int *) _dst; + const int* src = (const int*) _src; + int const * const end_ptr = dst + (_sz >> CHAR_BUFFER_ALIGN_SHIFT); + while (dst < end_ptr) { + *(dst++) = *(src++); + } +} + +void +char_buffer_init(struct char_buffer *b, size_t sz) +{ + b->size = roundup_size(sz); + b->data = xmalloc(b->size); + b->data[0] = 0; + b->length = 0; +} + +void +char_buffer_free(struct char_buffer *b) +{ + free(b->data); +} + +static void +char_buffer_resize(struct char_buffer *b, size_t req_size) +{ + req_size = round_two_power(req_size); + char *new_data = xmalloc(req_size); + bufcopy(new_data, b->data, b->length); + free(b->data); + b->data = new_data; + b->size = req_size; +} + +int +char_buffer_append(struct char_buffer *b, const char *str) +{ + const size_t len = strlen(str); + const int string_offset = b->length; + const size_t new_len = string_offset + roundup_size(len+1); + if (new_len > b->size) + char_buffer_resize(b, new_len); + + /* zero the final word of the destination buffer */ + int* const end_ptr = ((int *) (b->data + new_len)) - 1; + *end_ptr = 0; + + /* copy the string data into destination buffer. The final + zero is not needed since the last word of dest buffer was + padded with zeros. */ + memcpy(b->data + string_offset, str, len); + b->length = new_len; + return string_offset; +} diff --git a/gdt/char_buffer.h b/gdt/char_buffer.h new file mode 100644 index 00000000..fe44695a --- /dev/null +++ b/gdt/char_buffer.h @@ -0,0 +1,14 @@ +#ifndef GDT_CHAR_BUFFER_H +#define GDT_CHAR_BUFFER_H + +struct char_buffer { + char *data; + size_t length; + size_t size; +}; + +extern void char_buffer_init(struct char_buffer *b, size_t sz); +extern void char_buffer_free(struct char_buffer *b); +extern int char_buffer_append(struct char_buffer *b, const char *str); + +#endif diff --git a/gdt/gdt_index.c b/gdt/gdt_index.c new file mode 100644 index 00000000..7b94be59 --- /dev/null +++ b/gdt/gdt_index.c @@ -0,0 +1,81 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include "gdt_index.h" +#include "xmalloc.h" + +#define STRING_SECTION_INIT_SIZE 256 + +gdt_index * +gdt_index_new(int alloc_size) +{ + size_t extra_size = sizeof(int) * (alloc_size - INDEX_AUTO); + gdt_index *g = xmalloc(sizeof(gdt_index) + extra_size); + char_buffer_init(g->names, STRING_SECTION_INIT_SIZE); + g->length = 0; + g->size = alloc_size; + return g; +} + +void +gdt_index_free(gdt_index *g) +{ + char_buffer_free(g->names); + free(g); +} + +gdt_index * +gdt_index_resize(gdt_index *g) +{ + size_t alloc_size = g->size * 2; + size_t extra_size = sizeof(int) * (alloc_size - INDEX_AUTO); + gdt_index *new_g = xmalloc(sizeof(gdt_index) + extra_size); + + new_g->names[0] = g->names[0]; + new_g->length = g->length; + new_g->size = alloc_size; + memcpy(new_g->index, g->index, sizeof(int) * g->length); + + free(g); + return new_g; +} + +int +gdt_index_add(gdt_index *g, const char *str) +{ + /* if the index table is not big enough return error code */ + if (g->length + 1 > g->size) + return (-1); + + /* add the given string in the key string buffer */ + int str_offset = char_buffer_append(g->names, str); + + /* add the new string offset index into the index table */ + int idx = g->length; + g->index[idx] = str_offset; + g->length ++; + return idx; +} + +const char * +gdt_index_get(gdt_index *g, int index) +{ + if (index < 0 || index >= g->length) + return NULL; + return g->names->data + g->index[index]; +} + +int +gdt_index_lookup(gdt_index *g, const char *req) +{ + const char *base = g->names->data; + for (int k = 0; k < g->length; k++) + { + const char *str = base + g->index[k]; + if (strcmp(str, req) == 0) + return k; + } + return (-1); +} diff --git a/gdt/gdt_index.h b/gdt/gdt_index.h new file mode 100644 index 00000000..714b06a1 --- /dev/null +++ b/gdt/gdt_index.h @@ -0,0 +1,23 @@ +#ifndef GDT_INDEX_H +#define GDT_INDEX_H + +#include "defs.h" +#include "char_buffer.h" + +#define INDEX_AUTO 4 + +typedef struct { + struct char_buffer names[1]; + int length; + int size; + int index[INDEX_AUTO]; +} gdt_index; + +extern gdt_index * gdt_index_new (int alloc_size); +extern void gdt_index_free (gdt_index *g); +extern gdt_index * gdt_index_resize (gdt_index *g); +extern int gdt_index_add (gdt_index *g, const char *str); +extern const char * gdt_index_get (gdt_index *g, int index); +extern int gdt_index_lookup (gdt_index *g, const char *req); + +#endif diff --git a/gdt/gdt_table.c b/gdt/gdt_table.c new file mode 100644 index 00000000..7f68a443 --- /dev/null +++ b/gdt/gdt_table.c @@ -0,0 +1,372 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "gdt_table.h" +#include "xmalloc.h" + +static inline int +elem_is_string(const gdt_element* e) +{ + return e->word.hi == TAG_STRING; +} + +static inline int +elem_is_undef(const gdt_element* e) +{ + return e->word.hi == TAG_UNDEF; +} + +static void +string_array_init(struct string_array *v, int length) +{ + char_buffer_init(v->buffer, 256); + v->offset_data = xmalloc(sizeof(int) * length); + v->offset_len = length; + for (int k = 0; k < length; k++) + { + v->offset_data[k] = -1; + } +} + +static void +string_array_free(struct string_array *v) +{ + char_buffer_free(v->buffer); + free(v->offset_data); +} + +static const char * +string_array_get(struct string_array *v, int k) +{ + int offset = v->offset_data[k]; + return (offset >= 0 ? v->buffer->data + offset : NULL); +} + +static void +string_array_set(struct string_array *v, int k, const char *str) +{ + int offset = char_buffer_append(v->buffer, str); + v->offset_data[k] = offset; +} + +static int +string_array_lookup(struct string_array *v, const char *key) +{ + int k, len = v->offset_len; + const char * base_data = v->buffer->data; + for (k = 0; k < len; k++) + { + int offset = v->offset_data[k]; + if (offset >= 0 && strcmp(base_data + offset, key) == 0) + return k; + } + return (-1); +} + +static void +string_array_insert(struct string_array *v, int j_in, int n) +{ + int new_len = v->offset_len + n; + int old_len = v->offset_len; + int *new_data = xmalloc(sizeof(int) * new_len); + int *old_data = v->offset_data; + int j, k; + + for (j = 0; j < j_in; j++) + new_data[j] = old_data[j]; + for (k = 0; k < n; k++) + new_data[j_in + k] = -1; + for (/* */; j < old_len; j++) + new_data[j + n] = old_data[j]; + + free(v->offset_data); + + v->offset_data = new_data; + v->offset_len = new_len; +} + +/* match string in the form "V[1-9]\d*". strtol is not used because + it does match other forms like for example "V +015". */ +static int +match_anonymous_header(const char* s) +{ + if (*s == 'V') { + const int int0 = (int) '0', int9 = (int) '9'; + const int s0 = *(++s); + if (s0 > int0 && s0 <= int9) { + int accu = s0 - int0; + for (s++; (int) s[0] >= int0 && (int) s[0] <= int9; s++) { + accu = accu * 10 + ((int)s[0] - int0); + } + if (*s == 0) { + return (accu - 1); + } + } + } + return (-1); +} + +static gdt_block * +gdt_block_new(int size) +{ + gdt_element *data = malloc(size * sizeof(gdt_element)); + if (unlikely(data == 0)) + return NULL; + gdt_block *b = xmalloc(sizeof(gdt_block)); + b->data = data; + b->size = size; + b->ref_count = 0; + return b; +} + +static void +gdt_block_ref(gdt_block *b) +{ + b->ref_count ++; +} + +static void +gdt_block_unref(gdt_block *b) +{ + b->ref_count --; + if (b->ref_count <= 0) + { + free(b->data); + free(b); + } +} + +gdt_table * +gdt_table_new(int nb_rows, int nb_columns, int nb_rows_alloc) +{ + int sz = nb_columns * nb_rows_alloc; + if (unlikely(sz <= 0)) return NULL; + gdt_block *b = gdt_block_new(sz); + if (unlikely(b == NULL)) return NULL; + gdt_block_ref(b); + + gdt_table *dt = xmalloc(sizeof(gdt_table)); + + dt->size1 = nb_rows; + dt->size2 = nb_columns; + dt->tda = nb_columns; + dt->data = b->data; + dt->block = b; + + dt->strings = gdt_index_new(16); + + string_array_init(dt->headers, nb_columns); + + dt->cursor->table = dt; + + return dt; +} + +void +gdt_table_free(gdt_table *t) +{ + gdt_block_unref(t->block); + gdt_index_free(t->strings); + string_array_free(t->headers); + t->cursor->table = NULL; +} + +const gdt_element * +gdt_table_get(gdt_table *t, int i, int j) +{ + return &t->data[i * t->tda + j]; +} + +const gdt_element * +gdt_table_get_by_name(gdt_table *t, int i, const char* col_name) +{ + int j = gdt_table_header_index(t, col_name); + if (j >= 0) { + return gdt_table_get(t, i, j); + } + return NULL; +} + +int +gdt_table_header_index(gdt_table *t, const char* col_name) +{ + int j = string_array_lookup(t->headers, col_name); + if (likely(j >= 0)) { + return j; + } else { + int jan = match_anonymous_header(col_name); + if (jan >= 0 && jan < t->size2) { + const char* name = string_array_get(t->headers, jan); + if (!name) { + return jan; + } + } + } + return (-1); +} + +const char * +gdt_table_element_get_string(gdt_table *t, const gdt_element *e) +{ + if (elem_is_string(e)) + return gdt_index_get(t->strings, e->word.lo); + return NULL; +} + +void +gdt_table_set_undef(gdt_table *t, int i, int j) +{ + gdt_element *e = &t->data[i * t->tda + j]; + e->word.hi = TAG_UNDEF; +} + +void +gdt_table_set_number(gdt_table *t, int i, int j, double num) +{ + gdt_element *e = &t->data[i * t->tda + j]; + e->number = num; +} + +void +gdt_table_set_string(gdt_table *t, int i, int j, const char *s) +{ + gdt_element *e = &t->data[i * t->tda + j]; + + int str_index = gdt_index_lookup(t->strings, s); + if (str_index < 0) + { + str_index = gdt_index_add(t->strings, s); + if (str_index < 0) + { + t->strings = gdt_index_resize(t->strings); + str_index = gdt_index_add(t->strings, s); + } + } + + e->word.hi = TAG_STRING; + e->word.lo = str_index; +} + +const char * +gdt_table_get_header(gdt_table *t, int j) +{ + return string_array_get(t->headers, j); +} + +void +gdt_table_set_header(gdt_table *t, int j, const char *str) +{ + string_array_set(t->headers, j, str); +} + +int +gdt_table_insert_columns(gdt_table *t, int j_in, int n) +{ + int os2 = t->size2, ns2 = t->size2 + n; + int sz = ns2 * t->size1; + int *src, *dst; + int i; + + if (unlikely(sz <= 0)) return (-1); + gdt_block *new_block = gdt_block_new(sz); + if (unlikely(new_block == NULL)) return (-1); + gdt_block_ref(new_block); + + src = (int *) t->data; + dst = (int *) new_block->data; + + for (i = 0; i < t->size1; i++) + { + int j; + + for (j = 0; j < 2 * j_in; j++) + { + dst[j] = src[j]; + } + for (/* */; j < 2 * os2; j++) + { + dst[j + 2 * n] = src[j]; + } + + dst += 2 * ns2; + src += 2 * os2; + } + + gdt_block_unref(t->block); + + t->size2 = ns2; + t->tda = ns2; + t->block = new_block; + t->data = new_block->data; + + string_array_insert(t->headers, j_in, n); + + return 0; +} + +int +gdt_table_insert_rows(gdt_table *t, int i_in, int n) +{ + int n1 = t->size1, n2 = t->size2; + int i; + + if (t->block->size < (n1 + n) * n2) + { + int size_req = (n1 + n) * n2; + if (unlikely(size_req <= 0)) return (-1); + int new_size = round_two_power(size_req); + gdt_block *new_block = gdt_block_new(new_size); + + if (unlikely(new_block == NULL)) return (-1); + gdt_block_ref(new_block); + + int * const src = (int *) t->data; + int * const dst = (int *) new_block->data; + + for (i = 0; i < 2 * i_in * n2; i++) + { + dst[i] = src[i]; + } + + for (/* */; i < 2 * n1 * n2; i++) + { + dst[i + 2 * n * n2] = src[i]; + } + + gdt_block_unref(t->block); + t->block = new_block; + t->data = new_block->data; + } + else + { + int * const data = (int *) t->data; + for (i = 2 * n1 * n2 - 1; i >= 2 * i_in * n2; i--) + { + data[i + 2 * n * n2] = data[i]; + } + } + + t->size1 = n1 + n; + + return 0; +} + +gdt_table_cursor * +gdt_table_get_cursor(gdt_table *t) +{ + return t->cursor; +} + +const gdt_element * +gdt_table_cursor_get(gdt_table_cursor *c, const char *key) +{ + gdt_table *t = c->table; + int k; + if (!t) + return NULL; + k = string_array_lookup(t->headers, key); + if (k < 0) + return NULL; + return gdt_table_get(t, c->index, k); +} diff --git a/gdt/gdt_table.h b/gdt/gdt_table.h new file mode 100644 index 00000000..55a4880c --- /dev/null +++ b/gdt/gdt_table.h @@ -0,0 +1,75 @@ +#ifndef GDT_TABLE_H +#define GDT_TABLE_H + +#include "defs.h" +#include "gdt_index.h" + +enum { + TAG_STRING = 0xffff0000, + TAG_UNDEF = 0xfffe0000, + TAG_NUMBER = 0xfff80000, +}; + +/* NaN encoding is used to discriminate between (double) numbers + and strings or undef values. + For NaN values "hi" is equal to 0xfff80000 and "lo" is 0. + We use values of "hi" higher then 0xfff80000 to tag non-number + values. In the case of strings "lo" is used to store the string + index. */ +typedef union { + double number; + struct { + unsigned int lo; + unsigned int hi; + } word; +} gdt_element; + +typedef struct { + int size; + gdt_element *data; + int ref_count; +} gdt_block; + +struct string_array { + struct char_buffer buffer[1]; + int *offset_data; + int offset_len; +}; + +struct __gdt_table; + +typedef struct { + int index; + struct __gdt_table *table; +} gdt_table_cursor; + +struct __gdt_table { + int size1; + int size2; + int tda; + gdt_element *data; + gdt_block *block; + gdt_index *strings; + struct string_array headers[1]; + gdt_table_cursor cursor[1]; +}; + +typedef struct __gdt_table gdt_table; + +extern gdt_table * gdt_table_new (int nb_rows, int nb_columns, int nb_rows_alloc); +extern void gdt_table_free (gdt_table *t); +extern const gdt_element * gdt_table_get (gdt_table *t, int i, int j); +extern const gdt_element * gdt_table_get_by_name (gdt_table *t, int i, const char* col_name); +extern const char * gdt_table_element_get_string (gdt_table *t, const gdt_element *e); +extern void gdt_table_set_number (gdt_table *t, int i, int j, double num); +extern void gdt_table_set_string (gdt_table *t, int i, int j, const char *s); +extern void gdt_table_set_undef (gdt_table *t, int i, int j); +extern const char * gdt_table_get_header (gdt_table *t, int j); +extern void gdt_table_set_header (gdt_table *t, int j, const char *str); +extern int gdt_table_header_index (gdt_table *t, const char* col_name); +extern int gdt_table_insert_columns (gdt_table *t, int j_in, int n); +extern int gdt_table_insert_rows (gdt_table *t, int i_in, int n); +extern const gdt_element * gdt_table_cursor_get (gdt_table_cursor *c, const char *key); +extern gdt_table_cursor * gdt_table_get_cursor (gdt_table *t); + +#endif diff --git a/gdt/xmalloc.h b/gdt/xmalloc.h new file mode 100644 index 00000000..646473c9 --- /dev/null +++ b/gdt/xmalloc.h @@ -0,0 +1,31 @@ +#ifndef GDT_XMALLOC_H +#define GDT_XMALLOC_H + +#include <stdlib.h> +#include <stdio.h> +#include "defs.h" + +static inline void *xmalloc(size_t sz) +{ + void *p = malloc(sz); + if (unlikely(p == NULL)) + { + fputs("not enough virtual memory!\n", stderr); + abort(); + } + return p; +} + +static inline unsigned int round_two_power(unsigned int n) +{ + n = n - 1; + n = n | (n >> 1); + n = n | (n >> 2); + n = n | (n >> 4); + n = n | (n >> 8); + n = n | (n >> 16); + n = n + 1; + return n; +} + +#endif diff --git a/graph-init.lua b/graph-init.lua index 8c75f4ef..7cc04fcf 100644 --- a/graph-init.lua +++ b/graph-init.lua @@ -225,8 +225,12 @@ graph.color = { } local bcolors = {'red', 'blue', 'green', 'magenta', 'cyan', 'yellow'} --- colors from a popular spreadsheet application -local wcolors = {0x4f81bd, 0xc0504d, 0x9bbb59, 0x695185, 0x3c8da3, 0xcc7b38} +-- colors from a popular spreadsheet application + random colors from +-- the web +local wcolors = {0x4f81bd, 0xc0504d, 0x9bbb59, 0x695185, 0x3c8da3, 0xcc7b38, + 0x58c3bb, 0xf29a86, 0xbd87bb, 0xc3a492, 0xf0d845, + 0x2d7ac0, 0xfce4ca, 0x8b9068, 0xc0b99d, + 0xD9CCB9, 0xDF7782, 0xE95D22, 0x017890, 0x613D2D} local hue_map = { {231, 0, 0 }, @@ -2395,6 +2395,111 @@ int gsl_sf_eta_int_e(int n, gsl_sf_result * result); double gsl_sf_eta_int(const int n); int gsl_sf_eta_e(const double s, gsl_sf_result * result); double gsl_sf_eta(const double s); + +typedef struct { + size_t n ; + double * range ; + double * bin ; +} gsl_histogram ; + +typedef struct { + size_t n ; + double * range ; + double * sum ; +} gsl_histogram_pdf ; + +gsl_histogram * gsl_histogram_alloc (size_t n); + +gsl_histogram * gsl_histogram_calloc (size_t n); +gsl_histogram * gsl_histogram_calloc_uniform (const size_t n, const double xmin, const double xmax); +void gsl_histogram_free (gsl_histogram * h); +int gsl_histogram_increment (gsl_histogram * h, double x); +int gsl_histogram_accumulate (gsl_histogram * h, double x, double weight); +int gsl_histogram_find (const gsl_histogram * h, + const double x, size_t * i); + +double gsl_histogram_get (const gsl_histogram * h, size_t i); +int gsl_histogram_get_range (const gsl_histogram * h, size_t i, + double * lower, double * upper); + +double gsl_histogram_max (const gsl_histogram * h); +double gsl_histogram_min (const gsl_histogram * h); +size_t gsl_histogram_bins (const gsl_histogram * h); + +void gsl_histogram_reset (gsl_histogram * h); + +gsl_histogram * gsl_histogram_calloc_range(size_t n, double * range); + +int +gsl_histogram_set_ranges (gsl_histogram * h, const double range[], size_t size); +int +gsl_histogram_set_ranges_uniform (gsl_histogram * h, double xmin, double xmax); + + + +int +gsl_histogram_memcpy(gsl_histogram * dest, const gsl_histogram * source); + +gsl_histogram * +gsl_histogram_clone(const gsl_histogram * source); + +double gsl_histogram_max_val (const gsl_histogram * h); + +size_t gsl_histogram_max_bin (const gsl_histogram * h); + +double gsl_histogram_min_val (const gsl_histogram * h); + +size_t gsl_histogram_min_bin (const gsl_histogram * h); + +int +gsl_histogram_equal_bins_p(const gsl_histogram *h1, const gsl_histogram *h2); + +int +gsl_histogram_add(gsl_histogram *h1, const gsl_histogram *h2); + +int +gsl_histogram_sub(gsl_histogram *h1, const gsl_histogram *h2); + +int +gsl_histogram_mul(gsl_histogram *h1, const gsl_histogram *h2); + +int +gsl_histogram_div(gsl_histogram *h1, const gsl_histogram *h2); + +int +gsl_histogram_scale(gsl_histogram *h, double scale); + +int +gsl_histogram_shift (gsl_histogram * h, double shift); + + +double gsl_histogram_sigma (const gsl_histogram * h); + +double gsl_histogram_mean (const gsl_histogram * h); + +double gsl_histogram_sum (const gsl_histogram * h); + +int gsl_histogram_fwrite (FILE * stream, const gsl_histogram * h) ; +int gsl_histogram_fread (FILE * stream, gsl_histogram * h); +int gsl_histogram_fprintf (FILE * stream, const gsl_histogram * h, + const char * range_format, const char * bin_format); +int gsl_histogram_fscanf (FILE * stream, gsl_histogram * h); + +gsl_histogram_pdf * gsl_histogram_pdf_alloc (const size_t n); +int gsl_histogram_pdf_init (gsl_histogram_pdf * p, const gsl_histogram * h); +void gsl_histogram_pdf_free (gsl_histogram_pdf * p); +double gsl_histogram_pdf_sample (const gsl_histogram_pdf * p, double r); + +double gsl_stats_mean (const double data[], const size_t stride, const size_t n); +double gsl_stats_variance (const double data[], const size_t stride, const size_t n); +double gsl_stats_sd (const double data[], const size_t stride, const size_t n); +double gsl_stats_variance_with_fixed_mean (const double data[], const size_t stride, const size_t n, const double mean); +double gsl_stats_sd_with_fixed_mean (const double data[], const size_t stride, const size_t n, const double mean); +double gsl_stats_tss (const double data[], const size_t stride, const size_t n); +double gsl_stats_tss_m (const double data[], const size_t stride, const size_t n, const double mean); + +double gsl_stats_median_from_sorted_data (const double sorted_data[], const size_t stride, const size_t n) ; +double gsl_stats_quantile_from_sorted_data (const double sorted_data[], const size_t stride, const size_t n, const double f) ; ]] diff --git a/gslext.lua b/gslext.lua index 48fe2c94..1f883390 100644 --- a/gslext.lua +++ b/gslext.lua @@ -15,6 +15,11 @@ require('contour') require('sf') require('help') require('vegas') +require('gdt') +require('gdt-parse-csv') +require('gdt-hist') +require('gdt-plot') +require('gdt-lm') num.linfit = require 'linfit' num.bspline = require 'bspline' diff --git a/lm-expr.lua b/lm-expr.lua new file mode 100644 index 00000000..3c59d7c3 --- /dev/null +++ b/lm-expr.lua @@ -0,0 +1,26 @@ +local format = string.format + +local function as_char(v, prio) + if type(v) == 'table' and v.name then + return (v.prio < prio and format("(%s)", v.name) or v.name) + end + return tostring(v) +end + +local var_name + +local var_name_mt = { + __add = function(a, b) return var_name(format("%s + %s", as_char(a, 0), as_char(b, 0)), 0) end, + __mul = function(a, b) return var_name(format("%s * %s", as_char(a, 2), as_char(b, 2)), 2) end, + __sub = function(a, b) return var_name(format("%s - %s", as_char(a, 0), as_char(b, 0)), 0) end, + __div = function(a, b) return var_name(format("%s / %s", as_char(a, 2), as_char(b, 2)), 2) end, + __pow = function(a, b) return var_name(format("%s^%s", as_char(a, 10), as_char(b, 10)), 10) end, + __unm = function(a) return var_name(format("-%s", as_char(a, 1)), 1) end, +} + +var_name = function (name, prio) + local t = {prio= prio or 10, name= name} + return setmetatable(t, var_name_mt) +end + +return var_name diff --git a/lm-helpers.lua b/lm-helpers.lua new file mode 100644 index 00000000..098971fa --- /dev/null +++ b/lm-helpers.lua @@ -0,0 +1,65 @@ +local LM = {} + +local var_name = require 'lm-expr' + +local factor_mt + +local function mul_factor(a, b) + local c = {value= a.value .. ":" .. b.value} + return setmetatable(c, factor_mt) +end + +factor_mt = { + __mul = mul_factor, +} + +function LM.factor(name) + local t = {name= name, value = ""} + return setmetatable(t, factor_mt) +end + +function LM.eval_test(...) + local inf = {np = select('#', ...)} + inf.class = {} + for k= 1, inf.np do + local v = select(k, ...) + inf.class[k] = (type(v) == 'number' and 1 or 0) + end + return inf +end + +function LM.eval_func(inf, pt, i, ...) + for k = 1, inf.np do + local x = select(k, ...) + local value = (inf.class[k] == 1 and x or x.value) + gdt.set(pt, i, k, value) + end +end + +LM.var_name = var_name + +local function expr_to_name(expr) + if type(expr) == 'table' then + return expr.name + else + local base = '(average)' + local minus = expr < 0 and '- ' or '' + if expr == 1 or expr == -1 then + return string.format("%s%s", minus, base) + else + return string.format("%s%s / %g", minus, base, math.abs(expr)) + end + end +end + +function LM.find_names(...) + local n = select("#", ...) + local names = {} + for k = 1, n do + local expr = select(k, ...) + names[k] = expr_to_name(expr) + end + return names +end + +return LM diff --git a/lua-gsl/lua-gsl.c b/lua-gsl/lua-gsl.c index 004dba16..7243295e 100644 --- a/lua-gsl/lua-gsl.c +++ b/lua-gsl/lua-gsl.c @@ -29,6 +29,13 @@ #include "lua-utils.h" #include "fatal.h" +#include "gdt/gdt_table.h" + +/* used to force the linker to link the gdt library. Otherwise it + * would be discarded as there are no other references to its functions. */ +extern gdt_table *(*_gdt_ref)(int nb_rows, int nb_columns, int nb_rows_alloc); +gdt_table *(*_gdt_ref)(int nb_rows, int nb_columns, int nb_rows_alloc) = gdt_table_new; + struct gsl_shell_state* global_state; void @@ -57,10 +57,14 @@ LIBS += -lsupc++ ifeq ($(HOST_SYS),Windows) DEFS += -DWIN32 EXE_EXT = .exe + DLL_EXT = .dll + LDFLAGS += -Wl,--export-all-symbols else EXE_EXT = + DLL_EXT = .so DEFS += -pthread LIBS += -pthread + LDFLAGS += -Wl,-E endif ifeq ($(strip $(DEBUG)), yes) diff --git a/matrix-quicksort.lua b/matrix-quicksort.lua new file mode 100644 index 00000000..111973ad --- /dev/null +++ b/matrix-quicksort.lua @@ -0,0 +1,31 @@ + +local function quicksort_array(m, f) + local t = m.data + + local function quicksort(start, endi) + if start >= endi then return end + local pivot = start + for i = start + 1, endi do + if f(t[i], t[pivot]) then + local temp = t[pivot + 1] + t[pivot + 1] = t[pivot] + if(i == pivot + 1) then + t[pivot] = temp + else + t[pivot] = t[i] + t[i] = temp + end + pivot = pivot + 1 + end + end + + quicksort(start, pivot - 1) + quicksort(pivot + 1, endi) + end + + local n, ncols = m:dim() + assert(ncols == 1, "expecting column matrix") + quicksort(0, n - 1) +end + +return quicksort_array diff --git a/matrix.lua b/matrix.lua index b911812b..5e5e3c8f 100644 --- a/matrix.lua +++ b/matrix.lua @@ -522,7 +522,7 @@ local function matrix_complex_unm(a) return m end -local function matrix_norm(m) +local function matrix_norm2(m) local r, c = matrix_dim(m) local tda = m.tda local ssq, idx = 0, 0 @@ -533,10 +533,14 @@ local function matrix_norm(m) end idx = idx + tda end - return sqrt(ssq) + return ssq end -local function matrix_complex_norm(m) +local function matrix_norm(m) + return sqrt(matrix_norm2(m)) +end + +local function matrix_complex_norm2(m) local r, c = matrix_dim(m) local tda = m.tda local ssq, idx = 0, 0 @@ -547,7 +551,11 @@ local function matrix_complex_norm(m) end idx = idx + 2*tda end - return sqrt(ssq) + return ssq +end + +local function matrix_complex_norm(m) + return sqrt(matrix_complex_norm2(m)) end complex = { @@ -556,6 +564,7 @@ complex = { real = complex_real, imag = complex_imag, abs = complex_abs, + norm = complex_abs, norm2 = complex_norm2, rect = cartesian, i = 1i, @@ -675,7 +684,9 @@ local matrix_methods = { set = matrix_set, copy = matrix_copy, norm = matrix_norm, + norm2 = matrix_norm2, slice = matrix_slice, + sort = require("matrix-quicksort"), show = matrix_display_gen(mat_real_get), } @@ -740,6 +751,7 @@ local matrix_complex_methods = { set = matrix_complex_set, copy = matrix_complex_copy, norm = matrix_complex_norm, + norm2 = matrix_complex_norm2, slice = matrix_complex_slice, show = matrix_display_gen(mat_complex_get), } diff --git a/monomial.lua b/monomial.lua new file mode 100644 index 00000000..d6ef769d --- /dev/null +++ b/monomial.lua @@ -0,0 +1,92 @@ +local function monomial_len(a)
+ return (#a - 1) / 2
+end
+
+local function mon_terms_iter(a, k)
+ k = k + 1
+ if 2*k + 1 <= #a then
+ return k, a[2*k], a[2*k+1]
+ end
+end
+
+local function mon_terms(a)
+ return mon_terms_iter, a, 0
+end
+
+local function mon_symbol(sym)
+ return {1, sym, 1}
+end
+
+local function monomial_set_term_pow(a, k, new_pow)
+ a[2*k+1] = new_pow
+end
+
+local function monomial_insert_term(a, k, sym, pow)
+ local n = monomial_len(a)
+ for k= n, k, -1 do
+ a[2*k+2] = a[2*k ]
+ a[2*k+3] = a[2*k+1]
+ end
+ a[2*k ] = sym
+ a[2*k + 1] = pow
+end
+
+local function monomial_mult_factor(a, sym, pow)
+ for k, a_sym, a_pow in mon_terms(a) do
+ if a_sym == sym then
+ monomial_set_term_pow(a, k, a_pow + pow)
+ return
+ end
+ if a_sym > sym then
+ monomial_insert_term(a, k, sym, pow)
+ return
+ end
+ end
+ local n = monomial_len(a)
+ monomial_insert_term(a, n + 1, sym, pow)
+end
+
+local function monomial_mult(a, b)
+ a[1] = a[1] * b[1]
+ for k, sym, pow in mon_terms(b) do
+ monomial_mult_factor(a, sym, pow)
+ end
+end
+
+local function monomial_power(m, n)
+ m[1] = m[1]^n
+ for k, sym, pow in mon_terms(m) do
+ monomial_set_term_pow(m, k, pow * n)
+ end
+end
+
+local function monomial_equal(a, b)
+ if a[1] ~= b[1] or #a ~= #b then return false end
+ for k, asym, apow in mon_terms(a) do
+ bsym, bpow = b[2*k], b[2*k+1]
+ if bsym ~= asym or bpow ~= apow then return false end
+ end
+ return true
+end
+
+local function combine_rec(a, k)
+ local n = monomial_len(a)
+ if k > n then return {{1}} end
+ local sym, pow = a[2*k], a[2*k+1]
+ local rls = combine_rec(a, k + 1)
+ local ls = {}
+ for p = 0, pow do
+ for _, mon in ipairs(rls) do
+ local xt = p > 0 and {1, sym, p} or {1}
+ monomial_mult(xt, mon)
+ ls[#ls+1] = xt
+ end
+ end
+ return ls
+end
+
+local function monomial_combine(a)
+ return combine_rec(a, 1)
+end
+
+return {symbol=mon_symbol, mult= monomial_mult, power=monomial_power, combine= monomial_combine, terms= mon_terms, equal=monomial_equal}
diff --git a/sigeb-doe-mbir.csv b/sigeb-doe-mbir.csv new file mode 100644 index 00000000..94195d29 --- /dev/null +++ b/sigeb-doe-mbir.csv @@ -0,0 +1,307 @@ +site,wafer,time_dep,geh4,b2h6,XCoord,YCoord,GAMMA,THICK_SIGE,CONC_BORE,DOSE_BORE,sigeb_th,sigeb_conc,dose,SiGe25p free carriers gamma,SiGe25p free carriers doping,model_quality +1,1,350,690,125,0,-0.001,1160.9441,101.6132,116.0944,11.7967,101.6132,116.0944,11.7967,1160.9441,257.0574,0.0123 +2,1,350,690,125,73.999,-14.8,1139.2299,128.2958,113.923,14.6158,128.2958,113.923,14.6158,1139.2299,198.4226,0.0129 +3,1,350,690,125,29.6,-74.001,1132.6603,110.6792,113.266,12.5362,110.6792,113.266,12.5362,1132.6603,227.417,0.0124 +4,1,350,690,125,-44.401,-59.199,1167.0649,114.8651,116.7065,13.4055,114.8651,116.7065,13.4055,1167.0649,225.321,0.0159 +5,1,350,690,125,-74.001,14.801,1154.0609,81.1815,115.4061,9.3688,81.1815,115.4061,9.3688,1154.0609,316.6042,0.012 +6,1,350,690,125,-29.599,74,1170.0858,116.0159,117.0086,13.5749,116.0159,117.0086,13.5749,1170.0858,223.2926,0.0151 +7,1,350,690,125,44.399,59.2,1195.4558,190.9536,119.5456,22.8277,190.9536,119.5456,22.8277,1195.4558,136.2262,0.0202 +8,1,350,690,125,118.4,-0.001,1213.585,132.6457,121.3585,16.0977,132.6457,121.3585,16.0977,1213.585,193.294,0.0186 +9,1,350,690,125,103.599,-74.001,1209.037,148.0181,120.9037,17.8959,148.0181,120.9037,17.8959,1209.037,168.344,0.0174 +10,1,350,690,125,44.398,-118.4,1203.9659,121.269,120.3966,14.6004,121.269,120.3966,14.6004,1203.9659,205.7172,0.0172 +11,1,350,690,125,-44.4,-118.4,1196.0825,148.2113,119.6083,17.7273,148.2113,119.6083,17.7273,1196.0825,166.7153,0.0159 +12,1,350,690,125,-103.6,-74,1228.8953,116.6782,122.8895,14.3385,116.6782,122.8895,14.3385,1228.8953,215.4175,0.0179 +13,1,350,690,125,-118.4,0,1225.613,132.3679,122.5613,16.2232,132.3679,122.5613,16.2232,1225.613,191.7461,0.0191 +14,1,350,690,125,-103.599,74,1191.651,134.1236,119.1651,15.9828,134.1236,119.1651,15.9828,1191.651,188.5197,0.0178 +15,1,350,690,125,-44.4,118.4,1182.6534,100.4732,118.2654,11.8825,100.4732,118.2654,11.8825,1182.6534,250.8498,0.0122 +16,1,350,690,125,44.399,118.4,1158.233,100.0726,115.8233,11.5907,100.0726,115.8233,11.5907,1158.233,254.0417,0.0136 +17,1,350,690,125,103.601,74,1191.0448,108.2786,119.1045,12.8965,108.2786,119.1045,12.8965,1191.0448,235.8914,0.0176 +1,2,425,560,125,0,-0.001,1340.9701,110.7836,134.097,14.8558,110.7836,134.097,14.8558,1340.9701,218.9478,0.0103 +2,2,425,560,125,74,-14.8,1352.7814,147.5634,135.2781,19.9621,147.5634,135.2781,19.9621,1352.7814,159.3164,0.0146 +3,2,425,560,125,29.6,-74.001,1398.4663,142.6645,139.8466,19.9512,142.6645,139.8466,19.9512,1398.4663,166.1914,0.0146 +4,2,425,560,125,-44.4,-59.198,1395.6664,129.766,139.5666,18.111,129.766,139.5666,18.111,1395.6664,182.9004,0.0153 +5,2,425,560,125,-74.001,14.801,1427.3025,113.0309,142.7303,16.1329,113.0309,142.7303,16.1329,1427.3025,215.4577,0.0135 +6,2,425,560,125,-29.599,74,1404.3782,125.8235,140.4378,17.6704,125.8235,140.4378,17.6704,1404.3782,191.9325,0.0128 +7,2,425,560,125,44.4,59.2,1320.8767,116.027,132.0877,15.3257,116.027,132.0877,15.3257,1320.8767,203.3011,0.0104 +8,2,425,560,125,118.401,-0.001,1442.5963,129.9383,144.2596,18.7449,129.9383,144.2596,18.7449,1442.5963,183.4069,0.0162 +9,2,425,560,125,103.601,-74.002,1403.6919,137.4036,140.3692,19.2872,137.4036,140.3692,19.2872,1403.6919,166.8992,0.0159 +10,2,425,560,125,44.399,-118.4,1419.2523,131.4971,141.9252,18.6628,131.4971,141.9252,18.6628,1419.2523,174.9044,0.0167 +11,2,425,560,125,-44.402,-118.4,1351.7634,126.853,135.1763,17.1475,126.853,135.1763,17.1475,1351.7634,175.2173,0.0131 +12,2,425,560,125,-103.6,-74,1420.8838,124.3073,142.0884,17.6626,124.3073,142.0884,17.6626,1420.8838,188.0764,0.0165 +13,2,425,560,125,-118.4,0.001,1392.4772,135.8725,139.2477,18.9199,135.8725,139.2477,18.9199,1392.4772,171.6227,0.0169 +14,2,425,560,125,-103.6,73.999,1360.2761,124.28,136.0276,16.9055,124.28,136.0276,16.9055,1360.2761,187.439,0.0162 +15,2,425,560,125,-44.4,118.4,1401.3322,139.4659,140.1332,19.5438,139.4659,140.1332,19.5438,1401.3322,169.9649,0.0164 +16,2,425,560,125,44.4,118.4,1391.1602,126.1553,139.116,17.5502,126.1553,139.116,17.5502,1391.1602,186.5518,0.015 +17,2,425,560,125,103.601,74,1410.959,120.8274,141.0959,17.0483,120.8274,141.0959,17.0483,1410.959,193.4996,0.0111 +1,3,500,690,125,-0.001,-0.001,1098.6635,148.778,109.8663,16.3457,148.778,109.8663,16.3457,1098.6635,257.4893,0.0095 +2,3,500,690,125,73.999,-14.8,1050.8905,134.9192,105.0891,14.1785,134.9192,105.0891,14.1785,1050.8905,273.244,0.007 +3,3,500,690,125,29.601,-74.002,1095.5502,139.4366,109.555,15.276,139.4366,109.555,15.276,1095.5502,265.6098,0.0086 +4,3,500,690,125,-44.4,-59.198,1078.2655,132.1626,107.8265,14.2506,132.1626,107.8265,14.2506,1078.2655,281.2629,0.0087 +5,3,500,690,125,-74.002,14.801,1125.2391,147.1914,112.5239,16.5626,147.1914,112.5239,16.5626,1125.2391,259.057,0.0101 +6,3,500,690,125,-29.599,74,1111.0837,158.5089,111.1084,17.6117,158.5089,111.1084,17.6117,1111.0837,239.5477,0.01 +7,3,500,690,125,44.401,59.2,1118.9916,151.8772,111.8992,16.9949,151.8772,111.8992,16.9949,1118.9916,250.988,0.0093 +8,3,500,690,125,118.401,-0.001,1126.8556,147.3221,112.6856,16.6011,147.3221,112.6856,16.6011,1126.8556,249.9522,0.0113 +9,3,500,690,125,103.6,-74.001,1100.6057,131.7269,110.0606,14.4979,131.7269,110.0606,14.4979,1100.6057,270.5363,0.0082 +10,3,500,690,125,44.398,-118.401,1138.3494,167.6986,113.8349,19.09,167.6986,113.8349,19.09,1138.3494,215.0619,0.0123 +11,3,500,690,125,-44.401,-118.4,1075.0031,144.5505,107.5003,15.5392,144.5505,107.5003,15.5392,1075.0031,248.1641,0.0097 +12,3,500,690,125,-103.601,-73.999,1123.7715,137.0708,112.3772,15.4036,137.0708,112.3772,15.4036,1123.7715,266.8614,0.0104 +13,3,500,690,125,-118.401,0,1102.6298,133.2532,110.263,14.6929,133.2532,110.263,14.6929,1102.6298,276.3846,0.0094 +14,3,500,690,125,-103.601,73.999,1103.1072,195.6354,110.3107,21.5807,195.6354,110.3107,21.5807,1103.1072,189.041,0.0117 +15,3,500,690,125,-44.4,118.4,1091.3899,128.5676,109.139,14.0317,128.5676,109.139,14.0317,1091.3899,288.2108,0.0078 +16,3,500,690,125,44.4,118.4,1104.0432,154.7197,110.4043,17.0817,154.7197,110.4043,17.0817,1104.0432,238.2348,0.0104 +17,3,500,690,125,103.601,74,1133.6483,147.5149,113.3648,16.723,147.5149,113.3648,16.723,1133.6483,248.7319,0.0118 +1,4,425,820,125,-0.001,0,959.3732,147.3553,95.9373,14.1369,147.3553,95.9373,14.1369,959.3732,288.3061,0.0076 +2,4,425,820,125,74,-14.8,930.3077,151.7954,93.0308,14.1216,151.7954,93.0308,14.1216,930.3077,272.4224,0.0064 +3,4,425,820,125,29.599,-74.001,945.3029,140.1995,94.5303,13.2531,140.1995,94.5303,13.2531,945.3029,294.1247,0.0058 +4,4,425,820,125,-44.402,-59.199,946.8767,134.2821,94.6877,12.7149,134.2821,94.6877,12.7149,946.8767,307.701,0.0059 +5,4,425,820,125,-74.002,14.801,982.3398,153.8791,98.234,15.1162,153.8791,98.234,15.1162,982.3398,274.8448,0.0086 +6,4,425,820,125,-29.598,74,954.0851,152.0713,95.4085,14.5089,152.0713,95.4085,14.5089,954.0851,276.77,0.0078 +7,4,425,820,125,44.401,59.2,953.4825,146.4125,95.3483,13.9602,146.4125,95.3483,13.9602,953.4825,288.373,0.0074 +8,4,425,820,125,118.4,-0.001,957.3687,126.3103,95.7369,12.0925,126.3103,95.7369,12.0925,957.3687,320.8157,0.0074 +9,4,425,820,125,103.599,-74.002,974.9827,150.7522,97.4983,14.6981,150.7522,97.4983,14.6981,974.9827,263.0969,0.0081 +10,4,425,820,125,44.398,-118.399,945.7808,119.4648,94.5781,11.2988,119.4648,94.5781,11.2988,945.7808,330.1664,0.0059 +11,4,425,820,125,-44.401,-118.4,956.6352,160.8106,95.6635,15.3837,160.8106,95.6635,15.3837,956.6352,246.8589,0.0086 +12,4,425,820,125,-103.601,-74.001,984.6396,170.9414,98.464,16.8316,170.9414,98.464,16.8316,984.6396,237.2368,0.0095 +13,4,425,820,125,-118.401,0,978.1149,166.0597,97.8115,16.2425,166.0597,97.8115,16.2425,978.1149,246.8126,0.009 +14,4,425,820,125,-103.601,74,939.1465,131.7551,93.9146,12.3737,131.7551,93.9146,12.3737,939.1465,307.3555,0.0067 +15,4,425,820,125,-44.401,118.4,966.8745,159.8504,96.6875,15.4555,159.8504,96.6875,15.4555,966.8745,256.696,0.0087 +16,4,425,820,125,44.4,118.4,952.5738,137.4299,95.2574,13.0912,137.4299,95.2574,13.0912,952.5738,295.1786,0.0074 +17,4,425,820,125,103.602,73.999,963.6486,131.8012,96.3649,12.701,131.8012,96.3649,12.701,963.6486,306.505,0.008 +1,5,350,560,150,0,-0.001,1522.4639,121.9129,152.2464,18.5608,121.9129,152.2464,18.5608,1522.4639,226.2355,0.0094 +2,5,350,560,150,74,-14.8,1441.3958,119.4457,144.1396,17.2169,119.4457,144.1396,17.2169,1441.3958,219.6275,0.0098 +3,5,350,560,150,29.6,-74.001,1432.8378,97.5556,143.2838,13.9781,97.5556,143.2838,13.9781,1432.8378,265.9988,0.0087 +4,5,350,560,150,-44.402,-59.199,1440.3071,95.9859,144.0307,13.8249,95.9859,144.0307,13.8249,1440.3071,269.2918,0.0084 +5,5,350,560,150,-74.002,14.801,1533.3241,99.9684,153.3324,15.3284,99.9684,153.3324,15.3284,1533.3241,270.5641,0.0094 +6,5,350,560,150,-29.599,74,1489.0645,106.0987,148.9064,15.7988,106.0987,148.9064,15.7988,1489.0645,251.6372,0.0083 +7,5,350,560,150,44.4,59.2,1529.0575,117.6483,152.9057,17.9891,117.6483,152.9057,17.9891,1529.0575,233.5129,0.0127 +8,5,350,560,150,118.4,-0.001,1546.8643,126.3409,154.6864,19.5432,126.3409,154.6864,19.5432,1546.8643,210.2897,0.0133 +9,5,350,560,150,103.599,-74.001,1424.3513,99.3836,142.4351,14.1557,99.3836,142.4351,14.1557,1424.3513,250.6941,0.01 +10,5,350,560,150,44.399,-118.4,1508.7517,120.5587,150.8752,18.1893,120.5587,150.8752,18.1893,1508.7517,213.4964,0.0132 +11,5,350,560,150,-44.4,-118.4,1420.1658,110.0666,142.0166,15.6313,110.0666,142.0166,15.6313,1420.1658,224.7218,0.0097 +12,5,350,560,150,-103.6,-74.001,1469.0427,92.9494,146.9043,13.6547,92.9494,146.9043,13.6547,1469.0427,274.7619,0.0115 +13,5,350,560,150,-118.4,0,1537.1573,116.595,153.7157,17.9225,116.595,153.7157,17.9225,1537.1573,224.078,0.0108 +14,5,350,560,150,-103.6,74,1425.4626,101.3291,142.5463,14.4441,101.3291,142.5463,14.4441,1425.4626,252.0004,0.0094 +15,5,350,560,150,-44.4,118.4,1481.8595,115.075,148.1859,17.0525,115.075,148.1859,17.0525,1481.8595,228.1937,0.0111 +16,5,350,560,150,44.4,118.4,1496.2394,127.9479,149.6239,19.1441,127.9479,149.6239,19.1441,1496.2394,203.3417,0.0118 +17,5,350,560,150,103.602,73.998,1455.1559,86.3596,145.5156,12.5667,86.3596,145.5156,12.5667,1455.1559,298.9005,0.0096 +1,6,350,820,150,0,0,1040.9357,134.3012,104.0936,13.9799,134.3012,104.0936,13.9799,1040.9357,316.8077,0.0084 +2,6,350,820,150,74,-14.801,1011.8945,134.42,101.1894,13.6019,134.42,101.1894,13.6019,1011.8945,307.2251,0.0064 +3,6,350,820,150,29.601,-74,1037.3596,132.181,103.736,13.7119,132.181,103.736,13.7119,1037.3596,314.3874,0.0072 +4,6,350,820,150,-44.401,-59.199,1056.7278,148.2117,105.6728,15.6619,148.2117,105.6728,15.6619,1056.7278,282.0483,0.0087 +5,6,350,820,150,-74.002,14.801,1074.7209,163.7163,107.4721,17.5949,163.7163,107.4721,17.5949,1074.7209,259.131,0.0105 +6,6,350,820,150,-29.599,74,1027.4191,131.5946,102.7419,13.5203,131.5946,102.7419,13.5203,1027.4191,319.5789,0.0078 +7,6,350,820,150,44.401,59.2,1048.8521,141.1099,104.8852,14.8003,141.1099,104.8852,14.8003,1048.8521,299.573,0.0084 +8,6,350,820,150,118.4,0,1029.912,117.5913,102.9912,12.1109,117.5913,102.9912,12.1109,1029.912,345.8013,0.0082 +9,6,350,820,150,103.599,-74.001,1023.3384,123.7673,102.3338,12.6656,123.7673,102.3338,12.6656,1023.3384,322.0461,0.008 +10,6,350,820,150,44.399,-118.401,1036.6729,127.8704,103.6673,13.256,127.8704,103.6673,13.256,1036.6729,311.967,0.0089 +11,6,350,820,150,-44.4,-118.4,1026.6694,135.5508,102.6669,13.9166,135.5508,102.6669,13.9166,1026.6694,293.6286,0.008 +12,6,350,820,150,-103.601,-74,1044.5675,135.6537,104.4567,14.1699,135.6537,104.4567,14.1699,1044.5675,299.7883,0.0096 +13,6,350,820,150,-118.4,0.001,1016.7437,116.7579,101.6744,11.8713,116.7579,101.6744,11.8713,1016.7437,347.7873,0.0073 +14,6,350,820,150,-103.598,74.001,1043.826,139.3021,104.3826,14.5407,139.3021,104.3826,14.5407,1043.826,292.2158,0.0077 +15,6,350,820,150,-44.4,118.4,1042.925,141.859,104.2925,14.7948,141.859,104.2925,14.7948,1042.925,290.3291,0.0095 +16,6,350,820,150,44.401,118.4,1032.2683,132.91,103.2268,13.7199,132.91,103.2268,13.7199,1032.2683,306.5731,0.0081 +17,6,350,820,150,103.601,74,1072.3485,156.039,107.2349,16.7328,156.039,107.2349,16.7328,1072.3485,261.7688,0.0106 +1,7,425,690,150,0,-0.001,1139.9686,123.1208,113.9969,14.0354,123.1208,113.9969,14.0354,1139.9686,333.6,0.0064 +2,7,425,690,150,74,-14.8,1134.7286,143.0049,113.4729,16.2272,143.0049,113.4729,16.2272,1134.7286,279.5648,0.0071 +3,7,425,690,150,29.6,-74.001,1118.854,124.5106,111.8854,13.9309,124.5106,111.8854,13.9309,1118.854,317.8181,0.0059 +4,7,425,690,150,-44.402,-59.199,1177.7003,172.041,117.77,20.2613,172.041,117.77,20.2613,1177.7003,234.195,0.009 +5,7,425,690,150,-74.001,14.802,1148.4651,119.9049,114.8465,13.7707,119.9049,114.8465,13.7707,1148.4651,340.2529,0.0068 +6,7,425,690,150,-29.6,73.999,1167.1372,144.0397,116.7137,16.8114,144.0397,116.7137,16.8114,1167.1372,284.5324,0.0073 +7,7,425,690,150,44.4,59.2,1156.9921,128.1438,115.6992,14.8261,128.1438,115.6992,14.8261,1156.9921,319.0108,0.0073 +8,7,425,690,150,118.4,-0.002,1176.5168,147.7013,117.6517,17.3773,147.7013,117.6517,17.3773,1176.5168,267.9968,0.0094 +9,7,425,690,150,103.599,-74.001,1155.1473,136.2332,115.5147,15.7369,136.2332,115.5147,15.7369,1155.1473,282.0941,0.0085 +10,7,425,690,150,44.398,-118.402,1161.446,135.3569,116.1446,15.721,135.3569,116.1446,15.721,1161.446,285.5377,0.0095 +11,7,425,690,150,-44.401,-118.4,1150.6721,151.5359,115.0672,17.4368,151.5359,115.0672,17.4368,1150.6721,252.7599,0.0089 +12,7,425,690,150,-103.601,-74,1134.3208,115.6318,113.4321,13.1164,115.6318,113.4321,13.1164,1134.3208,336.1958,0.0074 +13,7,425,690,150,-118.4,0.001,1146.0645,126.7663,114.6064,14.5282,126.7663,114.6064,14.5282,1146.0645,312.782,0.0081 +14,7,425,690,150,-103.599,74,1161.9893,173.0368,116.1989,20.1067,173.0368,116.1989,20.1067,1161.9893,230.2462,0.0094 +15,7,425,690,150,-44.4,118.4,1123.3571,117.7319,112.3357,13.2255,117.7319,112.3357,13.2255,1123.3571,338.3218,0.0064 +16,7,425,690,150,44.401,118.4,1160.8114,148.623,116.0811,17.2523,148.623,116.0811,17.2523,1160.8114,268.2859,0.0086 +17,7,425,690,150,103.601,74,1118.2275,108.3438,111.8227,12.1153,108.3438,111.8227,12.1153,1118.2275,359.3965,0.006 +1,8,425,690,150,0,-0.001,1157.6516,131.3165,115.7652,15.2019,131.3165,115.7652,15.2019,1157.6516,314.8207,0.006 +2,8,425,690,150,74,-14.801,1107.1106,134.9486,110.7111,14.9403,134.9486,110.7111,14.9403,1107.1106,294.2646,0.006 +3,8,425,690,150,29.599,-74.001,1135.3351,128.832,113.5335,14.6267,128.832,113.5335,14.6267,1135.3351,309.9772,0.0067 +4,8,425,690,150,-44.4,-59.199,1120.0377,118.227,112.0038,13.2419,118.227,112.0038,13.2419,1120.0377,338.45,0.0058 +5,8,425,690,150,-74.002,14.801,1179.2781,149.6723,117.9278,17.6505,149.6723,117.9278,17.6505,1179.2781,275.618,0.0092 +6,8,425,690,150,-29.598,74,1119.655,125.3812,111.9655,14.0384,125.3812,111.9655,14.0384,1119.655,323.7866,0.0063 +7,8,425,690,150,44.4,59.2,1155.7062,133.2421,115.5706,15.3989,133.2421,115.5706,15.3989,1155.7062,308.0564,0.0072 +8,8,425,690,150,118.4,-0.002,1154.4113,121.1354,115.4411,13.984,121.1354,115.4411,13.984,1154.4113,325.6235,0.0076 +9,8,425,690,150,103.601,-74.002,1151.8226,139.1282,115.1823,16.0251,139.1282,115.1823,16.0251,1151.8226,276.7519,0.0083 +10,8,425,690,150,44.399,-118.4,1117.2654,118.6821,111.7265,13.2599,118.6821,111.7265,13.2599,1117.2654,323.0569,0.0071 +11,8,425,690,150,-44.4,-118.4,1087.4218,128.832,108.7422,14.0095,128.832,108.7422,14.0095,1087.4218,295.9807,0.0056 +12,8,425,690,150,-103.6,-74,1162.0498,131.9962,116.205,15.3386,131.9962,116.205,15.3386,1162.0498,297.6368,0.0079 +13,8,425,690,150,-118.4,0,1150.3326,138.4217,115.0333,15.9231,138.4217,115.0333,15.9231,1150.3326,287.6591,0.0073 +14,8,425,690,150,-103.599,74,1129.1129,133.5416,112.9113,15.0784,133.5416,112.9113,15.0784,1129.1129,297.6233,0.007 +15,8,425,690,150,-44.4,118.4,1133.5565,131.5212,113.3557,14.9087,131.5212,113.3557,14.9087,1133.5565,303.6555,0.0073 +16,8,425,690,150,44.401,118.4,1126.9139,128.71,112.6914,14.5045,128.71,112.6914,14.5045,1126.9139,305.3612,0.0066 +17,8,425,690,150,103.6,74,1148.5432,135.9828,114.8543,15.6182,135.9828,114.8543,15.6182,1148.5432,289.6769,0.0071 +1,9,500,560,150,0,-0.002,1398.2841,119.2919,139.8284,16.6804,119.2919,139.8284,16.6804,1398.2841,333.7281,0.0049 +2,9,500,560,150,74.001,-14.8,1381.7664,132.0324,138.1766,18.2438,132.0324,138.1766,18.2438,1381.7664,291.6813,0.0054 +3,9,500,560,150,29.599,-74.001,1372.9491,121.8222,137.2949,16.7256,121.8222,137.2949,16.7256,1372.9491,312.6319,0.0045 +4,9,500,560,150,-44.4,-59.198,1412.8303,126.2842,141.283,17.8418,126.2842,141.283,17.8418,1412.8303,307.8591,0.0057 +5,9,500,560,150,-74.002,14.801,1440.0875,129.6621,144.0088,18.6725,129.6621,144.0088,18.6725,1440.0875,307.3572,0.0067 +6,9,500,560,150,-29.599,74.001,1381.9885,122.263,138.1989,16.8966,122.263,138.1989,16.8966,1381.9885,320.9442,0.0056 +7,9,500,560,150,44.4,59.201,1415.1222,127.5906,141.5122,18.0556,127.5906,141.5122,18.0556,1415.1222,310.9431,0.0047 +8,9,500,560,150,118.4,-0.001,1437.807,136.5523,143.7807,19.6336,136.5523,143.7807,19.6336,1437.807,283.1598,0.0072 +9,9,500,560,150,103.6,-74.001,1402.5479,131.1021,140.2548,18.3877,131.1021,140.2548,18.3877,1402.5479,285.1945,0.006 +10,9,500,560,150,44.399,-118.402,1421.7739,126.5238,142.1774,17.9888,126.5238,142.1774,17.9888,1421.7739,296.0705,0.0057 +11,9,500,560,150,-44.402,-118.4,1390.0883,139.7046,139.0088,19.4202,139.7046,139.0088,19.4202,1390.0883,264.9912,0.0065 +12,9,500,560,150,-103.601,-74,1420.3638,126.3209,142.0364,17.9422,126.3209,142.0364,17.9422,1420.3638,299.4482,0.0067 +13,9,500,560,150,-118.401,0,1412.4456,123.5645,141.2446,17.4528,123.5645,141.2446,17.4528,1412.4456,310.8511,0.0061 +14,9,500,560,150,-103.601,73.999,1348.3495,119.8113,134.8349,16.1547,119.8113,134.8349,16.1547,1348.3495,317.4254,0.0045 +15,9,500,560,150,-44.4,118.4,1373.5247,117.95,137.3525,16.2007,117.95,137.3525,16.2007,1373.5247,326.0612,0.0057 +16,9,500,560,150,44.4,118.4,1365.3591,111.5789,136.5359,15.2345,111.5789,136.5359,15.2345,1365.3591,341.6983,0.0054 +17,9,500,560,150,103.601,74,1409.9067,124.4067,140.9907,17.5402,124.4067,140.9907,17.5402,1409.9067,310.086,0.0071 +1,10,500,820,150,0,0,934.3936,203.8473,93.4394,19.0474,203.8473,93.4394,19.0474,934.3936,302.392,0.0043 +2,10,500,820,150,74,-14.801,911.2024,197.9812,91.1202,18.0401,197.9812,91.1202,18.0401,911.2024,303.6357,0.0036 +3,10,500,820,150,29.6,-74.001,905.6408,188.4489,90.5641,17.0667,188.4489,90.5641,17.0667,905.6408,316.9743,0.0027 +4,10,500,820,150,-44.401,-59.199,924.2469,191.4788,92.4247,17.6974,191.4788,92.4247,17.6974,924.2469,314.4996,0.0038 +5,10,500,820,150,-74.002,14.801,937.0928,188.0172,93.7093,17.619,188.0172,93.7093,17.619,937.0928,324.6773,0.004 +6,10,500,820,150,-29.599,73.998,926.4006,194.7829,92.6401,18.0447,194.7829,92.6401,18.0447,926.4006,313.6027,0.0036 +7,10,500,820,150,44.401,59.2,915.2459,186.4029,91.5246,17.0604,186.4029,91.5246,17.0604,915.2459,327.4021,0.0032 +8,10,500,820,150,118.4,0,935.3946,198.4357,93.5395,18.5616,198.4357,93.5395,18.5616,935.3946,299.1221,0.0046 +9,10,500,820,150,103.599,-74.001,922.5721,188.9889,92.2572,17.4356,188.9889,92.2572,17.4356,922.5721,307.8723,0.004 +10,10,500,820,150,44.399,-118.4,922.1081,179.5398,92.2108,16.5555,179.5398,92.2108,16.5555,922.1081,322.9603,0.0037 +11,10,500,820,150,-44.401,-118.401,915.8755,192.1954,91.5875,17.6027,192.1954,91.5875,17.6027,915.8755,299.7164,0.0039 +12,10,500,820,150,-103.6,-74.002,924.4468,175.3309,92.4447,16.2084,175.3309,92.4447,16.2084,924.4468,330.6322,0.0038 +13,10,500,820,150,-118.402,0,921.4701,183.2796,92.147,16.8887,183.2796,92.147,16.8887,921.4701,321.3475,0.0037 +14,10,500,820,150,-103.598,73.999,922.6891,191.2822,92.2689,17.6494,191.2822,92.2689,17.6494,922.6891,307.1461,0.0041 +15,10,500,820,150,-44.4,118.4,913.4069,173.6426,91.3407,15.8606,173.6426,91.3407,15.8606,913.4069,341.7005,0.0036 +16,10,500,820,150,44.4,118.4,905.8611,175.2945,90.5861,15.8793,175.2945,90.5861,15.8793,905.8611,338.8118,0.0031 +17,10,500,820,150,103.601,74,913.1182,167.2369,91.3118,15.2707,167.2369,91.3118,15.2707,913.1182,352.3076,0.0033 +1,11,425,560,175,0,-0.001,1577.2516,115.5139,157.7252,18.2194,115.5139,157.7252,18.2194,1577.2516,376.1414,0.005 +2,11,425,560,175,74,-14.802,1576.9465,141.4918,157.6946,22.3125,141.4918,157.6946,22.3125,1576.9465,298.2518,0.0058 +3,11,425,560,175,29.6,-74,1576.5328,119.8478,157.6533,18.8944,119.8478,157.6533,18.8944,1576.5328,352.0585,0.0057 +4,11,425,560,175,-44.4,-59.2,1590.7429,121.8368,159.0743,19.3811,121.8368,159.0743,19.3811,1590.7429,347.3639,0.0058 +5,11,425,560,175,-74.002,14.801,1539.521,91.7546,153.9521,14.1258,91.7546,153.9521,14.1258,1539.521,459.3864,0.005 +6,11,425,560,175,-29.599,74,1551.4679,104.2055,155.1468,16.1672,104.2055,155.1468,16.1672,1551.4679,409.2702,0.0046 +7,11,425,560,175,44.4,59.198,1559.7476,96.9797,155.9748,15.1264,96.9797,155.9748,15.1264,1559.7476,442.5668,0.0052 +8,11,425,560,175,118.4,-0.002,1559.1539,107.5377,155.9154,16.7668,107.5377,155.9154,16.7668,1559.1539,391.7175,0.0057 +9,11,425,560,175,103.599,-74.001,1532.7208,110.2128,153.2721,16.8925,110.2128,153.2721,16.8925,1532.7208,370.8411,0.0059 +10,11,425,560,175,44.399,-118.4,1543.5431,110.0292,154.3543,16.9835,110.0292,154.3543,16.9835,1543.5431,371.5874,0.0067 +11,11,425,560,175,-44.401,-118.401,1496.551,107.9053,149.6551,16.1486,107.9053,149.6551,16.1486,1496.551,371.9031,0.0062 +12,11,425,560,175,-103.601,-74,1528.3134,89.6321,152.8313,13.6986,89.6321,152.8313,13.6986,1528.3134,454.0893,0.0056 +13,11,425,560,175,-118.4,0,1594.9004,142.0633,159.49,22.6577,142.0633,159.49,22.6577,1594.9004,294.3279,0.0077 +14,11,425,560,175,-103.6,74,1506.0541,99.4095,150.6054,14.9716,99.4095,150.6054,14.9716,1506.0541,413.524,0.005 +15,11,425,560,175,-44.4,118.401,1533.2604,95.1805,153.326,14.5936,95.1805,153.326,14.5936,1533.2604,440.0305,0.0052 +16,11,425,560,175,44.4,118.4,1587.3641,136.5686,158.7364,21.6784,136.5686,158.7364,21.6784,1587.3641,309.0923,0.0068 +17,11,425,560,175,103.602,73.999,1529.3723,96.8544,152.9372,14.8126,96.8544,152.9372,14.8126,1529.3723,427.8804,0.0039 +1,12,350,690,175,0,0,1262.6829,128.6814,126.2683,16.2484,128.6814,126.2683,16.2484,1262.6829,327.4826,0.0075 +2,12,350,690,175,74,-14.801,1225.7365,124.1813,122.5736,15.2214,124.1813,122.5736,15.2214,1225.7365,327.6692,0.0064 +3,12,350,690,175,29.6,-74.001,1255.9065,124.8767,125.5906,15.6834,124.8767,125.5906,15.6834,1255.9065,327.159,0.0077 +4,12,350,690,175,-44.401,-59.199,1243.5211,110.5973,124.3521,13.753,110.5973,124.3521,13.753,1243.5211,367.7591,0.0073 +5,12,350,690,175,-74.001,14.801,1280.6741,115.9303,128.0674,14.8469,115.9303,128.0674,14.8469,1280.6741,360.5648,0.0079 +6,12,350,690,175,-29.599,74,1254.269,125.2864,125.4269,15.7143,125.2864,125.4269,15.7143,1254.269,332.1158,0.0084 +7,12,350,690,175,44.4,59.2,1250.984,115.3199,125.0984,14.4263,115.3199,125.0984,14.4263,1250.984,360.2453,0.0067 +8,12,350,690,175,118.4,-0.001,1276.1816,141.6809,127.6182,18.0811,141.6809,127.6182,18.0811,1276.1816,288.0168,0.0098 +9,12,350,690,175,103.601,-74.001,1249.4902,129.925,124.949,16.234,129.925,124.949,16.234,1249.4902,304.6896,0.0086 +10,12,350,690,175,44.399,-118.4,1235.246,105.5023,123.5246,13.0321,105.5023,123.5246,13.0321,1235.246,371.9051,0.0075 +11,12,350,690,175,-44.401,-118.399,1231.3326,122.8381,123.1333,15.1255,122.8381,123.1333,15.1255,1231.3326,316.9024,0.0082 +12,12,350,690,175,-103.6,-74,1265.4224,130.389,126.5422,16.4997,130.389,126.5422,16.4997,1265.4224,306.6324,0.01 +13,12,350,690,175,-118.4,-0.001,1247.0762,115.9334,124.7076,14.4578,115.9334,124.7076,14.4578,1247.0762,348.2094,0.0087 +14,12,350,690,175,-103.601,74.001,1223.8086,114.607,122.3809,14.0257,114.607,122.3809,14.0257,1223.8086,351.5815,0.0069 +15,12,350,690,175,-44.401,118.4,1211.6361,103.4511,121.1636,12.5345,103.4511,121.1636,12.5345,1211.6361,392.5425,0.0075 +16,12,350,690,175,44.4,118.4,1203.1277,103.4183,120.3128,12.4425,103.4183,120.3128,12.4425,1203.1277,388.8979,0.0066 +17,12,350,690,175,103.603,74,1275.9834,124.0386,127.5983,15.8271,124.0386,127.5983,15.8271,1275.9834,328.2786,0.008 +1,13,425,820,175,0,-0.001,1026.9851,187.2942,102.6985,19.2348,187.2942,102.6985,19.2348,1026.9851,328.9004,0.0048 +2,13,425,820,175,74.001,-14.8,995.9362,178.6365,99.5936,17.7911,178.6365,99.5936,17.7911,995.9362,334.2852,0.0034 +3,13,425,820,175,29.599,-74.002,1009.9288,176.3346,100.9929,17.8085,176.3346,100.9929,17.8085,1009.9288,340.7504,0.004 +4,13,425,820,175,-44.402,-59.198,1010.898,172.2551,101.0898,17.4132,172.2551,101.0898,17.4132,1010.898,348.0244,0.0037 +5,13,425,820,175,-74.002,14.801,1025.9451,170.7877,102.5945,17.5219,170.7877,102.5945,17.5219,1025.9451,357.3063,0.0046 +6,13,425,820,175,-29.599,74,1017.6483,177.3801,101.7648,18.0511,177.3801,101.7648,18.0511,1017.6483,343.2542,0.0046 +7,13,425,820,175,44.401,59.2,1027.6479,184.5124,102.7648,18.9614,184.5124,102.7648,18.9614,1027.6479,331.1529,0.0049 +8,13,425,820,175,118.4,-0.001,1033.7094,187.612,103.3709,19.3936,187.612,103.3709,19.3936,1033.7094,316.7488,0.0056 +9,13,425,820,175,103.599,-74.002,1023.3242,189.8949,102.3324,19.4324,189.8949,102.3324,19.4324,1023.3242,309.2833,0.0053 +10,13,425,820,175,44.398,-118.4,1006.0446,167.8854,100.6045,16.89,167.8854,100.6045,16.89,1006.0446,346.5529,0.004 +11,13,425,820,175,-44.401,-118.399,983.3046,170.634,98.3305,16.7785,170.634,98.3305,16.7785,983.3046,337.0011,0.0036 +12,13,425,820,175,-103.601,-74.001,1004.5849,164.7505,100.4585,16.5506,164.7505,100.4585,16.5506,1004.5849,353.922,0.0044 +13,13,425,820,175,-118.4,0,1001.4636,175.1772,100.1464,17.5434,175.1772,100.1464,17.5434,1001.4636,333.5986,0.0037 +14,13,425,820,175,-103.601,74,995.1066,173.1695,99.5107,17.2322,173.1695,99.5107,17.2322,995.1066,338.2366,0.0042 +15,13,425,820,175,-44.4,118.4,1011.2062,169.9928,101.1206,17.1898,169.9928,101.1206,17.1898,1011.2062,345.9093,0.0038 +16,13,425,820,175,44.4,118.4,1012.6649,167.8883,101.2665,17.0015,167.8883,101.2665,17.0015,1012.6649,349.3786,0.0036 +17,13,425,820,175,103.602,74,1006.1393,163.6858,100.6139,16.4691,163.6858,100.6139,16.4691,1006.1393,358.2688,0.0042 +1,14,500,690,175,0,-0.001,1200.2115,181.4321,120.0212,21.7757,181.4321,120.0212,21.7757,1200.2115,335.1192,0.0046 +2,14,500,690,175,74.001,-14.8,1175.4667,185.3515,117.5467,21.7875,185.3515,117.5467,21.7875,1175.4667,319.2879,0.0046 +3,14,500,690,175,29.6,-74.001,1187.8223,178.9529,118.7822,21.2564,178.9529,118.7822,21.2564,1187.8223,330.7546,0.0051 +4,14,500,690,175,-44.4,-59.199,1163.1127,166.805,116.3113,19.4013,166.805,116.3113,19.4013,1163.1127,351.8608,0.0039 +5,14,500,690,175,-74.002,14.801,1185.476,161.8775,118.5476,19.1902,161.8775,118.5476,19.1902,1185.476,370.9543,0.0048 +6,14,500,690,175,-29.599,74.001,1157.6405,166.9275,115.764,19.3242,166.9275,115.764,19.3242,1157.6405,356.915,0.0038 +7,14,500,690,175,44.401,59.2,1195.1595,174.6315,119.516,20.8713,174.6315,119.516,20.8713,1195.1595,346.3336,0.0049 +8,14,500,690,175,118.4,0,1178.6151,158.5145,117.8615,18.6828,158.5145,117.8615,18.6828,1178.6151,367.7084,0.0047 +9,14,500,690,175,103.599,-74.001,1151.3474,158.624,115.1348,18.2631,158.624,115.1348,18.2631,1151.3474,359.2731,0.0041 +10,14,500,690,175,44.399,-118.4,1181.156,178.9433,118.1156,21.136,178.9433,118.1156,21.136,1181.156,321.738,0.0056 +11,14,500,690,175,-44.401,-118.399,1173.3024,184.8949,117.3302,21.6938,184.8949,117.3302,21.6938,1173.3024,307.3172,0.0053 +12,14,500,690,175,-103.599,-74,1189.1587,175.8474,118.9159,20.911,175.8474,118.9159,20.911,1189.1587,327.4549,0.0057 +13,14,500,690,175,-118.402,0,1167.9316,165.323,116.7932,19.3086,165.323,116.7932,19.3086,1167.9316,350.5558,0.0041 +14,14,500,690,175,-103.598,74,1157.9685,170.4319,115.7969,19.7355,170.4319,115.7969,19.7355,1157.9685,340.5424,0.0044 +15,14,500,690,175,-44.4,118.4,1181.1707,171.7384,118.1171,20.2852,171.7384,118.1171,20.2852,1181.1707,341.8434,0.0048 +16,14,500,690,175,44.4,118.4,1154.916,158.8994,115.4916,18.3515,158.8994,115.4916,18.3515,1154.916,364.8066,0.0045 +17,14,500,690,175,103.601,74,1185.6005,165.8131,118.56,19.6588,165.8131,118.56,19.6588,1185.6005,352.3506,0.0048 +1,15,425,690,150,0,-0.001,1180.0281,118.5564,118.0028,13.99,118.5564,118.0028,13.99,1180.0281,344.8683,0.0071 +2,15,425,690,150,74,-14.801,1213.5027,179.9232,121.3503,21.8337,179.9232,121.3503,21.8337,1213.5027,222.1038,0.0106 +3,15,425,690,150,29.601,-74.001,1204.845,128.9742,120.4845,15.5394,128.9742,120.4845,15.5394,1204.845,310.7895,0.0095 +4,15,425,690,150,-44.402,-59.199,1205.4177,120.5808,120.5418,14.535,120.5808,120.5418,14.535,1205.4177,332.9639,0.0089 +5,15,425,690,150,-74.001,14.801,1223.9078,114.6912,122.3908,14.0371,114.6912,122.3908,14.0371,1223.9078,358.4737,0.0101 +6,15,425,690,150,-29.599,74,1209.4362,134.9985,120.9436,16.3272,134.9985,120.9436,16.3272,1209.4362,303.9903,0.0107 +7,15,425,690,150,44.4,59.201,1228.4595,129.7705,122.846,15.9418,129.7705,122.846,15.9418,1228.4595,318.1927,0.0105 +8,15,425,690,150,118.4,-0.001,1208.3083,106.9388,120.8308,12.9215,106.9388,120.8308,12.9215,1208.3083,368.3277,0.0098 +9,15,425,690,150,103.599,-74.001,1162.2089,105.6266,116.2209,12.276,105.6266,116.2209,12.276,1162.2089,361.7582,0.0087 +10,15,425,690,150,44.399,-118.401,1244.9277,140.2387,124.4928,17.4587,140.2387,124.4928,17.4587,1244.9277,276.8294,0.0116 +11,15,425,690,150,-44.402,-118.4,1153.3521,108.5453,115.3352,12.5191,108.5453,115.3352,12.5191,1153.3521,350.1047,0.0084 +12,15,425,690,150,-103.601,-74.001,1246.7141,130.2036,124.6714,16.2327,130.2036,124.6714,16.2327,1246.7141,305.1168,0.0119 +13,15,425,690,150,-118.402,0,1196.9844,108.6696,119.6984,13.0076,108.6696,119.6984,13.0076,1196.9844,367.3816,0.0102 +14,15,425,690,150,-103.601,73.998,1210.6956,128.4285,121.0696,15.5488,128.4285,121.0696,15.5488,1210.6956,310.8858,0.0112 +15,15,425,690,150,-44.399,118.401,1171.0328,98.4096,117.1033,11.5241,98.4096,117.1033,11.5241,1171.0328,404.1108,0.0087 +16,15,425,690,150,44.4,118.4,1169.9117,100.7126,116.9912,11.7825,100.7126,116.9912,11.7825,1169.9117,392.2843,0.0088 +17,15,425,690,150,103.603,73.999,1199.7618,108.1952,119.9762,12.9808,108.1952,119.9762,12.9808,1199.7618,364.4402,0.0107 +1,16,350,820,150,0,0,1029.9489,157.9004,102.9949,16.2629,157.9004,102.9949,16.2629,1029.9489,270.9289,0.0109 +2,16,350,820,150,74,-14.801,989.5313,130.8999,98.9531,12.953,130.8999,98.9531,12.953,989.5313,316.7947,0.0069 +3,16,350,820,150,29.602,-74,968.9048,121.7231,96.8905,11.7938,121.7231,96.8905,11.7938,968.9048,337.616,0.0069 +4,16,350,820,150,-44.401,-59.199,1008.6535,134.1505,100.8653,13.5311,134.1505,100.8653,13.5311,1008.6535,309.924,0.0098 +5,16,350,820,150,-74.001,14.802,991.4529,109.1183,99.1453,10.8186,109.1183,99.1453,10.8186,991.4529,383.7622,0.0073 +6,16,350,820,150,-29.599,74,997.0968,123.7614,99.7097,12.3402,123.7614,99.7097,12.3402,997.0968,339.8541,0.0086 +7,16,350,820,150,44.401,59.198,991.1741,111.3156,99.1174,11.0333,111.3156,99.1174,11.0333,991.1741,379.4342,0.0077 +8,16,350,820,150,118.4,-0.001,1002.0113,108.9231,100.2011,10.9142,108.9231,100.2011,10.9142,1002.0113,374.8463,0.0083 +9,16,350,820,150,103.599,-74.001,1000.4697,123.3659,100.047,12.3424,123.3659,100.047,12.3424,1000.4697,325.5202,0.0092 +10,16,350,820,150,44.398,-118.4,1013.8029,121.1421,101.3803,12.2814,121.1421,101.3803,12.2814,1013.8029,330.2841,0.0094 +11,16,350,820,150,-44.401,-118.4,987.4907,115.4388,98.7491,11.3995,115.4388,98.7491,11.3995,987.4907,342.9402,0.0075 +12,16,350,820,150,-103.601,-73.999,1020.0015,129.1119,102.0001,13.1694,129.1119,102.0001,13.1694,1020.0015,313.6122,0.0122 +13,16,350,820,150,-118.402,0,1012.4409,122.6144,101.2441,12.414,122.6144,101.2441,12.414,1012.4409,333.1339,0.0102 +14,16,350,820,150,-103.598,74,1014.5298,124.9659,101.453,12.6782,124.9659,101.453,12.6782,1014.5298,323.0759,0.0089 +15,16,350,820,150,-44.4,118.401,997.7552,112.2317,99.7755,11.198,112.2317,99.7755,11.198,997.7552,362.5231,0.0088 +16,16,350,820,150,44.401,118.4,977.0716,97.4107,97.7072,9.5177,97.4107,97.7072,9.5177,977.0716,414.4219,0.0079 +17,16,350,820,150,103.601,74,995.0288,102.6314,99.5029,10.2121,102.6314,99.5029,10.2121,995.0288,392.5791,0.0078 +1,17,350,820,150,0,-0.001,967.4733,216.1438,96.7473,20.9113,216.1438,96.7473,20.9113,967.4733,204.7814,0.0042 +2,17,350,820,150,74.001,-14.8,926.9498,216.5282,92.695,20.0711,216.5282,92.695,20.0711,926.9498,199.3709,0.0037 +3,17,350,820,150,29.601,-74.001,943.6208,215.1827,94.3621,20.3051,215.1827,94.3621,20.3051,943.6208,201.5136,0.004 +4,17,350,820,150,-44.401,-59.198,959.7181,214.6907,95.9718,20.6043,214.6907,95.9718,20.6043,959.7181,202.6169,0.0048 +5,17,350,820,150,-74,14.801,995.183,232.9227,99.5183,23.1801,232.9227,99.5183,23.1801,995.183,190.24,0.0055 +6,17,350,820,150,-29.599,74,937.8175,208.7773,93.7818,19.5795,208.7773,93.7818,19.5795,937.8175,209.9875,0.0034 +7,17,350,820,150,44.4,59.199,977.2335,231.4196,97.7234,22.6151,231.4196,97.7234,22.6151,977.2335,191.7707,0.0055 +8,17,350,820,150,118.4,-0.001,973.6445,209.9531,97.3645,20.442,209.9531,97.3645,20.442,973.6445,207.1429,0.0044 +9,17,350,820,150,103.601,-74.001,962.7674,211.3637,96.2767,20.3494,211.3637,96.2767,20.3494,962.7674,202.8725,0.0042 +10,17,350,820,150,44.399,-118.401,971.0012,216.5083,97.1001,21.023,216.5083,97.1001,21.023,971.0012,198.3957,0.0054 +11,17,350,820,150,-44.402,-118.4,942.0002,204.0039,94.2,19.2172,204.0039,94.2,19.2172,942.0002,207.056,0.0037 +12,17,350,820,150,-103.6,-74,973.6995,200.8508,97.3699,19.5568,200.8508,97.3699,19.5568,973.6995,215.2973,0.0054 +13,17,350,820,150,-118.4,0,961.8871,201.8273,96.1887,19.4135,201.8273,96.1887,19.4135,961.8871,216.2349,0.0049 +14,17,350,820,150,-103.601,74.001,977.9094,222.0011,97.7909,21.7097,222.0011,97.7909,21.7097,977.9094,197.6788,0.0051 +15,17,350,820,150,-44.4,118.4,963.5474,223.0385,96.3547,21.4908,223.0385,96.3547,21.4908,963.5474,198.4774,0.0056 +16,17,350,820,150,44.4,118.4,958.5841,212.906,95.8584,20.4088,212.906,95.8584,20.4088,958.5841,205.7514,0.005 +17,17,350,820,150,103.602,73.999,969.0357,214.0431,96.9036,20.7415,214.0431,96.9036,20.7415,969.0357,203.7684,0.0053 +1,18,350,820,150,0,0,1016.0071,133.132,101.6007,13.5263,133.132,101.6007,13.5263,1016.0071,321.2368,0.007 +2,18,350,820,150,74,-14.801,987.7178,136.1069,98.7718,13.4435,136.1069,98.7718,13.4435,987.7178,305.331,0.0056 +3,18,350,820,150,29.599,-74.001,1019.0529,141.7201,101.9053,14.442,141.7201,101.9053,14.442,1019.0529,295.4286,0.0074 +4,18,350,820,150,-44.401,-59.199,1021.54,143.0793,102.154,14.6161,143.0793,102.154,14.6161,1021.54,293.4315,0.0077 +5,18,350,820,150,-74.002,14.801,1029.3126,140.8482,102.9313,14.4977,140.8482,102.9313,14.4977,1029.3126,303.9875,0.0093 +6,18,350,820,150,-29.599,74,1007.5427,129.7302,100.7543,13.0709,129.7302,100.7543,13.0709,1007.5427,327.5743,0.0072 +7,18,350,820,150,44.4,59.2,1053.8663,156.7547,105.3866,16.5199,156.7547,105.3866,16.5199,1053.8663,273.9025,0.0087 +8,18,350,820,150,118.401,-0.001,1045.0486,147.8745,104.5049,15.4536,147.8745,104.5049,15.4536,1045.0486,283.0747,0.0092 +9,18,350,820,150,103.599,-74.001,1028.8269,149.3593,102.8827,15.3665,149.3593,102.8827,15.3665,1028.8269,273.9069,0.0088 +10,18,350,820,150,44.398,-118.401,1046.8239,143.8671,104.6824,15.0604,143.8671,104.6824,15.0604,1046.8239,284.7881,0.0096 +11,18,350,820,150,-44.402,-118.4,1019.8665,141.967,101.9866,14.4787,141.967,101.9866,14.4787,1019.8665,286.7693,0.0082 +12,18,350,820,150,-103.601,-74,1022.0805,117.0597,102.2081,11.9644,117.0597,102.2081,11.9644,1022.0805,352.8903,0.0077 +13,18,350,820,150,-118.4,0,1019.1177,126.9935,101.9118,12.9421,126.9935,101.9118,12.9421,1019.1177,328.637,0.0088 +14,18,350,820,150,-103.599,74.001,993.0048,115.8635,99.3005,11.5053,115.8635,99.3005,11.5053,993.0048,355.9823,0.0059 +15,18,350,820,150,-44.4,118.4,1007.6011,114.3499,100.7601,11.5219,114.3499,100.7601,11.5219,1007.6011,366.751,0.0076 +16,18,350,820,150,44.4,118.4,1015.3873,129.8054,101.5387,13.1803,129.8054,101.5387,13.1803,1015.3873,321.9023,0.0084 +17,18,350,820,150,103.601,74,1015.5718,115.81,101.5572,11.7613,115.81,101.5572,11.7613,1015.5718,357.6244,0.007 diff --git a/sigeb-doe-new.csv b/sigeb-doe-new.csv new file mode 100644 index 00000000..57692d02 --- /dev/null +++ b/sigeb-doe-new.csv @@ -0,0 +1,443 @@ +wafer,site,time_dep,geh4,b2h6,th_sigeb,oxide, GOF +1,1,350,690,125,145.514,10.0168,0.91157 +1,2,350,690,125,145.055,10.1523,0.91233 +1,3,350,690,125,144.982,10.2892,0.91194 +1,4,350,690,125,144.464,10.0638,0.91097 +1,5,350,690,125,145.525,10.0484,0.91154 +1,6,350,690,125,146.326,10.1825,0.91064 +1,7,350,690,125,145.991,10.0093,0.91145 +1,8,350,690,125,144.453,10.2859,0.9111 +1,9,350,690,125,144.038,10.4623,0.91101 +1,10,350,690,125,143.361,10.5098,0.91163 +1,11,350,690,125,143.028,10.4588,0.91136 +1,12,350,690,125,142.481,10.4081,0.91182 +1,13,350,690,125,143.147,10.3145,0.91243 +1,14,350,690,125,144.31,10.3705,0.91096 +1,15,350,690,125,145.766,10.4885,0.91092 +1,16,350,690,125,145.902,10.3611,0.90982 +1,17,350,690,125,144.253,10.1681,0.91174 +1,18,350,690,125,145.505,10.0081,0.91165 +1,19,350,690,125,145.566,10.1,0.911 +1,20,350,690,125,145.572,10.0218,0.91202 +1,21,350,690,125,145.687,10.0665,0.91044 +1,22,350,690,125,145.68,10.0761,0.91055 +1,23,350,690,125,145.361,10.0334,0.91162 +1,24,350,690,125,143.082,10.3668,0.91189 +1,25,350,690,125,143.199,10.3587,0.91228 +1,26,350,690,125,143.347,10.3197,0.91262 +2,1,425,560,125,116.785,8.6946,0.89922 +2,2,425,560,125,115.419,8.7367,0.90145 +2,3,425,560,125,115.032,8.9338,0.90063 +2,4,425,560,125,115.188,8.8582,0.90065 +2,5,425,560,125,116.295,8.8693,0.90087 +2,6,425,560,125,117.133,8.9213,0.90176 +2,7,425,560,125,116.604,8.6695,0.90046 +2,8,425,560,125,114.236,8.9176,0.90152 +2,9,425,560,125,113.302,9.1138,0.90279 +2,10,425,560,125,112.919,9.2271,0.90462 +2,11,425,560,125,113.507,9.2392,0.90302 +2,12,425,560,125,114.24,9.2459,0.90451 +2,13,425,560,125,114.676,9.2358,0.90337 +2,14,425,560,125,116.384,9.2687,0.90447 +2,15,425,560,125,117.148,9.2305,0.90459 +2,16,425,560,125,116.449,9.1342,0.90446 +2,17,425,560,125,114.922,8.8886,0.90343 +2,18,425,560,125,116.741,8.6945,0.90052 +2,19,425,560,125,116.764,8.7589,0.89989 +2,20,425,560,125,116.799,8.715,0.90048 +2,21,425,560,125,116.312,8.9032,0.90211 +2,22,425,560,125,116.362,8.9025,0.90126 +2,23,425,560,125,116.203,8.864,0.90065 +2,24,425,560,125,114.656,9.2897,0.9046 +2,25,425,560,125,114.751,9.252,0.90342 +2,26,425,560,125,114.783,9.2136,0.90333 +3,1,500,690,125,207.834,9.2361,0.88955 +3,2,500,690,125,207.203,9.333,0.88948 +3,3,500,690,125,207.132,9.4713,0.88968 +3,4,500,690,125,206.786,9.3504,0.88861 +3,5,500,690,125,208.169,9.4038,0.88855 +3,6,500,690,125,209.411,9.409,0.88771 +3,7,500,690,125,208.479,9.2213,0.88892 +3,8,500,690,125,203.66,9.4801,0.88863 +3,9,500,690,125,202.748,9.6177,0.88806 +3,10,500,690,125,202.804,9.6772,0.88777 +3,11,500,690,125,204.744,9.5466,0.88807 +3,12,500,690,125,205.242,9.5361,0.88791 +3,13,500,690,125,206.366,9.6722,0.88801 +3,14,500,690,125,207.426,9.5462,0.88706 +3,15,500,690,125,208.343,9.5627,0.88631 +3,16,500,690,125,206.172,9.5173,0.88745 +3,17,500,690,125,203.489,9.349,0.88846 +3,18,500,690,125,207.751,9.2326,0.88838 +3,19,500,690,125,207.755,9.3003,0.88952 +3,20,500,690,125,207.684,9.2133,0.88822 +3,21,500,690,125,208.455,9.3974,0.88861 +3,22,500,690,125,208.321,9.398,0.88907 +3,23,500,690,125,207.863,9.3973,0.88882 +3,24,500,690,125,206.001,9.6793,0.88688 +3,25,500,690,125,206.426,9.6652,0.88752 +3,26,500,690,125,206.664,9.5924,0.88802 +4,1,425,820,125,254.491,9.044,0.88419 +4,2,425,820,125,254.842,9.1095,0.88408 +4,3,425,820,125,254.954,9.2301,0.88504 +4,4,425,820,125,253.842,9.112,0.8843 +4,5,425,820,125,255.473,9.2031,0.88458 +4,6,425,820,125,257.257,9.2664,0.88306 +4,7,425,820,125,256.196,9.0418,0.88476 +4,8,425,820,125,249.808,9.1655,0.88366 +4,9,425,820,125,247.836,9.2871,0.88226 +4,10,425,820,125,248.207,9.3255,0.88193 +4,11,425,820,125,249.76,9.2167,0.88276 +4,12,425,820,125,251.016,9.2033,0.88206 +4,13,425,820,125,252.896,9.3954,0.88333 +4,14,425,820,125,252.717,9.341,0.88157 +4,15,425,820,125,254.407,9.3804,0.8817 +4,16,425,820,125,252.007,9.2789,0.88194 +4,17,425,820,125,248.825,9.0224,0.88281 +4,18,425,820,125,254.399,9.0179,0.88321 +4,19,425,820,125,254.418,9.1339,0.88475 +4,20,425,820,125,254.372,9.0182,0.88326 +4,21,425,820,125,255.933,9.2065,0.88511 +4,22,425,820,125,255.701,9.2107,0.88465 +4,23,425,820,125,254.971,9.1803,0.88508 +4,24,425,820,125,252.279,9.4159,0.88319 +4,25,425,820,125,252.935,9.3853,0.88298 +4,26,425,820,125,253.494,9.3655,0.88401 +5,1,350,560,150,113.375,9.1907,0.87433 +5,2,350,560,150,112.017,9.1516,0.87784 +5,3,350,560,150,111.629,9.2904,0.88099 +5,4,350,560,150,111.626,9.25,0.87976 +5,5,350,560,150,112.632,9.2946,0.8796 +5,6,350,560,150,113.51,9.3519,0.87999 +5,7,350,560,150,113.139,9.1506,0.87649 +5,8,350,560,150,110.971,9.2219,0.88351 +5,9,350,560,150,110.434,9.3196,0.88919 +5,10,350,560,150,110.561,9.3276,0.89137 +5,11,350,560,150,110.531,9.2665,0.89273 +5,12,350,560,150,110.446,9.2775,0.89143 +5,13,350,560,150,111.274,9.4339,0.88699 +5,14,350,560,150,112.944,9.4018,0.89135 +5,15,350,560,150,113.335,9.3575,0.8881 +5,16,350,560,150,112.582,9.2881,0.88735 +5,17,350,560,150,111.458,9.0891,0.8854 +5,18,350,560,150,113.333,9.1931,0.87364 +5,19,350,560,150,113.429,9.2488,0.87435 +5,20,350,560,150,113.391,9.1973,0.87337 +5,21,350,560,150,112.698,9.3398,0.88015 +5,22,350,560,150,112.809,9.321,0.88021 +5,23,350,560,150,112.669,9.3225,0.87959 +5,24,350,560,150,111.273,9.4797,0.88861 +5,25,350,560,150,111.29,9.4566,0.88787 +5,26,350,560,150,111.289,9.422,0.8875 +6,1,350,820,150,223.754,9.1031,0.88108 +6,2,350,820,150,223.832,9.1178,0.88268 +6,3,350,820,150,223.807,9.2311,0.88197 +6,4,350,820,150,223.385,9.1473,0.88135 +6,5,350,820,150,225.163,9.2337,0.88146 +6,6,350,820,150,226.335,9.2297,0.88146 +6,7,350,820,150,225.131,9.0664,0.88166 +6,8,350,820,150,221.776,9.2743,0.88145 +6,9,350,820,150,220.265,9.4186,0.88189 +6,10,350,820,150,219.815,9.4368,0.88182 +6,11,350,820,150,221.186,9.3154,0.88088 +6,12,350,820,150,222.457,9.3061,0.8804 +6,13,350,820,150,223.131,9.422,0.88128 +6,14,350,820,150,223.808,9.3943,0.87952 +6,15,350,820,150,224.756,9.3546,0.88001 +6,16,350,820,150,223.123,9.3159,0.88008 +6,17,350,820,150,220.961,9.1681,0.88052 +6,18,350,820,150,223.741,9.0918,0.88249 +6,19,350,820,150,223.587,9.1561,0.88265 +6,20,350,820,150,223.677,9.0742,0.88096 +6,21,350,820,150,225.554,9.2554,0.88148 +6,22,350,820,150,225.356,9.2422,0.88079 +6,23,350,820,150,224.815,9.2516,0.88188 +6,24,350,820,150,222.884,9.4817,0.88046 +6,25,350,820,150,223.201,9.4438,0.88075 +6,26,350,820,150,223.543,9.4049,0.88136 +7,1,425,690,150,197.907,9.511,0.89173 +7,2,425,690,150,197.101,9.5863,0.89099 +7,3,425,690,150,196.633,9.6784,0.89146 +7,4,425,690,150,196.486,9.6373,0.89126 +7,5,425,690,150,198.183,9.6796,0.89097 +7,6,425,690,150,199.421,9.6729,0.89093 +7,7,425,690,150,198.539,9.5264,0.89151 +7,8,425,690,150,194.219,9.7533,0.89195 +7,9,425,690,150,192.92,9.8558,0.89242 +7,10,425,690,150,192.86,9.8802,0.89216 +7,11,425,690,150,193.839,9.7845,0.89108 +7,12,425,690,150,195.018,9.8333,0.89182 +7,13,425,690,150,196.848,9.8554,0.89053 +7,14,425,690,150,197.903,9.7841,0.88875 +7,15,425,690,150,198.965,9.7663,0.88786 +7,16,425,690,150,197.443,9.7202,0.88975 +7,17,425,690,150,194.822,9.6183,0.89235 +7,18,425,690,150,197.898,9.5314,0.89193 +7,19,425,690,150,197.869,9.5898,0.89211 +7,20,425,690,150,197.885,9.5324,0.89198 +7,21,425,690,150,198.337,9.6761,0.8916 +7,22,425,690,150,198.303,9.6993,0.89077 +7,23,425,690,150,197.873,9.6802,0.89129 +7,24,425,690,150,196.604,9.8809,0.89007 +7,25,425,690,150,196.913,9.8868,0.89181 +7,26,425,690,150,197.056,9.8507,0.89084 +8,1,425,690,150,199.214,9.5196,0.8916 +8,2,425,690,150,198.348,9.583,0.89186 +8,3,425,690,150,198.118,9.6587,0.89157 +8,4,425,690,150,197.957,9.6154,0.8913 +8,5,425,690,150,199.407,9.7073,0.89133 +8,6,425,690,150,200.58,9.6753,0.8898 +8,7,425,690,150,199.637,9.5283,0.89128 +8,8,425,690,150,195.201,9.7685,0.89245 +8,9,425,690,150,194.143,9.8567,0.89125 +8,10,425,690,150,194.54,9.8543,0.89218 +8,11,425,690,150,196.496,9.7172,0.89029 +8,12,425,690,150,196.225,9.79,0.891 +8,13,425,690,150,197.959,9.8747,0.89134 +8,14,425,690,150,199.377,9.7811,0.88865 +8,15,425,690,150,199.721,9.809,0.88812 +8,16,425,690,150,197.523,9.7538,0.89096 +8,17,425,690,150,195.19,9.6418,0.89161 +8,18,425,690,150,199.125,9.5184,0.89131 +8,19,425,690,150,199.106,9.5729,0.8917 +8,20,425,690,150,199.05,9.497,0.89095 +8,21,425,690,150,199.709,9.7215,0.89173 +8,22,425,690,150,199.645,9.7217,0.89103 +8,23,425,690,150,199.215,9.694,0.89134 +8,24,425,690,150,197.616,9.8937,0.89009 +8,25,425,690,150,197.979,9.859,0.89103 +8,26,425,690,150,198.149,9.8424,0.88996 +9,1,500,560,150,171.219,9.3213,0.88059 +9,2,500,560,150,168.824,9.2898,0.88235 +9,3,500,560,150,167.992,9.3826,0.88479 +9,4,500,560,150,168.385,9.3533,0.883 +9,5,500,560,150,170.089,9.4412,0.88419 +9,6,500,560,150,171.125,9.4637,0.88526 +9,7,500,560,150,170.528,9.2816,0.8829 +9,8,500,560,150,165.942,9.3819,0.885 +9,9,500,560,150,164.681,9.4762,0.88767 +9,10,500,560,150,163.792,9.4819,0.88893 +9,11,500,560,150,164.59,9.4292,0.88888 +9,12,500,560,150,165.074,9.5164,0.88871 +9,13,500,560,150,167.494,9.5837,0.88775 +9,14,500,560,150,169.998,9.6664,0.89077 +9,15,500,560,150,169.999,9.616,0.89055 +9,16,500,560,150,169.034,9.4979,0.88918 +9,17,500,560,150,167.333,9.3395,0.88773 +9,18,500,560,150,171.255,9.3297,0.87966 +9,19,500,560,150,171.207,9.3688,0.88086 +9,20,500,560,150,171.27,9.3797,0.88162 +9,21,500,560,150,170.124,9.4378,0.88383 +9,22,500,560,150,170.211,9.4321,0.88402 +9,23,500,560,150,170.043,9.4412,0.88348 +9,24,500,560,150,167.26,9.6049,0.88892 +9,25,500,560,150,167.57,9.5893,0.8876 +9,26,500,560,150,167.687,9.5774,0.88719 +10,1,500,820,150,324.651,9.5177,0.90332 +10,2,500,820,150,324.836,9.5548,0.90257 +10,3,500,820,150,324.289,9.6089,0.90188 +10,4,500,820,150,323.051,9.5188,0.90149 +10,5,500,820,150,325.471,9.6739,0.90238 +10,6,500,820,150,327.638,9.7456,0.90323 +10,7,500,820,150,326.633,9.55,0.9035 +10,8,500,820,150,321.363,9.5655,0.89838 +10,9,500,820,150,319.899,9.6231,0.89695 +10,10,500,820,150,318.39,9.5666,0.8963 +10,11,500,820,150,318.159,9.4704,0.89611 +10,12,500,820,150,317.739,9.5313,0.89541 +10,13,500,820,150,320.951,9.7599,0.89801 +10,14,500,820,150,320.942,9.7003,0.89516 +10,15,500,820,150,323.289,9.7635,0.89812 +10,16,500,820,150,323.646,9.6401,0.89888 +10,17,500,820,150,320.027,9.3668,0.89791 +10,18,500,820,150,324.6,9.4834,0.90238 +10,19,500,820,150,324.577,9.5883,0.90405 +10,20,500,820,150,324.611,9.5069,0.90314 +10,21,500,820,150,325.907,9.7,0.90266 +10,22,500,820,150,325.739,9.6772,0.90292 +10,23,500,820,150,325.046,9.6503,0.90233 +10,24,500,820,150,320.312,9.6848,0.89677 +10,25,500,820,150,321.101,9.7492,0.89832 +10,26,500,820,150,321.679,9.7177,0.89767 +11,1,425,560,175,170.221,10.052,0.84759 +11,2,425,560,175,168.204,10.0193,0.85147 +11,3,425,560,175,167.091,10.057,0.8538 +11,4,425,560,175,167.122,10.0629,0.85169 +11,5,425,560,175,168.461,10.1213,0.85242 +11,6,425,560,175,169.599,10.1577,0.85463 +11,7,425,560,175,169.464,10.0226,0.85173 +11,8,425,560,175,165.893,10.004,0.85991 +11,9,425,560,175,163.678,9.9432,0.86659 +11,10,425,560,175,162.668,9.9428,0.86667 +11,11,425,560,175,162.821,9.8704,0.86822 +11,12,425,560,175,162.719,9.9728,0.86604 +11,13,425,560,175,164.397,10.1248,0.86049 +11,14,425,560,175,165.637,10.0314,0.86758 +11,15,425,560,175,166.875,10.0366,0.86722 +11,16,425,560,175,166.549,9.9406,0.8633 +11,17,425,560,175,165.627,9.8118,0.86289 +11,18,425,560,175,170.104,10.0742,0.84733 +11,19,425,560,175,170.216,10.1402,0.84855 +11,20,425,560,175,170.227,10.1031,0.84801 +11,21,425,560,175,168.38,10.1203,0.85316 +11,22,425,560,175,168.552,10.0993,0.85089 +11,23,425,560,175,168.427,10.114,0.85198 +11,24,425,560,175,164.131,10.1201,0.8625 +11,25,425,560,175,164.463,10.1348,0.86103 +11,26,425,560,175,164.785,10.1361,0.86069 +12,1,350,690,175,184.429,9.8748,0.90254 +12,2,350,690,175,183.219,9.915,0.90278 +12,3,350,690,175,182.672,9.9855,0.90266 +12,4,350,690,175,182.645,9.9603,0.90207 +12,5,350,690,175,184.361,10.019,0.90167 +12,6,350,690,175,185.253,10.0237,0.90088 +12,7,350,690,175,184.55,9.8467,0.9024 +12,8,350,690,175,181.271,10.104,0.90493 +12,9,350,690,175,179.494,10.1351,0.90436 +12,10,350,690,175,179.019,10.1481,0.9044 +12,11,350,690,175,179.53,10.0902,0.90294 +12,12,350,690,175,180.727,10.1145,0.90304 +12,13,350,690,175,182.023,10.1747,0.90213 +12,14,350,690,175,183.276,10.1591,0.90063 +12,15,350,690,175,184.149,10.1035,0.89983 +12,16,350,690,175,183.348,10.0513,0.90159 +12,17,350,690,175,181.831,9.967,0.9032 +12,18,350,690,175,184.406,9.8525,0.90248 +12,19,350,690,175,184.334,9.9174,0.9022 +12,20,350,690,175,184.32,9.8413,0.90157 +12,21,350,690,175,184.44,10.0577,0.90235 +12,22,350,690,175,184.433,10.0124,0.90117 +12,23,350,690,175,184.166,10.0251,0.9027 +12,24,350,690,175,181.871,10.1833,0.90248 +12,25,350,690,175,182.136,10.2115,0.90262 +12,26,350,690,175,182.23,10.1702,0.90197 +13,1,425,820,175,292.202,9.1663,0.89238 +13,2,425,820,175,291.759,9.1725,0.89074 +13,3,425,820,175,291.668,9.2152,0.89002 +13,4,425,820,175,290.778,9.231,0.88994 +13,5,425,820,175,292.582,9.2785,0.89094 +13,6,425,820,175,293.808,9.2801,0.89174 +13,7,425,820,175,292.837,9.1161,0.89297 +13,8,425,820,175,288.549,9.251,0.89001 +13,9,425,820,175,288.634,9.2536,0.88851 +13,10,425,820,175,287.597,9.2449,0.88866 +13,11,425,820,175,287.6,9.2276,0.88637 +13,12,425,820,175,287.92,9.2618,0.8869 +13,13,425,820,175,288.812,9.3774,0.88877 +13,14,425,820,175,288.758,9.3416,0.88703 +13,15,425,820,175,288.931,9.3116,0.88823 +13,16,425,820,175,287.662,9.1981,0.88802 +13,17,425,820,175,286.416,9.1196,0.88831 +13,18,425,820,175,292.218,9.1371,0.89118 +13,19,425,820,175,292.142,9.2263,0.89213 +13,20,425,820,175,292.18,9.1386,0.88973 +13,21,425,820,175,292.972,9.284,0.89174 +13,22,425,820,175,292.808,9.2962,0.89146 +13,23,425,820,175,292.27,9.2772,0.89133 +13,24,425,820,175,288.434,9.4141,0.88619 +13,25,425,820,175,288.852,9.376,0.8879 +13,26,425,820,175,289.257,9.3542,0.88889 +14,1,500,690,175,259.519,8.7268,0.88819 +14,2,500,690,175,257.807,8.751,0.88782 +14,3,500,690,175,257.436,8.827,0.88721 +14,4,500,690,175,257.183,8.8243,0.88664 +14,5,500,690,175,259.134,8.8602,0.88711 +14,6,500,690,175,260.255,8.8925,0.8876 +14,7,500,690,175,259.461,8.7201,0.88832 +14,8,500,690,175,254.12,8.9055,0.88725 +14,9,500,690,175,252.424,8.9223,0.8861 +14,10,500,690,175,253.313,8.9736,0.88644 +14,11,500,690,175,252.893,8.8805,0.88523 +14,12,500,690,175,252.887,8.9266,0.88527 +14,13,500,690,175,255.043,9.0161,0.88717 +14,14,500,690,175,256.317,8.9341,0.88518 +14,15,500,690,175,256.622,8.9268,0.88607 +14,16,500,690,175,255.149,8.8486,0.88598 +14,17,500,690,175,253.716,8.7923,0.88616 +14,18,500,690,175,259.429,8.7133,0.88707 +14,19,500,690,175,259.453,8.7927,0.88733 +14,20,500,690,175,259.439,8.7181,0.8874 +14,21,500,690,175,259.362,8.8878,0.88721 +14,22,500,690,175,259.297,8.8704,0.88772 +14,23,500,690,175,259.027,8.8843,0.88752 +14,24,500,690,175,254.832,9.0135,0.88624 +14,25,500,690,175,255.162,8.9976,0.88596 +14,26,500,690,175,255.484,8.9819,0.88635 +15,1,425,690,150,197.956,9.6905,0.89394 +15,2,425,690,150,196.561,9.7232,0.89484 +15,3,425,690,150,196.079,9.831,0.89479 +15,4,425,690,150,196.071,9.8243,0.89438 +15,5,425,690,150,197.571,9.8277,0.89357 +15,6,425,690,150,198.766,9.8569,0.89183 +15,7,425,690,150,197.931,9.6956,0.89415 +15,8,425,690,150,192.895,9.9616,0.89498 +15,9,425,690,150,191.459,9.9804,0.89418 +15,10,425,690,150,191.551,10.0448,0.89544 +15,11,425,690,150,192.413,10.0173,0.89455 +15,12,425,690,150,193.65,9.9505,0.89367 +15,13,425,690,150,195.344,9.9868,0.89404 +15,14,425,690,150,196.033,9.9571,0.89208 +15,15,425,690,150,197.121,9.8914,0.89087 +15,16,425,690,150,195.54,9.8878,0.89315 +15,17,425,690,150,193.203,9.8615,0.89481 +15,18,425,690,150,197.89,9.6823,0.89428 +15,19,425,690,150,197.879,9.7376,0.89374 +15,20,425,690,150,197.853,9.6945,0.89335 +15,21,425,690,150,197.768,9.8552,0.89448 +15,22,425,690,150,197.727,9.8432,0.89426 +15,23,425,690,150,197.401,9.857,0.89437 +15,24,425,690,150,195.044,9.993,0.89301 +15,25,425,690,150,195.413,10.0025,0.89309 +15,26,425,690,150,195.662,9.9647,0.8939 +16,1,350,820,150,234.612,9.018,0.88232 +16,2,350,820,150,234.112,9.0162,0.88186 +16,3,350,820,150,233.763,9.1845,0.88161 +16,4,350,820,150,233.233,9.1616,0.88229 +16,5,350,820,150,234.866,9.1689,0.88264 +16,6,350,820,150,235.813,9.1467,0.88175 +16,7,350,820,150,235.146,8.979,0.88298 +16,8,350,820,150,230.611,9.2715,0.88184 +16,9,350,820,150,229.191,9.3451,0.87982 +16,10,350,820,150,227.962,9.4103,0.88064 +16,11,350,820,150,228.802,9.3852,0.88068 +16,12,350,820,150,228.494,9.3225,0.87873 +16,13,350,820,150,229.894,9.3715,0.8808 +16,14,350,820,150,228.896,9.3628,0.87839 +16,15,350,820,150,229.631,9.3221,0.87892 +16,16,350,820,150,228.926,9.2514,0.88077 +16,17,350,820,150,227.714,9.1847,0.88118 +16,18,350,820,150,234.655,9.0425,0.88229 +16,19,350,820,150,234.541,9.0911,0.88328 +16,20,350,820,150,234.614,9.0232,0.88137 +16,21,350,820,150,235.135,9.1964,0.8827 +16,22,350,820,150,235.056,9.1589,0.88196 +16,23,350,820,150,234.56,9.1559,0.88187 +16,24,350,820,150,229.297,9.3606,0.88012 +16,25,350,820,150,229.912,9.3629,0.8806 +16,26,350,820,150,230.509,9.3365,0.88078 +18,1,350,820,150,228.446,9.1394,0.882 +18,2,350,820,150,228.228,9.2263,0.88109 +18,3,350,820,150,228.157,9.3743,0.88159 +18,4,350,820,150,227.709,9.2978,0.88255 +18,5,350,820,150,229.461,9.2777,0.88145 +18,6,350,820,150,230.567,9.3037,0.88103 +18,7,350,820,150,229.535,9.142,0.88119 +18,8,350,820,150,226.277,9.3444,0.88184 +18,9,350,820,150,225.378,9.6416,0.88213 +18,10,350,820,150,224.996,9.682,0.88166 +18,11,350,820,150,225.889,9.5442,0.88183 +18,12,350,820,150,226.963,9.5057,0.8794 +18,13,350,820,150,227.654,9.4551,0.88029 +18,14,350,820,150,227.983,9.5043,0.87875 +18,15,350,820,150,229.177,9.4398,0.87903 +18,16,350,820,150,228.004,9.48,0.88038 +18,17,350,820,150,225.563,9.4523,0.88227 +18,18,350,820,150,228.399,9.127,0.88081 +18,19,350,820,150,228.305,9.2,0.88204 +18,20,350,820,150,228.358,9.0938,0.87994 +18,21,350,820,150,229.816,9.3323,0.88149 +18,22,350,820,150,229.664,9.2771,0.88134 +18,23,350,820,150,229.116,9.279,0.88255 +18,24,350,820,150,227.467,9.4927,0.88179 +18,25,350,820,150,227.671,9.5128,0.88031 +18,26,350,820,150,227.944,9.4633,0.88128 |