tioga 1.11 → 1.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. data/Tioga_README +58 -35
  2. data/{split/scripts → bin}/tioga +1 -1
  3. data/{split → ext/Dobjects}/Dtable/dtable.c +81 -15
  4. data/{split → ext/Dobjects}/Dtable/dtable_intern.h +0 -0
  5. data/ext/Dobjects/Dtable/extconf.rb +7 -0
  6. data/{split → ext/Dobjects}/Dtable/include/dtable.h +0 -0
  7. data/{split → ext/Dobjects}/Dvector/dvector.c +361 -51
  8. data/{split → ext/Dobjects}/Dvector/dvector_intern.h +0 -0
  9. data/ext/Dobjects/Dvector/extconf.rb +22 -0
  10. data/{split/Dtable → ext/Dobjects/Dvector/include}/dvector.h +0 -0
  11. data/ext/Dobjects/Function/extconf.rb +7 -0
  12. data/{split → ext/Dobjects}/Function/function.c +636 -11
  13. data/{split → ext/Dobjects}/Function/joint_qsort.c +0 -0
  14. data/ext/Flate/extconf.rb +26 -0
  15. data/{split → ext}/Flate/flate.c +7 -3
  16. data/{split → ext}/Flate/flate_intern.h +0 -0
  17. data/{split → ext}/Flate/include/flate.h +0 -0
  18. data/ext/Flate/zlib/adler32.c +149 -0
  19. data/ext/Flate/zlib/compress.c +79 -0
  20. data/ext/Flate/zlib/crc32.c +423 -0
  21. data/ext/Flate/zlib/crc32.h +441 -0
  22. data/ext/Flate/zlib/deflate.c +1736 -0
  23. data/ext/Flate/zlib/deflate.h +331 -0
  24. data/ext/Flate/zlib/gzio.c +1026 -0
  25. data/ext/Flate/zlib/infback.c +623 -0
  26. data/ext/Flate/zlib/inffast.c +318 -0
  27. data/ext/Flate/zlib/inffast.h +11 -0
  28. data/ext/Flate/zlib/inffixed.h +94 -0
  29. data/ext/Flate/zlib/inflate.c +1368 -0
  30. data/ext/Flate/zlib/inflate.h +115 -0
  31. data/ext/Flate/zlib/inftrees.c +329 -0
  32. data/ext/Flate/zlib/inftrees.h +55 -0
  33. data/ext/Flate/zlib/trees.c +1219 -0
  34. data/ext/Flate/zlib/trees.h +128 -0
  35. data/ext/Flate/zlib/uncompr.c +61 -0
  36. data/ext/Flate/zlib/zlib.h +1357 -0
  37. data/ext/Flate/zlib/zutil.c +318 -0
  38. data/ext/Flate/zlib/zutil.h +269 -0
  39. data/ext/Tioga/FigureMaker/__shared_axes.c +1373 -0
  40. data/ext/Tioga/FigureMaker/__shared_makers.c +1303 -0
  41. data/{split/Tioga/pdf_font_dicts.c → ext/Tioga/FigureMaker/__shared_pdf_font_dicts.c} +0 -0
  42. data/{split/Tioga/pdfcolor.c → ext/Tioga/FigureMaker/__shared_pdfcolor.c} +0 -0
  43. data/{split/Tioga/pdfcoords.c → ext/Tioga/FigureMaker/__shared_pdfcoords.c} +0 -0
  44. data/{split/Tioga/pdffile.c → ext/Tioga/FigureMaker/__shared_pdffile.c} +0 -0
  45. data/{split/Tioga/pdfimage.c → ext/Tioga/FigureMaker/__shared_pdfimage.c} +0 -0
  46. data/{split/Tioga/pdfpath.c → ext/Tioga/FigureMaker/__shared_pdfpath.c} +0 -0
  47. data/{split/Tioga/pdftext.c → ext/Tioga/FigureMaker/__shared_pdftext.c} +0 -0
  48. data/{split/Tioga/texout.c → ext/Tioga/FigureMaker/__shared_texout.c} +0 -0
  49. data/ext/Tioga/FigureMaker/extconf.rb +7 -0
  50. data/{split/Tioga → ext/Tioga/FigureMaker}/figures.c +14 -2
  51. data/{split/Tioga → ext/Tioga/FigureMaker}/figures.h +0 -0
  52. data/{split/Tioga → ext/Tioga/FigureMaker}/generic.c +1 -2
  53. data/{split/Tioga → ext/Tioga/FigureMaker}/generic.h +0 -1
  54. data/{split/Tioga → ext/Tioga/FigureMaker}/init.c +0 -0
  55. data/{split/Tioga → ext/Tioga/FigureMaker}/pdfs.h +0 -0
  56. data/{split/Tioga → ext/Tioga/FigureMaker/shared}/axes.c +32 -7
  57. data/{split/Tioga → ext/Tioga/FigureMaker/shared}/makers.c +2 -2
  58. data/ext/Tioga/FigureMaker/shared/pdf_font_dicts.c +18253 -0
  59. data/ext/Tioga/FigureMaker/shared/pdfcolor.c +904 -0
  60. data/ext/Tioga/FigureMaker/shared/pdfcoords.c +518 -0
  61. data/ext/Tioga/FigureMaker/shared/pdffile.c +451 -0
  62. data/ext/Tioga/FigureMaker/shared/pdfimage.c +539 -0
  63. data/ext/Tioga/FigureMaker/shared/pdfpath.c +766 -0
  64. data/ext/Tioga/FigureMaker/shared/pdftext.c +710 -0
  65. data/ext/Tioga/FigureMaker/shared/texout.c +533 -0
  66. data/{split/Tioga → ext/Tioga/FigureMaker}/wrappers.c +5 -5
  67. data/{split/Tioga → ext/Tioga/FigureMaker}/wrappers.h +0 -0
  68. data/{split/Dtable → ext/includes}/defs.h +0 -0
  69. data/{split/Dtable → ext/includes}/namespace.h +0 -0
  70. data/{split/Dtable → ext/includes}/safe_double.h +0 -0
  71. data/{split → ext/includes}/symbols.c +0 -1
  72. data/{split/Dtable → ext/includes}/symbols.h +0 -0
  73. data/{split/Dtable/lib → lib/Dobjects}/Dtable_extras.rb +0 -0
  74. data/{split/Dvector/lib → lib/Dobjects}/Dvector_extras.rb +1 -0
  75. data/{split/Function/lib → lib/Dobjects}/Function_extras.rb +0 -0
  76. data/{split/Dvector/lib → lib/Dobjects}/Numeric_extras.rb +0 -0
  77. data/{split/Tioga/lib → lib/Tioga}/Arcs_and_Circles.rb +0 -0
  78. data/{split/Tioga/lib → lib/Tioga}/ColorConstants.rb +0 -0
  79. data/{split/Tioga/lib → lib/Tioga}/Colorbars.rb +0 -0
  80. data/{split/Tioga/lib → lib/Tioga}/Colormaps.rb +0 -0
  81. data/{split/Tioga/lib → lib/Tioga}/Coordinate_Conversions.rb +0 -0
  82. data/{split/Tioga/lib → lib/Tioga}/Creating_Paths.rb +0 -0
  83. data/{split/Tioga/lib → lib/Tioga}/Doc.rb +0 -0
  84. data/{split/Tioga/lib → lib/Tioga}/Executive.rb +0 -0
  85. data/{split/Tioga/lib → lib/Tioga}/FigMkr.rb +13 -70
  86. data/{split/Tioga/lib → lib/Tioga}/FigureConstants.rb +0 -0
  87. data/{split/Tioga/lib → lib/Tioga}/Figures_and_Plots.rb +0 -0
  88. data/{split/Tioga/lib → lib/Tioga}/Images.rb +0 -0
  89. data/{split/Tioga/lib → lib/Tioga}/Legends.rb +0 -0
  90. data/{split/Tioga/lib → lib/Tioga}/MarkerConstants.rb +0 -0
  91. data/{split/Tioga/lib → lib/Tioga}/Markers.rb +0 -0
  92. data/{split/Tioga/lib → lib/Tioga}/Page_Frame_Bounds.rb +0 -0
  93. data/{split/Tioga/lib → lib/Tioga}/Rectangles.rb +0 -0
  94. data/{split/Tioga/lib → lib/Tioga}/Shading.rb +0 -0
  95. data/{split/Tioga/lib → lib/Tioga}/Special_Paths.rb +0 -0
  96. data/{split/Tioga/lib → lib/Tioga}/Strokes.rb +0 -0
  97. data/{split/Tioga/lib → lib/Tioga}/TeX_Text.rb +0 -0
  98. data/{split/Tioga/lib → lib/Tioga}/TexPreamble.rb +0 -0
  99. data/{split/Tioga/lib → lib/Tioga}/Titles_and_Labels.rb +0 -0
  100. data/{split/Tioga/lib → lib/Tioga}/Transparency.rb +0 -0
  101. data/{split/Tioga/lib → lib/Tioga}/Using_Paths.rb +0 -0
  102. data/{split/Tioga/lib → lib/Tioga}/Utils.rb +74 -0
  103. data/{split/Tioga/lib → lib/Tioga}/X_and_Y_Axes.rb +0 -0
  104. data/{split/Tioga/lib → lib/Tioga}/irb_tioga.rb +0 -0
  105. data/{split/Tioga/lib → lib/Tioga}/maker.rb +0 -0
  106. data/{split/Tioga/lib → lib/Tioga}/tioga.rb +0 -0
  107. data/{split/Tioga/lib → lib/Tioga}/tioga_ui.rb +0 -0
  108. data/{split/Tioga/lib → lib/Tioga}/tioga_ui_cmds.rb +0 -0
  109. data/tests/Icon_Test.pdf +0 -0
  110. data/tests/benchmark_dvector_reads.rb +20 -42
  111. data/tests/tc_Dvector.rb +45 -4
  112. data/tests/tc_Flate.rb +4 -5
  113. data/tests/tc_Function.rb +79 -0
  114. data/tests/vg.log +1453 -0
  115. metadata +141 -122
  116. data/split/Dtable/extconf.rb +0 -4
  117. data/split/Dvector/defs.h +0 -39
  118. data/split/Dvector/extconf.rb +0 -4
  119. data/split/Dvector/include/dvector.h +0 -77
  120. data/split/Dvector/namespace.h +0 -59
  121. data/split/Dvector/safe_double.h +0 -104
  122. data/split/Dvector/symbols.h +0 -52
  123. data/split/Flate/defs.h +0 -39
  124. data/split/Flate/extconf.rb +0 -19
  125. data/split/Flate/namespace.h +0 -59
  126. data/split/Flate/safe_double.h +0 -104
  127. data/split/Flate/symbols.h +0 -52
  128. data/split/Function/defs.h +0 -39
  129. data/split/Function/dvector.h +0 -77
  130. data/split/Function/extconf.rb +0 -4
  131. data/split/Function/namespace.h +0 -59
  132. data/split/Function/safe_double.h +0 -104
  133. data/split/Function/symbols.h +0 -52
  134. data/split/Tioga/defs.h +0 -39
  135. data/split/Tioga/dtable.h +0 -35
  136. data/split/Tioga/dvector.h +0 -77
  137. data/split/Tioga/extconf.rb +0 -4
  138. data/split/Tioga/flate.h +0 -98
  139. data/split/Tioga/mk_tioga_sty.rb +0 -53
  140. data/split/Tioga/namespace.h +0 -59
  141. data/split/Tioga/safe_double.h +0 -104
  142. data/split/Tioga/symbols.h +0 -52
  143. data/split/defs.h +0 -39
  144. data/split/extconf.rb +0 -125
  145. data/split/mkmf2.rb +0 -1623
  146. data/split/namespace.h +0 -59
  147. data/split/safe_double.h +0 -104
  148. data/split/symbols.h +0 -52
