tioga 1.11 → 1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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