#include "NaiveIRGenerator.h" #include using mnd::NaiveIRGenerator; namespace mnd { template class NaiveIRGenerator; template class NaiveIRGenerator; template class NaiveIRGenerator; template class NaiveIRGenerator; } template NaiveIRGenerator::NaiveIRGenerator(const mnd::ir::Formula& irf, mnd::Precision prec) : mnd::MandelGenerator{ prec }, form{ irf } { } template struct EvalRes { size_t incVal; T result; }; using namespace mnd; template struct TVisitor { T a, b, x, y; size_t incrementValue; T visitNode(ir::Node* n) { EvalRes* nodeData = getNodeData(n); if (nodeData) { if (nodeData->incVal == incrementValue) return nodeData->result; } T res = std::visit(*this, *n); if (nodeData) { nodeData->incVal = incrementValue; nodeData->result = res; } return res; } EvalRes* getNodeData(ir::Node* n) { assert(n != nullptr); std::any& x = std::visit([](auto& n) -> std::any& { return n.nodeData; }, *n); if (auto* v = std::any_cast>(&x)) return v; else return nullptr; } T operator()(const ir::Constant& c) { return mnd::convert(c.value); } T operator()(const ir::Variable& v) { if (v.name == "z_re") return a; else if (v.name == "z_im") return b; else if (v.name == "c_re") return x; else if (v.name == "c_im") return y; else return 0.0; } T operator()(const ir::Negation& n) { return -visitNode(n.value); } T operator()(const ir::Addition& n) { return visitNode(n.left) + visitNode(n.right); } T operator()(const ir::Subtraction& n) { return visitNode(n.left) - visitNode(n.right); } T operator()(const ir::Multiplication& n) { return visitNode(n.left) * visitNode(n.right); } T operator()(const ir::Division& n) { return visitNode(n.left) / visitNode(n.right); } T operator()(const ir::Atan2& n) { return ::atan2(visitNode(n.left), visitNode(n.right)); } T operator()(const ir::Pow& n) { return ::pow(visitNode(n.left), visitNode(n.right)); } T operator()(const ir::Cos& n) { return ::cos(visitNode(n.value)); } T operator()(const ir::Sin& n) { return ::sin(visitNode(n.value)); } T operator()(const ir::Exp& n) { return ::exp(visitNode(n.value)); } T operator()(const ir::Ln& n) { return ::log(visitNode(n.value)); } }; template void NaiveIRGenerator::generate(const mnd::MandelInfo& info, float* data) { const MandelViewport& view = info.view; const bool parallel = true; T viewx = mnd::convert(view.x); T viewy = mnd::convert(view.y); T wpp = mnd::convert(view.width / info.bWidth); T hpp = mnd::convert(view.height / info.bHeight); #if defined(_OPENMP) if constexpr (parallel) omp_set_num_threads(omp_get_num_procs()); # pragma omp parallel for schedule(static, 1) if (parallel) #endif for (long j = 0; j < info.bHeight; j++) { T y = viewy + T(double(j)) * hpp; long i = 0; for (i; i < info.bWidth; i++) { T x = viewx + T(double(i)) * wpp; TVisitor beforeVisitor{ 0, 0, x, y, 0 }; T a = beforeVisitor.visitNode(form.startA); T b = beforeVisitor.visitNode(form.startB); TVisitor visitor{ a, b, x, y, 0 }; int k = 0; for (k = 0; k < info.maxIter; k++) { T newA = visitor.visitNode(form.newA); T newB = visitor.visitNode(form.newB); a = newA; b = newB; if (a * a + b * b >= 16.0) break; visitor.incrementValue++; } data[i + j * info.bWidth] = float(k); } } }