File without changes
@@ -0,0 +1,22 @@
1
+ # Dtable installation file
2
+ require 'mkmf'
3
+
4
+ # Conditional use of fftw3
5
+ if have_header("fftw3.h") and have_library("fftw3", "fftw_execute", "fftw3.h")
6
+ puts "fftw3 was found on this system: Fourier transforms will be available"
7
+ else
8
+ puts "fftw3 was not found on this system: no Fourier transforms"
9
+ end
10
+
11
+ # "Safe" way to store doubles (ie in a platform-independant way)
12
+ unless have_header("ieee754.h")
13
+ puts "You lack the ieee754.h header file, which might mean lower " +
14
+ "reliability when Marshalling Dvectors and Dtables"
15
+ end
16
+
17
+
18
+ # We add include directories
19
+ $INCFLAGS += " -I../../includes"
20
+
21
+
22
+ create_makefile 'Dobjects/Dvector'
@@ -0,0 +1,7 @@
1
+ # Function installation file
2
+ require 'mkmf'
3
+
4
+ # We add include directories
5
+ $INCFLAGS += " -I../../includes -I../Dvector/include"
6
+
7
+ create_makefile 'Dobjects/Function'
@@ -5,7 +5,7 @@
5
5
  An object embedding two Dvectors for the ease of manipulation as
