bz_discr.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #include "bz_discr.h"
  2. #include <stdio.h>
  3. #define INT_EPS 1e-12
  4. // define SPAM to get trace output
  5. #ifdef SPAM
  6. #define SPIM
  7. #endif
  8. // SPIM is more benign
  9. int comparedim;
  10. double globaldiscr;
  11. double fmax(double a,double b)
  12. {
  13. return ((a)>(b))?(a):(b);
  14. }
  15. // argument is pointer to pointsetmember, i.e. double **.
  16. int cmpkeyk(double **pt1, double **pt2)
  17. {
  18. double a=(*pt1)[comparedim], b=(*pt2)[comparedim];
  19. if (a<b)
  20. return -1;
  21. else if (a>b)
  22. return 1;
  23. return 0;
  24. }
  25. int intpoints(double **pointset, int dim, int npoints, double *base)
  26. {
  27. int n=npoints,i,j;
  28. for (i=0; i<npoints; i++) {
  29. for (j=0; j<dim; j++) {
  30. if (pointset[i][j] >= (base[j]-INT_EPS)) {
  31. n--;
  32. break;
  33. }
  34. }
  35. }
  36. return n;
  37. }
  38. // Fixes one dimension at a time, each dimension defined by a point (which
  39. // must be on the boundary of the box). Maintains list of points that are
  40. // still possible (first rempoints points) and smallest base compatible with
  41. // earlier dimension choices (boundary points must not be excluded).
  42. double int_poly_discr(double **pointset, int dim, int npoints, int rempoints,
  43. double *base, int cdim)
  44. {
  45. double discr,maxdiscr=0.0, basecopy[dim], *ptcopy[rempoints];
  46. int i,j, resort=0;
  47. #ifdef SPAM
  48. fprintf(stderr, "Dim %d points %d/%d base (%g", cdim, rempoints, npoints, base[0]);
  49. for (i=1; i<dim; i++)
  50. fprintf(stderr, ", %g", base[i]);
  51. fprintf(stderr, ")\n");
  52. #endif
  53. if (cdim==dim) {
  54. discr = 1.0;
  55. for (i=0; i<dim; i++)
  56. discr *= base[i];
  57. maxdiscr = fmax((double)rempoints/npoints-discr,
  58. discr-(double)intpoints(pointset, dim, rempoints, base)/npoints);
  59. #ifdef SPAM
  60. fprintf(stderr, "Volume %g point-share %g--%g -> discr. %g\n",
  61. discr, (double)intpoints(pointset, dim, rempoints, base)/npoints,
  62. (double)rempoints/npoints, maxdiscr);
  63. #endif
  64. if (maxdiscr > globaldiscr) {
  65. globaldiscr=maxdiscr;
  66. #ifdef SPIM
  67. fprintf(stderr, "Improved to %g\n", globaldiscr);
  68. #endif
  69. }
  70. return maxdiscr;
  71. }
  72. for (i=cdim; i<dim; i++)
  73. basecopy[i]=base[i];
  74. comparedim = cdim;
  75. qsort(pointset, rempoints, sizeof(double *), cmpkeyk);
  76. #ifdef SPAM
  77. for (i=0; i<rempoints; i++) {
  78. fprintf(stderr, "Point %04d: (%g", i, pointset[i][0]);
  79. for (j=1; j<dim; j++)
  80. fprintf(stderr, ", %g", pointset[i][j]);
  81. fprintf(stderr, ")\n");
  82. }
  83. #endif
  84. for (i=0; i<rempoints; i++) {
  85. if (!cdim)
  86. fprintf(stderr, "%d/%d\n", i, rempoints);
  87. if (pointset[i][cdim] < base[cdim]-INT_EPS) {
  88. #ifdef SPAM
  89. fprintf(stderr, "Skip'ng %d: coord too small\n", i);
  90. #endif
  91. continue;
  92. }
  93. base[cdim]=pointset[i][cdim];
  94. for (j=cdim+1; j<dim; j++) {
  95. if (pointset[i][j] > base[j])
  96. base[j]=pointset[i][j];
  97. }
  98. if ((i && (pointset[i-1][cdim] == pointset[i][cdim])) ||
  99. (((i+1)<rempoints) &&
  100. (pointset[i+1][cdim] == pointset[i][cdim]))) {
  101. resort=1;
  102. for (j=0; j<rempoints; j++)
  103. ptcopy[j]=pointset[j];
  104. }
  105. j=i+1;
  106. while ((j < rempoints) && (pointset[j-1][cdim]==pointset[j][cdim]))
  107. j++;
  108. #ifdef SPAM
  109. fprintf(stderr, "Calling %d\n", i);
  110. #endif
  111. discr = int_poly_discr(pointset, dim, npoints, j, base, cdim+1);
  112. if (discr > maxdiscr)
  113. maxdiscr=discr;
  114. if (resort) {
  115. for (j=0; j<rempoints; j++)
  116. pointset[j]=ptcopy[j];
  117. resort=0;
  118. }
  119. for (j=cdim+1; j<dim; j++)
  120. base[j]=basecopy[j];
  121. }
  122. #ifdef SPAM
  123. fprintf(stderr, "Calling 1.0\n");
  124. #endif
  125. if (!cdim)
  126. fprintf(stderr, "Trying 1.0\n");
  127. base[cdim]=1.0;
  128. discr = int_poly_discr(pointset, dim, npoints, rempoints, base, cdim+1);
  129. for (j=cdim; j<dim; j++)
  130. base[j]=basecopy[j];
  131. if (discr > maxdiscr)
  132. maxdiscr=discr;
  133. return maxdiscr;
  134. }
  135. double poly_discr(double **pointset, int dim, int npoints)
  136. {
  137. double *base, discr;
  138. int i;
  139. globaldiscr=0;
  140. base = malloc(dim*sizeof(double));
  141. for (i=0; i<dim; i++)
  142. base[i]=0.0;
  143. discr = int_poly_discr(pointset, dim, npoints, npoints, base, 0);
  144. free(base);
  145. return discr;
  146. }