NaiveIRGenerator.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. #include "NaiveIRGenerator.h"
  2. #include <omp.h>
  3. using mnd::NaiveIRGenerator;
  4. namespace mnd
  5. {
  6. template class NaiveIRGenerator<float>;
  7. template class NaiveIRGenerator<double>;
  8. template class NaiveIRGenerator<mnd::DoubleDouble>;
  9. template class NaiveIRGenerator<mnd::QuadDouble>;
  10. }
  11. namespace mnd::eval
  12. {
  13. struct Load { size_t index; };
  14. struct Store
  15. {
  16. size_t index;
  17. std::unique_ptr<EvalNode> v;
  18. };
  19. struct BinaryOperation
  20. {
  21. std::unique_ptr<EvalNode> a;
  22. std::unique_ptr<EvalNode> b;
  23. };
  24. struct UnaryOperation
  25. {
  26. std::unique_ptr<EvalNode> a;
  27. };
  28. struct Add : BinaryOperation {};
  29. struct Sub : BinaryOperation {};
  30. struct Mul : BinaryOperation {};
  31. struct Div : BinaryOperation {};
  32. struct Neg : UnaryOperation {};
  33. struct Atan2 : BinaryOperation {};
  34. struct Pow : BinaryOperation {};
  35. struct Cos : UnaryOperation {};
  36. struct Sin : UnaryOperation {};
  37. struct Exp : UnaryOperation {};
  38. struct Ln : UnaryOperation {};
  39. using namespace mnd;
  40. using namespace mnd::ir;
  41. template<typename T>
  42. struct ToEvalVisitor
  43. {
  44. EvalStruct<T>& es;
  45. std::unique_ptr<EvalNode> visit(ir::Node* f)
  46. {
  47. std::any& nodeData = getNodeData(f);
  48. if (EvalNode** en = std::any_cast<EvalNode*>(&nodeData)) {
  49. size_t tmpStore;
  50. if (Store* s = std::get_if<Store>(*en)) {
  51. tmpStore = s->index;
  52. }
  53. else {
  54. tmpStore = createTemp();
  55. EvalNode store = Store{ tmpStore, std::make_unique<EvalNode>(std::move(**en)) };
  56. **en = std::move(store);
  57. }
  58. auto l = std::make_unique<EvalNode>(Load{ tmpStore });
  59. setNodeData(f, l.get());
  60. return l;
  61. }
  62. EvalNode n = std::visit(*this, *f);
  63. auto r = std::make_unique<EvalNode>(std::move(n));
  64. setNodeData(f, r.get());
  65. return r;
  66. }
  67. std::any& getNodeData(ir::Node* n)
  68. {
  69. return std::visit([](auto& x) -> std::any& { return x.nodeData; }, *n);
  70. }
  71. void setNodeData(ir::Node* n, EvalNode* en)
  72. {
  73. std::visit([en](auto& x) { x.nodeData = en; }, *n);
  74. }
  75. size_t createTemp(void)
  76. {
  77. es.variables.push_back(0);
  78. return es.variables.size() - 1;
  79. }
  80. size_t createConstant(mnd::Real& value)
  81. {
  82. es.variables.push_back(mnd::convert<T>(value));
  83. return es.variables.size() - 1;
  84. }
  85. size_t createVariable(std::string& value)
  86. {
  87. es.variables.push_back(0);
  88. es.variableNames.emplace(value, es.variables.size() - 1);
  89. return es.variables.size() - 1;
  90. }
  91. EvalNode operator()(ir::Constant& x) {
  92. return Load{ createConstant(x.value) };
  93. }
  94. EvalNode operator()(ir::Variable& x) {
  95. return Load{ createVariable(x.name) };
  96. }
  97. EvalNode operator()(ir::Addition& x) {
  98. return Add{ visit(x.left), visit(x.right) };
  99. }
  100. EvalNode operator()(ir::Subtraction& x) {
  101. return Sub{ visit(x.left), visit(x.right) };
  102. }
  103. EvalNode operator()(ir::Multiplication& x) {
  104. return Mul{ visit(x.left), visit(x.right) };
  105. }
  106. EvalNode operator()(ir::Division& x) {
  107. return Div{ visit(x.left), visit(x.right) };
  108. }
  109. EvalNode operator()(ir::Negation& x) {
  110. return Neg{ visit(x.value) };
  111. }
  112. EvalNode operator()(ir::Atan2& x) {
  113. return Atan2{ visit(x.left), visit(x.right) };
  114. }
  115. EvalNode operator()(ir::Pow& x) {
  116. return Pow{ visit(x.left), visit(x.right) };
  117. }
  118. EvalNode operator()(ir::Cos& x) {
  119. return Cos{ visit(x.value) };
  120. }
  121. EvalNode operator()(ir::Sin& x) {
  122. return Sin{ visit(x.value) };
  123. }
  124. EvalNode operator()(ir::Exp& x) {
  125. return Exp{ visit(x.value) };
  126. }
  127. EvalNode operator()(ir::Ln& x) {
  128. return Ln{ visit(x.value) };
  129. }
  130. };
  131. template<typename T>
  132. struct EvalVisitor
  133. {
  134. mnd::eval::EvalStruct<T>& es;
  135. T visit(const EvalNode& en) {
  136. return std::visit(*this, en);
  137. }
  138. T operator()(const Load& x) {
  139. return es.variables[x.index];
  140. }
  141. T operator()(const Store& x) {
  142. T r = visit(*x.v);
  143. es.variables[x.index] = r;
  144. return r;
  145. }
  146. T operator()(const Add& x) {
  147. return visit(*x.a) + visit(*x.b);
  148. }
  149. T operator()(const Sub& x) {
  150. return visit(*x.a) - visit(*x.b);
  151. }
  152. T operator()(const Mul& x) {
  153. return visit(*x.a) * visit(*x.b);
  154. }
  155. T operator()(const Div& x) {
  156. return visit(*x.a) / visit(*x.b);
  157. }
  158. T operator()(const Neg& x) {
  159. return -visit(*x.a);
  160. }
  161. T operator()(const Atan2& x) {
  162. return mnd::atan2(visit(*x.a), visit(*x.b));
  163. }
  164. T operator()(const Pow& x) {
  165. return mnd::pow(visit(*x.a), visit(*x.b));
  166. }
  167. T operator()(const Cos& x) {
  168. return mnd::cos(visit(*x.a));
  169. }
  170. T operator()(const Sin& x) {
  171. return mnd::sin(visit(*x.a));
  172. }
  173. T operator()(const Exp& x) {
  174. return mnd::exp(visit(*x.a));
  175. }
  176. T operator()(const Ln& x) {
  177. return mnd::log(visit(*x.a));
  178. }
  179. };
  180. }
  181. template<typename T>
  182. NaiveIRGenerator<T>::NaiveIRGenerator(const mnd::ir::Formula& irf,
  183. mnd::Precision prec) :
  184. mnd::MandelGenerator{ prec },
  185. form{ irf }
  186. {
  187. eval::ToEvalVisitor<T> tev{ es };
  188. newz_re = tev.visit(irf.newA);
  189. newz_im = tev.visit(irf.newB);
  190. start_re = tev.visit(irf.startA);
  191. start_im = tev.visit(irf.startB);
  192. }
  193. template<typename T>
  194. void NaiveIRGenerator<T>::generate(const mnd::MandelInfo& info, float* data)
  195. {
  196. const MandelViewport& view = info.view;
  197. const bool parallel = true;
  198. T viewx = mnd::convert<T>(view.x);
  199. T viewy = mnd::convert<T>(view.y);
  200. T wpp = mnd::convert<T>(view.width / info.bWidth);
  201. T hpp = mnd::convert<T>(view.height / info.bHeight);
  202. #if defined(_OPENMP)
  203. if constexpr (parallel)
  204. omp_set_num_threads(omp_get_num_procs());
  205. # pragma omp parallel for schedule(static, 1) if (parallel)
  206. #endif
  207. for (long j = 0; j < info.bHeight; j++) {
  208. T y = viewy + T(double(j)) * hpp;
  209. long i = 0;
  210. for (i; i < info.bWidth; i++) {
  211. T x = viewx + T(double(i)) * wpp;
  212. es.prepare(0, 0, x, y);
  213. eval::EvalVisitor<T> visitor{ es };
  214. T a = visitor.visit(*start_re);
  215. T b = visitor.visit(*start_im);
  216. es.prepare(a, b, x, y);
  217. int k = 0;
  218. for (k = 0; k < info.maxIter; k++) {
  219. T newA = visitor.visit(*newz_re);
  220. T newB = visitor.visit(*newz_im);
  221. a = newA;
  222. b = newB;
  223. if (a * a + b * b >= 16.0)
  224. break;
  225. }
  226. data[i + j * info.bWidth] = float(k);
  227. }
  228. }
  229. }