6
6
  a function.
7
7
 
8
- Copyright (C) 2006 Vincent Fourmond
8
+ Copyright (C) 2006,2010 Vincent Fourmond
9
9
 
10
10
  This program is free software; you can redistribute it and/or modify
11
11
  it under the terms of the GNU General Library Public License as published
@@ -26,12 +26,16 @@
26
26
  #include <namespace.h>
27
27
  #include <ruby.h>
28
28
 
29
- #include "dvector.h"
30
- #include "../symbols.c"
31
29
 
32
30
  #include <math.h>
33
- /* compiler-dependent definitions, such as is_okay_number */
31
+
32
+ /* Private include files */
33
+ #include "dvector.h"
34
+ #include "symbols.c"
35
+
36
+ /* compiler-dependent defintions, such as is_okay_number */
34
37
  #include <defs.h>
38
+ /* End of private files */
35
39
 
36
40
  /* the class we're defining */
37
41
  static VALUE cFunction;
@@ -609,6 +613,8 @@ static VALUE function_interpolate(VALUE self, VALUE x_values)
609
613
  return Qnil;
610
614
  }
611
615
 
616
+
617
+
612
618
  /*
613
619
  Strips all the points containing NaN values from the function, and
614
620
  returns the number of points stripped.
@@ -644,7 +650,6 @@ static VALUE function_strip_nan(VALUE self)
644
650
  Returns the array of the subfunctions. The returned values are
645
651
  necessarily new values.
646
652
  */
647
-
648
653
  static VALUE function_split_monotonic(VALUE self)
649
654
  {
650
655
  VALUE ret = rb_ary_new();
@@ -707,6 +712,60 @@ static VALUE function_split_monotonic(VALUE self)
707
712
  }
708
713
 
709
714
 
715
+ /*
716
+ Splits the function on NaN values for x, y or xy, depending on
717
+ whether _sym_ is +:x+, +:y+ or +:xy+ (or, as a matter of fact,
718
+ anything else than +:x+ or +:y+).
719
+
720
+ This returns an array of new Function objects.
721
+
722
+ This function will return empty Function objects between consecutive
723
+ NaN values.
724
+ */
725
+ static VALUE function_split_on_nan(VALUE self, VALUE sym)
726
+ {
727
+ VALUE ret = rb_ary_new();
728
+ VALUE cur_x = Dvector_Create();
729
+ VALUE cur_y = Dvector_Create();
730
+ int on_x = 1;
731
+ int on_y = 1;
732
+ long size = function_sanity_check(self);
733
+ long cur_size = 0;
734
+ long i;
735
+ if(size < 2)
736
+ rb_raise(rb_eRuntimeError, "Function needs to have at least 2 points");
737
+
738
+ double *x = Dvector_Data_for_Read(get_x_vector(self),NULL);
739
+ double *y = Dvector_Data_for_Read(get_y_vector(self),NULL);
740
+
741
+ VALUE f;
742
+
743
+ if(sym == ID2SYM(rb_intern("x")))
744
+ on_y = 0;
745
+ else if(sym == ID2SYM(rb_intern("y")))
746
+ on_x = 0;
747
+
748
+
749
+ for(i = 0; i < size; i++) {
750
+ if((on_x && isnan(x[i])) ||
751
+ (on_y && isnan(y[i]))) {
752
+ /* We split */
753
+ f = Function_Create(cur_x, cur_y);
754
+ rb_ary_push(ret, f);
755
+ cur_x = Dvector_Create();
756
+ cur_y = Dvector_Create();
757
+ }
758
+ else {
759
+ Dvector_Push_Double(cur_x, x[i]);
760
+ Dvector_Push_Double(cur_y, y[i]);
761
+ }
762
+ }
763
+ f = Function_Create(cur_x, cur_y);
764
+ rb_ary_push(ret, f);
765
+ return ret;
766
+ }
767
+
768
+
710
769
  /*
711
770
  Sorts the X values while keeping the matching Y values.
712
771
  */
@@ -899,7 +958,8 @@ static VALUE function_primitive(VALUE self)
899
958
  Computes the derivative of the Function and returns it as a new Function.
900
959
  The newly created function shares the X vector with the previous one.
901
960
 
902
- WARNING: this is a very naive 3-points algorithm.
961
+ WARNING: this is a very naive 3-points algorithm; you should
962
+ consider using diff_5p
903
963
  */
904
964
  static VALUE function_derivative(VALUE self)
905
965
  {
@@ -924,6 +984,139 @@ static VALUE function_derivative(VALUE self)
924
984
  return Function_Create(get_x_vector(self), derivative);
925
985
  }
926
986
 
