algorithm.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. #include "simple/geom/algorithm.hpp"
  2. #include <cmath>
  3. #include <cassert>
  4. #include <vector>
  5. #include "simple/support/math.hpp"
  6. using namespace simple;
  7. using geom::vector;
  8. using float4 = vector<float, 4>;
  9. using int4 = vector<int, 4>;
  10. void Basic()
  11. {
  12. int4 p (1, 2, 3, 4);
  13. int4 p2 (4, 3, 2, 1);
  14. assert( int4(1, 2, 2, 1) == geom::min(p, p2) );
  15. assert( int4(4, 3, 3, 4) == geom::max(p, p2) );
  16. int4 p3;
  17. (p3 = p).min(p2);
  18. assert( int4(1, 2, 2, 1) == p3 );
  19. (p3 = p).max(p2);
  20. assert( int4(4, 3, 3, 4) == p3 );
  21. p = -p;
  22. assert( int4(-1, 2, 2, -3) == geom::clamp(int4(-10, 2, 3, -3), p, p2) );
  23. assert( int4(0, -2, -1, 1) == geom::clamp(int4(0, -3, -1, 10), p, p2) );
  24. assert( int4(3, -1, -2, 0) == geom::clamp(int4(3, -1, -2, 0), p, p2) );
  25. assert( int4(-1, 3, -3, 1) == geom::clamp(int4(-3, 7, -5, 3), p, p2) );
  26. (p3 = int4(-10, 2, 3, -3)).clamp(p,p2);
  27. assert( int4(-1, 2, 2, -3) == p3 );
  28. (p3 = int4(0, -3, -1, 10)).clamp(p,p2);
  29. assert( int4(0, -2, -1, 1) == p3);
  30. (p3 = int4(3, -1, -2, 0)).clamp(p,p2);
  31. assert( int4(3, -1, -2, 0) == p3);
  32. (p3 = int4(-3, 7, -5, 3)).clamp(p,p2);
  33. assert( int4(-1, 3, -3, 1) == p3);
  34. float4 fp (1.1f, 3.4f, 4.5f, 8.9f);
  35. assert( float4(1.f, 3.f, 4.f, 8.f) == trunc(fp) );
  36. assert( float4(1.f, 3.f, 4.f, 8.f) == floor(fp) );
  37. assert( float4(2.f, 4.f, 5.f, 9.f) == ceil(fp) );
  38. assert( float4(1.f, 3.f, 5.f, 9.f) == round(fp) );
  39. float4 fp2;
  40. (fp2 = fp).trunc();
  41. assert( float4(1.f, 3.f, 4.f, 8.f) == fp2 );
  42. (fp2 = fp).floor();
  43. assert( float4(1.f, 3.f, 4.f, 8.f) == fp2 );
  44. (fp2 = fp).ceil();
  45. assert( float4(2.f, 4.f, 5.f, 9.f) == fp2 );
  46. (fp2 = fp).round();
  47. assert( float4(1.f, 3.f, 5.f, 9.f) == fp2 );
  48. fp = float4(1.1f, -3.4f, 4.5f, -8.9f);
  49. assert( float4(1.f, -3.f, 4.f, -8.f) == trunc(fp) );
  50. assert( float4(1.f, -4.f, 4.f, -9.f) == floor(fp) );
  51. assert( float4(2.f, -3.f, 5.f, -8.f) == ceil(fp) );
  52. assert( float4(1.f, -3.f, 5.f, -9.f) == round(fp) );
  53. (fp2 = fp).trunc();
  54. assert( float4(1.f, -3.f, 4.f, -8.f) == fp2 );
  55. (fp2 = fp).floor();
  56. assert( float4(1.f, -4.f, 4.f, -9.f) == fp2 );
  57. (fp2 = fp).ceil();
  58. assert( float4(2.f, -3.f, 5.f, -8.f) == fp2 );
  59. (fp2 = fp).round();
  60. assert( float4(1.f, -3.f, 5.f, -9.f) == fp2 );
  61. int4 p4 (2, 6, 3, 0);
  62. assert( p4.magnitude() == 49);
  63. assert( p4.quadrance() == 49);
  64. assert( p4.length() == 7 );
  65. assert( magnitude(p4) == 49);
  66. assert( quadrance(p4) == 49);
  67. assert( length(p4) == 7 );
  68. assert( signum(int4(-12, 34, 0, 1)) == int4(-1, 1, 0, 1) );
  69. assert( signum(int4(9, -13, -77, 0)) == int4(1, -1, -1, 0) );
  70. assert( signum(float4(-.3f, .12f, .0f, +.0f)) == float4(-1.f, 1.f, 0.f, 0.f) );
  71. (p3 = int4(-12, 34, 0, 1)).signum();
  72. assert( int4(-1, 1, 0, 1) == p3 );
  73. (p3 = int4(9, -13, -77, 0)).signum();
  74. assert( int4(1, -1, -1, 0) == p3 );
  75. (fp2 = float4(-.3f, .12f, .0f, +.0f)).signum();
  76. assert( float4(-1.f, 1.f, 0.f, 0.f) == fp2 );
  77. }
  78. void MultidimentionalIteration()
  79. {
  80. using int3 = vector<int, 3>;
  81. const auto lower = int3{13,3,-20};
  82. const auto upper = int3{45,32,12};
  83. std::vector<int3> test_data;
  84. test_data.reserve(10000);
  85. std::vector<int3> data;
  86. data.reserve(10000);
  87. for(int k = lower[2]; k < upper[2]; ++k)
  88. for(int j = lower[1]; j < upper[1]; ++j)
  89. for(int i = lower[0]; i < upper[0]; ++i)
  90. test_data.push_back({i,j,k});
  91. loop(lower, upper, int3::one(), [&data](auto& i)
  92. {
  93. data.push_back(i);
  94. });
  95. // assert(data == test_data); // libcxx just can't contextually convertable to bool
  96. // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2167r3.html
  97. // this works though... so you can... you just don't wanna...
  98. assert(std::equal(data.begin(), data.end(), test_data.begin(), test_data.end(), std::equal_to<>{}));
  99. test_data.clear();
  100. data.clear();
  101. auto step = int3{1,2,3};
  102. for(int k = lower[2]; k < upper[2]; k += step[2])
  103. for(int j = lower[1]; j < upper[1]; j += step[1])
  104. for(int i = lower[0]; i < upper[0]; i += step[0])
  105. test_data.push_back({i,j,k});
  106. loop(lower, upper, step, [&data](auto& i)
  107. {
  108. data.push_back(i);
  109. });
  110. // assert(data == test_data); // libcxx just can't contextually convertable to bool
  111. // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2167r3.html
  112. // this works though... so you can... you just don't wanna...
  113. assert(std::equal(data.begin(), data.end(), test_data.begin(), test_data.end(), std::equal_to<>{}));
  114. }
  115. struct rational
  116. {
  117. long long num = 0;
  118. long long den = 1;
  119. constexpr
  120. bool operator < (const rational& other) const
  121. { return num * other.den < other.num * den; }
  122. constexpr
  123. bool operator == (const rational& other) const
  124. { return num * other.den == other.num * den; }
  125. constexpr
  126. rational operator+() const { return *this; }
  127. constexpr
  128. rational operator*(const rational& other) const
  129. { return {num*other.num, den*other.den}; }
  130. constexpr
  131. void normalize()
  132. {
  133. auto gcd = std::gcd(num, den);
  134. num /= gcd;
  135. den /= gcd;
  136. }
  137. constexpr
  138. rational& operator/=(const rational& other)
  139. {
  140. den *= other.num;
  141. num *= other.den;
  142. normalize();
  143. return *this;
  144. }
  145. constexpr
  146. rational& operator-=(const rational& other)
  147. {
  148. num *= other.den;
  149. num -= other.num * den;
  150. den *= other.den;
  151. normalize();
  152. return *this;
  153. }
  154. constexpr
  155. rational& operator+=(const rational& other)
  156. {
  157. num *= other.den;
  158. num += other.num * den;
  159. den *= other.den;
  160. normalize();
  161. return *this;
  162. }
  163. constexpr
  164. rational operator+(const rational& other) const
  165. {
  166. return rational(*this)+=other;;
  167. }
  168. };
  169. constexpr rational abs(rational r)
  170. {
  171. return {support::abs(r.num) , support::abs(r.den)};
  172. }
  173. void MatrixElimination()
  174. {
  175. using r = rational;
  176. constexpr auto inverse = gauss_jordan_elimination(vector(
  177. vector(r{2},r{0},r{3}, r{1},r{0},r{0}),
  178. vector(r{4},r{5},r{6}, r{0},r{1},r{0}),
  179. vector(r{7},r{8},r{9}, r{0},r{0},r{1})
  180. )).transformed(&vector<r,6>::last<3>);
  181. static_assert ( vector(r{2},r{0},r{3})(inverse) ==
  182. vector(r{17,5}, r{-4,5}, r{-8,5}) );
  183. assert( gauss_jordan_elimination(
  184. vector(
  185. vector(r{2},r{1},r{0}, r{1},r{0},r{0}),
  186. vector(r{0},r{2},r{0}, r{0},r{1},r{0}),
  187. vector(r{2},r{0},r{1}, r{0},r{0},r{1})
  188. ))
  189. ==
  190. vector(
  191. vector(r{1},r{0},r{0}, r{1,2},r{-1,4},r{0}),
  192. vector(r{0},r{1},r{0}, r{0}, r{1,2}, r{0}),
  193. vector(r{0},r{0},r{1}, r{-1}, r{1,2}, r{1})
  194. )
  195. );
  196. assert( gauss_jordan_elimination(
  197. vector(
  198. vector(r{1},r{1},r{0}, r{1},r{0},r{0}),
  199. vector(r{0},r{1},r{0}, r{0},r{1},r{0}),
  200. vector(r{2},r{1},r{1}, r{0},r{0},r{1})
  201. ))
  202. ==
  203. vector(
  204. vector(r{1},r{0},r{0}, r{1}, r{-1},r{0}),
  205. vector(r{0},r{1},r{0}, r{0}, r{1}, r{0}),
  206. vector(r{0},r{0},r{1}, r{-2},r{1}, r{1})
  207. )
  208. );
  209. assert( gauss_jordan_elimination(
  210. vector(
  211. vector(r{2},r{1},r{0}, r{1},r{0},r{0}),
  212. vector(r{2},r{0},r{0}, r{0},r{1},r{0}),
  213. vector(r{2},r{0},r{1}, r{0},r{0},r{1})
  214. ))
  215. ==
  216. vector(
  217. vector(r{1},r{0},r{0}, r{0},r{1,2},r{0}),
  218. vector(r{0},r{1},r{0}, r{1},r{-1}, r{0}),
  219. vector(r{0},r{0},r{1}, r{0},r{-1}, r{1})
  220. )
  221. );
  222. }
  223. // https://github.com/ClaasBontus/miterator
  224. void Miterator()
  225. {
  226. {
  227. std::vector v1{ 1, -1, 2, -2, 3, -3, 4, -4 };
  228. std::vector v2{ 5, 5, 6, 6 };
  229. int result= 0;
  230. // I would like to write
  231. // for( auto const &[i1,i2] : support::range{
  232. // vector(v1.begin(), v2.begin()),
  233. // vector(v1.end(), v2.end())
  234. // })
  235. // but alas operator!= is disjunctive, it is true if any element does not
  236. // equal, this makes sense logically but is no good for range checks, hence
  237. // have to use naked for, to convert it to a conjunction
  238. // IMHO this is a problem with range based for (and standard library algos
  239. // as well) overusing the operator, equivalence is much more subtle and
  240. // interesting thing and shouldn't be reserved for range checks, I would
  241. // advocate for a separate customization point called reaches(or touches)
  242. // that defaults to operator== and is then negated explicitly, and in this
  243. // case I could override it with to_disjunction(a == b), without
  244. // compromising the basic logic of the equivalence operators
  245. for(auto begin = vector(v1.begin(), v2.begin()),
  246. end = vector(v1.end(), v2.end());
  247. to_conjunction(begin != end);
  248. ++begin)
  249. {
  250. auto [i1, i2] = *begin;
  251. if( i1 <= 0 || i2 <= 0 ) continue;
  252. result += i1 * i2;
  253. }
  254. assert( result == (1*5 + 2*6) );
  255. // another gripe I have with it since times immemorial is sometimes you
  256. // want to take bigger strides forward, += some step instead of increment,
  257. // so you gotta check < in case you overshoot the end... now I know in many
  258. // cases you aren't even allowed to overshoot, but sometimes you are...
  259. // (incidentally < would actually work for our vector here as well, but
  260. // alas its definition is a pure heresy... it makes the most sense and it
  261. // works often enough to be useful... but not a total order you see...
  262. // unacceptable heresy...)
  263. }
  264. // exceeept... oftentimes we know the two ranges are the same size... then
  265. // this can be useful, without any massive reforms or type system
  266. // shamanisms... in fact, this whole different size ranges thing seems
  267. // quite odd when you think about it, how often does that come up, vs exact
  268. // correspondence?? so yeah I think this makes enough sense... after
  269. // all, riding on the keen edge of safety is the c++ way...
  270. {
  271. std::vector v1{ 1, -1, 2, -2 };
  272. std::vector v2{ 5, 5, 6, 6 };
  273. int result= 0;
  274. for( auto&& [i1,i2] : support::range{
  275. vector(v1.begin(), v2.begin()),
  276. vector(v1.end(), v2.end())
  277. })
  278. {
  279. if( i1 <= 0 || i2 <= 0 ) continue;
  280. result += i1 * i2;
  281. i1 += 10;
  282. i2 += 20;
  283. }
  284. assert( result == (1*5 + 2*6) );
  285. assert(( v1 == std::vector{11, -1, 12, -2} ));
  286. assert(( v2 == std::vector{25, 5, 26, 6} ));
  287. }
  288. }
  289. int main()
  290. {
  291. Basic();
  292. MultidimentionalIteration();
  293. MatrixElimination();
  294. Miterator();
  295. }