987
+ /*
988
+ Computes a 4th order accurate derivative of the Function.
989
+
990
+ This function *requires* that there are at the very least 5 data
991
+ points !
992
+ */
993
+ static VALUE function_diff_5p(VALUE self)
994
+ {
995
+ long size = function_sanity_check(self);
996
+ const double *x = Dvector_Data_for_Read(get_x_vector(self),NULL);
997
+ const double *y = Dvector_Data_for_Read(get_y_vector(self),NULL);
998
+ VALUE derivative = Dvector_Create();
999
+ long i = 0;
1000
+ double delta_1, delta_2, delta_3, delta_4;
1001
+ double alpha_1, alpha_2, alpha_3, alpha_4;
1002
+ double v0,v1,v2,v3,v4;
1003
+ /* TODO: what happens when there are less than 5 points ? */
1004
+
1005
+ for(i = 0; i < size; i++) {
1006
+ /* First initialize values, though this is very suboptimal */
1007
+ v0 = y[i];
1008
+ if(i == 0) {
1009
+ delta_1 = x[1] - x[0]; v1 = y[1];
1010
+ delta_2 = x[2] - x[0]; v2 = y[2];
1011
+ delta_3 = x[3] - x[0]; v3 = y[3];
1012
+ delta_4 = x[4] - x[0]; v4 = y[4];
1013
+ } else if(i == 1) {
1014
+ delta_1 = x[0] - x[1]; v1 = y[0];
1015
+ delta_2 = x[2] - x[1]; v2 = y[2];
1016
+ delta_3 = x[3] - x[1]; v3 = y[3];
1017
+ delta_4 = x[4] - x[1]; v4 = y[4];
1018
+ } else if(i == size - 2) {
1019
+ delta_1 = x[size-1] - x[size-2]; v1 = y[size-1];
1020
+ delta_2 = x[size-3] - x[size-2]; v2 = y[size-3];
1021
+ delta_3 = x[size-4] - x[size-2]; v3 = y[size-4];
1022
+ delta_4 = x[size-5] - x[size-2]; v4 = y[size-5];
1023
+ } else if(i == size - 1) {
1024
+ delta_1 = x[size-2] - x[size-1]; v1 = y[size-2];
1025
+ delta_2 = x[size-3] - x[size-1]; v2 = y[size-3];
1026
+ delta_3 = x[size-4] - x[size-1]; v3 = y[size-4];
1027
+ delta_4 = x[size-5] - x[size-1]; v4 = y[size-5];
1028
+ } else {
1029
+ delta_1 = x[i-2] - x[i]; v1 = y[i-2];
1030
+ delta_2 = x[i-1] - x[i]; v2 = y[i-1];
1031
+ delta_3 = x[i+2] - x[i]; v3 = y[i+2];
1032
+ delta_4 = x[i+1] - x[i]; v4 = y[i+1];
1033
+ }
1034
+ alpha_1 = delta_2*delta_3*delta_4/
1035
+ (delta_1 * (delta_2 - delta_1) * (delta_3 - delta_1)
1036
+ * (delta_4 - delta_1));
1037
+ alpha_2 = delta_1*delta_3*delta_4/
1038
+ (delta_2 * (delta_1 - delta_2) * (delta_3 - delta_2)
1039
+ * (delta_4 - delta_2));
1040
+ alpha_3 = delta_1*delta_2*delta_4/
1041
+ (delta_3 * (delta_1 - delta_3) * (delta_2 - delta_3)
1042
+ * (delta_4 - delta_3));
1043
+ alpha_4 = delta_1*delta_2*delta_3/
1044
+ (delta_4 * (delta_1 - delta_4) * (delta_2 - delta_4)
1045
+ * (delta_3 - delta_4));
1046
+ Dvector_Push_Double(derivative,
1047
+ -(alpha_1 + alpha_2 + alpha_3 + alpha_4) * v0 +
1048
+ alpha_1 * v1 + alpha_2 * v2 +
1049
+ alpha_3 * v3 + alpha_4 * v4);
1050
+ }
1051
+ return Function_Create(get_x_vector(self), derivative);
1052
+ }
1053
+
1054
+ /*
1055
+ Computes a 4th order accurate second derivative of the Function.
1056
+
1057
+ This function *requires* that there are at the very least 5 data
1058
+ points!
1059
+ */
1060
+ static VALUE function_diff2_5p(VALUE self)
1061
+ {
1062
+ long size = function_sanity_check(self);
1063
+ const double *x = Dvector_Data_for_Read(get_x_vector(self),NULL);
1064
+ const double *y = Dvector_Data_for_Read(get_y_vector(self),NULL);
1065
+ VALUE derivative = Dvector_Create();
1066
+ long i = 0;
1067
+ double delta_1, delta_2, delta_3, delta_4;
1068
+ double alpha_1, alpha_2, alpha_3, alpha_4;
1069
+ double v0,v1,v2,v3,v4;
1070
+
1071
+ for(i = 0; i < size; i++) {
1072
+ /* First initialize values, though this is very suboptimal */
1073
+ v0 = y[i];
1074
+ if(i == 0) {
1075
+ delta_1 = x[1] - x[0]; v1 = y[1];
1076
+ delta_2 = x[2] - x[0]; v2 = y[2];
1077
+ delta_3 = x[3] - x[0]; v3 = y[3];
1078
+ delta_4 = x[4] - x[0]; v4 = y[4];
1079
+ } else if(i == 1) {
1080
+ delta_1 = x[0] - x[1]; v1 = y[0];
1081
+ delta_2 = x[2] - x[1]; v2 = y[2];
1082
+ delta_3 = x[3] - x[1]; v3 = y[3];
1083
+ delta_4 = x[4] - x[1]; v4 = y[4];
1084
+ } else if(i == size - 2) {
1085
+ delta_1 = x[size-1] - x[size-2]; v1 = y[size-1];
1086
+ delta_2 = x[size-3] - x[size-2]; v2 = y[size-3];
1087
+ delta_3 = x[size-4] - x[size-2]; v3 = y[size-4];
1088
+ delta_4 = x[size-5] - x[size-2]; v4 = y[size-5];
1089
+ } else if(i == size - 1) {
1090
+ delta_1 = x[size-2] - x[size-1]; v1 = y[size-2];
1091
+ delta_2 = x[size-3] - x[size-1]; v2 = y[size-3];
1092
+ delta_3 = x[size-4] - x[size-1]; v3 = y[size-4];
1093
+ delta_4 = x[size-5] - x[size-1]; v4 = y[size-5];
1094
+ } else {
1095
+ delta_1 = x[i-2] - x[i]; v1 = y[i-2];
1096
+ delta_2 = x[i-1] - x[i]; v2 = y[i-1];
1097
+ delta_3 = x[i+2] - x[i]; v3 = y[i+2];
1098
+ delta_4 = x[i+1] - x[i]; v4 = y[i+1];
1099
+ }
1100
+ alpha_1 = -2 * (delta_2*delta_3 + delta_2*delta_4 + delta_3*delta_4)/
1101
+ (delta_1 * (delta_2 - delta_1) * (delta_3 - delta_1)
1102
+ * (delta_4 - delta_1));
1103
+ alpha_2 = -2 * (delta_1*delta_3 + delta_1*delta_4 + delta_3*delta_4)/
1104
+ (delta_2 * (delta_1 - delta_2) * (delta_3 - delta_2)
1105
+ * (delta_4 - delta_2));
1106
+ alpha_3 = -2 * (delta_2*delta_1 + delta_2*delta_4 + delta_1*delta_4)/
1107
+ (delta_3 * (delta_1 - delta_3) * (delta_2 - delta_3)
1108
+ * (delta_4 - delta_3));
1109
+ alpha_4 = -2 * (delta_2*delta_3 + delta_2*delta_1 + delta_3*delta_1)/
1110
+ (delta_4 * (delta_1 - delta_4) * (delta_2 - delta_4)
1111
+ * (delta_3 - delta_4));
1112
+ Dvector_Push_Double(derivative,
1113
+ -(alpha_1 + alpha_2 + alpha_3 + alpha_4) * v0 +
1114
+ alpha_1 * v1 + alpha_2 * v2 +
1115
+ alpha_3 * v3 + alpha_4 * v4);
1116
+ }
1117
+ return Function_Create(get_x_vector(self), derivative);
1118
+ }
1119
+
927
1120
  /*
928
1121
  Returns the number of points inside the function.
929
1122
  */
@@ -1026,6 +1219,418 @@ static VALUE function_bound_values(VALUE self,
1026
1219
  return Function_Create(x_out, y_out);
1027
1220
  }
1028
1221
 
1222
+ /* Reverses the function. Equivalent to doing
1223
+
1224
+ x.reverse!
1225
+ y.reverse!
1226
+
1227
+ excepted that it is faster (though not *much* faster).
1228
+ */
1229
+ static VALUE function_reverse(VALUE self)
1230
+ {
1231
+ long len = function_sanity_check(self);
1232
+ double *xs = Dvector_Data_for_Write(get_x_vector(self),NULL);
1233
+ double *ys = Dvector_Data_for_Write(get_y_vector(self),NULL);
1234
+
1235
+ double *xe = xs+len-1;
1236
+ double *ye = ys+len-1;
1237
+ double tmp;
1238
+ long i;
1239
+ for(i = 0; i < len/2; i++, xs++, ys++, xe--, ye--) {
1240
+ tmp = *xe; *xe = *xs; *xs = tmp;
1241
+ tmp = *ye; *ye = *ys; *ys = tmp;
1242
+ }
1243
+ return self;
1244
+ }
1245
+
1246
+ /* Computes the linear regression of the dataset. */
1247
+ static void reglin(const double *x, const double *y, long nb,
1248
+ double *a, double *b)
1249
+ {
1250
+ double sx = 0;
1251
+ double sy = 0;
1252
+ double sxx = 0;
1253
+ double sxy = 0;
1254
+ long i = 0;
1255
+ double det;
1256
+ for(i = 0; i < nb; i++, x++, y++) {
1257
+ sx += *x;
1258
+ sy += *y;
1259
+ sxx += *x * *x;
1260
+ sxy += *x * *y;
1261
+ }
1262
+ det = nb*sxx - sx*sx;
1263
+ if(det == 0) {
1264
+ *a = 0; /* Whichever, we only have one point */
1265
+ *b = sy/nb;
1266
+ }
1267
+ else {
1268
+ *a = (nb *sxy - sx*sy)/det;
1269
+ *b = (sxx * sy - sx * sxy)/(det);
1270
+ }
1271
+ }
1272
+
1273
+
1274
+ /*
1275
+ Performs a linear regression of the Function; returns the pair
1276
+ [ a, b]
1277
+ where f(x) = a*x + b
1278
+
1279
+ if the optional arguments _first_ and _last_ are provided, they
1280
+ represent the indices of the first and last elements.
1281
+ */
1282
+ static VALUE function_reglin(int argc, VALUE *argv, VALUE self)
1283
+ {
1284
+ long len = function_sanity_check(self);
1285
+ const double *x = Dvector_Data_for_Read(get_x_vector(self),NULL);
1286
+ const double *y = Dvector_Data_for_Read(get_y_vector(self),NULL);
1287
+ VALUE ret = rb_funcall(cDvector, idNew, 1, INT2NUM(2));
1288
+ double * dat = Dvector_Data_for_Write(ret, NULL);
1289
+ long nb;
1290
+ if(argc == 2) {
1291
+ long f = NUM2LONG(argv[0]);
1292
+ long l = NUM2LONG(argv[1]);
1293
+ if(f < 0)
1294
+ f = len + f;
1295
+ if(l < 0)
1296
+ l = len + l;
1297
+ x += f;
1298
+ y += f;
1299
+ nb = l - f;
1300
+ }
1301
+ else if(argc == 0) {
1302
+ nb = len;
1303
+ }
1304
+ else {
1305
+ rb_raise(rb_eArgError, "reglin should have 0 or 2 parameters");
1306
+ }
1307
+ reglin(x,y,nb,dat,dat+1);
1308
+ return ret;
1309
+ }
1310
+
1311
+
1312
+ /* Simply returns the sign */
1313
+ static int signof(double x)
1314
+ {
1315
+ if(x > 0)
1316
+ return 1;
1317
+ else if(x < 0)
1318
+ return -1;
1319
+ else
1320
+ return 0;
1321
+ }
1322
+
1323
+ /*
1324
+ Returns a "smoothed" value, according to the algorithm implented
1325
+ for "smooth" markers in Soas. See DOI:
1326
+ 10.1016/j.bioelechem.2009.02.010
1327
+
1328
+ Basically, we start at a given range, and narrow the range until
1329
+ the number of consecutive residuals of the same sign is lower than
1330
+ a quarter of the interval.
1331
+
1332
+ It works
1333
+
1334
+ */
1335
+ double smooth_pick(const double *x, const double *y,
1336
+ long nb, long idx, long range)
1337
+ {
1338
+ long left, right,i,nb_same_sign;
1339
+ double a,b;
1340
+ int last_sign;
1341
+ do {
1342
+ left = idx - range/2;
1343
+ if(left < 0)
1344
+ left = 0;
1345
+ right = idx + range/2;
1346
+ if(right > nb)
1347
+ right = nb;
1348
+ reglin(x+left, y+left, right-left,&a,&b);
1349
+ if(range == 6)
1350
+ break; /* We stop here */
1351
+ last_sign = 0;
1352
+ for(i = left; i < right; i++) {
1353
+ double residual = y[i] - a * x[i] - b;
1354
+ if(! last_sign)
1355
+ last_sign = signof(residual);
1356
+ else if(last_sign == signof(residual))
1357
+ nb_same_sign ++;
1358
+ else {
1359
+ nb_same_sign = 1;
1360
+ last_sign = signof(residual);
1361
+ }
1362
+ }
1363
+ if(nb_same_sign * 4 <= right - left)
1364
+ break;
1365
+ range -= (nb_same_sign * 4 -range)/2 + 2;
1366
+ if(range < 6)
1367
+ range = 6;
1368
+ } while(1);
1369
+ /* Now, we have a and b for the last range measured. */
1370
+ return a*x[idx] + b;
1371
+ }
1372
+
1373
+ /*
1374
+ Attempts to pick a smooth value for a point, according to the
1375
+ algorithm implented for "smooth" markers in Soas. See DOI:
1376
+ 10.1016/j.bioelechem.2009.02.010
1377
+
1378
+ Warning: be wary of this function as it will return a correct
1379
+ value only for rather noisy data !
1380
+ */
1381
+ static VALUE function_smooth_pick(int argc, VALUE *argv, VALUE self)
1382
+ {
1383
+ long len = function_sanity_check(self);
1384
+ const double *x = Dvector_Data_for_Read(get_x_vector(self),NULL);
1385
+ const double *y = Dvector_Data_for_Read(get_y_vector(self),NULL);
1386
+ long idx;
1387
+ long range;
1388
+ switch(argc) {
1389
+ case 2:
1390
+ range = NUM2LONG(argv[1]);
1391
+ break;
1392
+ case 1:
1393
+ range = len > 500 ? 50 : len/10;
1394
+ break;
1395
+ default:
1396
+ rb_raise(rb_eArgError, "smooth_a=t should have 1 or 2 parameters");
1397
+ }
1398
+ idx = NUM2LONG(argv[0]);
1399
+ if(idx < 0)
1400
+ idx = len + idx;
1401
+ return rb_float_new(smooth_pick(x,y,len,idx,range));
1402
+ }
1403
+
1404
+ /*
1405
+ Computes the convolution of the kernel with the dataset; the
1406
+ overall result is scaled
1407
+ */
1408
+ static double norm_convolve(const double *y, long len, long idx,
1409
+ const double * kernel, long klen, long kmid)
1410
+ {
1411
+ double ret = 0;
1412
+ long ki,yi;
1413
+ double norm = 0;
1414
+ yi = idx - kmid;
1415
+ /* We ensure we don't go */
1416
+ if(yi < 0) {
1417
+ ki -= yi;
1418
+ yi = 0;
1419
+ }
1420
+ for(; ki < klen && yi < len; yi++, ki++) {
1421
+ norm += kernel[ki];
1422
+ ret += kernel[ki] * y[yi];
1423
+ }
1424
+ return ret/norm;
1425
+ }
1426
+
1427
+ /*
1428
+ This functions tries to approximate the given data using a spline.
1429
+
1430
+ The algorithm is the following:
1431
+ * one starts with 3 points: 2 on the sides and one at the middle
1432
+ * then, we pick an interval between the points where the sum of the
1433
+ square of the residuals is the greatest, and place a point there.
1434
+ * then, we repeat until we reach a maximum number of points (_nbmax_)
1435
+
1436
+ Point positions are averaged over _nbavg_ using a gaussian-like
1437
+ filter.
1438
+
1439
+ Interpolation is returned into the _xi_, _yi_ and _y2i_ vectors
1440
+
1441
+ TODO: try to place the points more in the middle ? (provide a factor
1442
+ governing this)
1443
+
1444
+ TODO: use moments to decide of the precise position of the
1445
+ points ?
1446
+
1447
+ */
1448
+ static void internal_spline_approximation(const double *x, const double *y,
1449
+ long len,
1450
+ double *xi, double *yi,
1451
+ double *y2i,
1452
+ long nbmax,
1453
+ long nbavg,
1454
+ double * target)
1455
+ {
1456
+ double left_slope; /* Derivative on the left */
1457
+ double right_slope; /* Same on the right */
1458
+
1459
+ /* The gaussian kernel for the average */
1460
+ double kernel[nbavg];
1461
+
1462
+ /* The indices of the point where the residuals are maximal */
1463
+ long max_res_idx[nbmax-1];
1464
+
1465
+ /* The indices of the corner points*/
1466
+ long indices[nbmax];
1467
+
1468
+ long i;
1469
+ long cur_size = 3;
1470
+ double tmp,tmp2;
1471
+ /* Initialization of the kernel */
1472
+ long mid = nbavg/2; /* Middle of the kernel */
1473
+ for(i = 0,tmp=0; i < nbavg; i++) {
1474
+ tmp = (3.2 * (i - nbavg/2))/nbavg; /* Gives about 7% left on the
1475
+ side elements */
1476
+ tmp = exp(-tmp*tmp);
1477
+ kernel[i] = tmp;
1478
+ }
1479
+
1480
+ /* Left side */
1481
+ xi[0] = x[0];
1482
+ reglin(x,y, mid+1, &left_slope, &tmp2);
1483
+ yi[0] = left_slope * x[0] + tmp2;
1484
+ indices[0] = 0;
1485
+
1486
+ /* Middle */
1487
+ xi[1] = x[len/2];
1488
+ yi[1] = norm_convolve(y, len, len/2, kernel, nbavg, mid);
1489
+ indices[1] = len/2;
1490
+
1491
+ /* Right */
1492
+ xi[2] = x[len-1];
1493
+ reglin(x+(len-(mid+2)),y + (len-(mid+2)), mid+1, &right_slope, &tmp2);
1494
+ yi[2] = right_slope * x[len-1] + tmp2;
1495
+ indices[2] = len - 1;
1496
+
1497
+ do {
1498
+ long cur_seg;
1499
+ long max_res_seg = 0; /* The segment where the residuals are
1500
+ the greatest */
1501
+ double max_res = 0;
1502
+
1503
+ long max_deviation_seg = 0; /* The segment where the deviation
1504
+ (square of the average) is the
1505
+ greatest */
1506
+ double max_deviation = 0;
1507
+
1508
+ long chosen_seg; /* The segment in which we'll add a point */
1509
+ /* Compute interpolation */
1510
+ function_fill_second_derivatives(cur_size, xi, yi, y2i,
1511
+ left_slope, right_slope);
1512
+
1513
+
1514
+ /* We stop here if we have reached the max number and we're not
1515
+ interested in Y values */
1516
+ if(cur_size >= nbmax && !target)
1517
+ break;
1518
+
1519
+ /* Now we compute the residuals */
1520
+ for(cur_seg = 0; cur_seg < cur_size - 1; cur_seg++) {
1521
+ double residuals = 0;
1522
+ double a,b,int_y,delta,h = xi[cur_seg+1] - xi[cur_seg];
1523
+ double imr = 0; /* Internal max residuals */
1524
+ double deviation = 0;
1525
+ /* printf("seg: %ld/%ld indices %ld -- %ld\n", cur_seg, cur_size-1, */
1526
+ /* indices[cur_seg], indices[cur_seg+1]); */
1527
+ for(i = indices[cur_seg] + 1; i < indices[cur_seg+1]; i++) {
1528
+ a = (xi[cur_seg+1] - x[i])/h;
1529
+ b = (x[i] - xi[cur_seg])/h;
1530
+ int_y = a * yi[cur_seg] + b * yi[cur_seg + 1]
1531
+ + ((a*a*a - a) * y2i[cur_seg] +
1532
+ (b*b*b - b) * y2i[cur_seg + 1]) *
1533
+ (h * h)/6.0;
1534
+ if(target) /* We set the value if applicable. */
1535
+ target[i] = int_y;
1536
+ delta = int_y - y[i];
1537
+ deviation += delta;
1538
+ delta *= delta;
1539
+ residuals += delta;
1540
+ if(delta > imr) {
1541
+ imr = delta;
1542
+ max_res_idx[cur_seg] = i;
1543
+ }
1544
+ }
1545
+ if(max_res < residuals) {
1546
+ max_res = residuals;
1547
+ max_res_seg = cur_seg;
1548
+ }
1549
+ deviation *= deviation;
1550
+ if(deviation > max_deviation) {
1551
+ max_deviation_seg = cur_seg;
1552
+ max_deviation = deviation;
1553
+ }
1554
+ /* printf(" -> residuals %g\n", cur_seg, cur_size-1, */
1555
+ /* residuals); */
1556
+ }
1557
+ /* printf("-> max residuals at segment %d\n", max_res_seg); */
1558
+
1559
+ if(cur_size >= nbmax)
1560
+ break;
1561
+
1562
+
1563
+ /* OK, so now we know in which segment the residuals are the
1564
+ greatest, and which point of this segment is holds the max
1565
+ residuals. So we just add a point there */
1566
+ chosen_seg = max_deviation_seg;
1567
+
1568
+ /* We shift the positions */
1569
+ for(i = cur_size; i > chosen_seg + 1; i--) {
1570
+ xi[i] = xi[i-1];
1571
+ yi[i] = yi[i-1];
1572
+ y2i[i] = y2i[i-1];
1573
+ indices[i] = indices[i-1];
1574
+ }
1575
+ cur_size++;
1576
+ xi[chosen_seg + 1] = x[max_res_idx[chosen_seg]];
1577
+ yi[chosen_seg + 1] = norm_convolve(y, len, max_res_idx[chosen_seg],
1578
+ kernel, nbavg, mid);
1579
+ indices[chosen_seg + 1] = max_res_idx[chosen_seg];
1580
+ } while(1);
1581
+
1582
+ /* Now fill in the missing values of y, since we do not evaluate them */
1583
+ if(target) {
1584
+ for(i = 0; i < nbmax; i++)
1585
+ target[indices[i]] = yi[i];
1586
+ }
1587
+
1588
+
1589
+ }
1590
+
1591
+ /*
1592
+ Filters the Function through interpolation. _params_ holds a
1593
+ hash with the following values:
1594
+ * ??
1595
+
1596
+ It returns a hash.
1597
+ */
1598
+ static VALUE function_spline_approximation(VALUE self, VALUE params)
1599
+ {
1600
+ long len = function_sanity_check(self);
1601
+ const double *x = Dvector_Data_for_Read(get_x_vector(self),NULL);
1602
+ const double *y = Dvector_Data_for_Read(get_y_vector(self),NULL);
1603
+ VALUE xiret, yiret, y2iret, yintret,ret;
1604
+ double * xi, *yi, *y2i, *yint;
1605
+ long nbavg = 9;
1606
+ long nbmax = 20;
1607
+ if(RTEST(rb_hash_aref(params, rb_str_new2("number"))))
1608
+ nbmax = NUM2LONG(rb_hash_aref(params, rb_str_new2("number")));
1609
+ if(RTEST(rb_hash_aref(params, rb_str_new2("average"))))
1610
+ nbavg = NUM2LONG(rb_hash_aref(params, rb_str_new2("average")));
1611
+
1612
+ /* TODO: add checks that monotonic and growing. */
1613
+
1614
+ xiret = rb_funcall(cDvector, idNew, 1, INT2NUM(nbmax));
1615
+ xi = Dvector_Data_for_Write(xiret, NULL);
1616
+ yiret = rb_funcall(cDvector, idNew, 1, INT2NUM(nbmax));
1617
+ yi = Dvector_Data_for_Write(yiret, NULL);
1618
+ y2iret = rb_funcall(cDvector, idNew, 1, INT2NUM(nbmax));
1619
+ y2i = Dvector_Data_for_Write(y2iret, NULL);
1620
+ yintret = rb_funcall(cDvector, idNew, 1, INT2NUM(len));
1621
+ yint = Dvector_Data_for_Write(yintret, NULL);
1622
+
1623
+ internal_spline_approximation(x, y, len, xi, yi, y2i,
1624
+ nbmax, nbavg, yint);
1625
+ ret = rb_hash_new();
1626
+ rb_hash_aset(ret, rb_str_new2("xi"), xiret);
1627
+ rb_hash_aset(ret, rb_str_new2("yi"), yiret);
1628
+ rb_hash_aset(ret, rb_str_new2("y2i"), y2iret);
1629
+ rb_hash_aset(ret, rb_str_new2("y"), yintret);
1630
+ return ret;
1631
+ }
1632
+
1633
+
1029
1634
  /*
1030
1635
  Document-class: Dobjects::Function
1031
1636
 
@@ -1035,16 +1640,21 @@ static VALUE function_bound_values(VALUE self,
1035
1640
  - facilities for sorting the X while keeping the Y matching, with #sort and
1036
1641
  Function.joint_sort;
1037
1642
  - to check if X data is sorted: #sorted?, #is_sorted;
1038
- - interpolation, with #compute_spline, #compute_spline_data and #interpolate;
1643
+ - interpolation, with #compute_spline, #compute_spline_data and #interpolate
1039
1644
  - some functions for data access : #x, #y, #point;
1040
- - some utiliy functions: #split_monotonic, #strip_nan;
1645
+ - some utiliy functions: #split_monotonic, #strip_nan, #reverse!
1041
1646
  - data inspection: #min, #max;
1042
- - some computational functions: #integrate, #primitive, #derivative.
1647
+ - some computational functions: #integrate, #primitive, #derivative,
1648
+ and now 4th-order accurate first and second derivatives: #diff_5p
1649
+ and #diff2_5p
1043
1650
  - utility for fuzzy operations, when the X values of two functions
1044
1651
  differ, but only slightly, of when points are missing:
1045
1652
  #fuzzy_sub!
1653
+ - linear regression #reglin
1654
+ - a function to approximate data using a low-order spline:
1655
+ #spline_approximation
1046
1656
 
1047
- And getting bigger everyday...
1657
+ And getting bigger (almost) everyday...
1048
1658
  */
1049
1659
  void Init_Function()
1050
1660
  {
@@ -1059,6 +1669,7 @@ void Init_Function()
1059
1669
 
1060
1670
  rb_define_method(cFunction, "initialize", function_initialize, 2);
1061
1671
  rb_define_method(cFunction, "sorted?", function_is_sorted, 0);
1672
+ rb_define_method(cFunction, "reverse!", function_reverse, 0);
1062
1673
  rb_define_alias(cFunction, "is_sorted", "sorted?");
1063
1674
 
1064
1675
  rb_define_singleton_method(cFunction, "joint_sort", function_joint_sort, 2);
@@ -1074,15 +1685,24 @@ void Init_Function()
1074
1685
  function_interpolate, 1);
1075
1686
  rb_define_method(cFunction, "make_interpolant",
1076
1687
  function_make_interpolant, 0);
1688
+ rb_define_method(cFunction, "spline_approximation",
1689
+ function_spline_approximation, 1);
1690
+
1077
1691
 
1078
1692
  /* access to data */
1079
1693
  rb_define_method(cFunction, "point", function_point, 1);
1694
+ rb_define_method(cFunction, "[]", function_point, 1);
1080
1695
  rb_define_method(cFunction, "x", get_x_vector, 0);
1081
1696
  rb_define_method(cFunction, "y", get_y_vector, 0);
1082
1697
 
1083
1698
 
1084
1699
  rb_define_method(cFunction, "size", function_size, 0);
1085
1700
  rb_define_alias(cFunction, "length", "size");
1701
+
1702
+ /* Soas-like functions ;-) */
1703
+ rb_define_method(cFunction, "reglin", function_reglin, -1);
1704
+ rb_define_method(cFunction, "smooth_pick", function_smooth_pick, -1);
1705
+
1086
1706
 
1087
1707
 
1088
1708
  /* iterator */
@@ -1092,8 +1712,9 @@ void Init_Function()
1092
1712
  /* stripping of NaNs */
1093
1713
  rb_define_method(cFunction, "strip_nan", function_strip_nan, 0);
1094
1714
 
1095
- /* split into monotonic subfunctions */
1715
+ /* split into subfunctions with given properties */
1096
1716
  rb_define_method(cFunction, "split_monotonic", function_split_monotonic, 0);
1717
+ rb_define_method(cFunction, "split_on_nan", function_split_on_nan, 1);
1097
1718
 
1098
1719
  /* integration between two integer boundaries */
1099
1720
  rb_define_method(cFunction, "integrate", function_integrate, -1);
@@ -1102,6 +1723,10 @@ void Init_Function()
1102
1723
  /* derivative */
1103
1724
  rb_define_method(cFunction, "derivative", function_derivative, 0);
1104
1725
 
1726
+ /* 5-points derivatives */
1727
+ rb_define_method(cFunction, "diff_5p", function_diff_5p, 0);
1728
+ rb_define_method(cFunction, "diff2_5p", function_diff2_5p, 0);
1729
+
1105
1730
  /* distance to a point */
1106
1731
  rb_define_method(cFunction, "distance", function_distance, -1);
1107
1732