|
|
|
#include <xmmintrin.h> |
|
#include <immintrin.h> |
|
#include <smmintrin.h> |
|
#include <complex> |
|
#include <fstream> |
|
#include <iostream> |
|
#include <cnpy.h> |
|
#include <vector> |
|
#include "nlohmann/json.hpp" |
|
|
|
using namespace std::complex_literals; |
|
using json = nlohmann::json; |
|
int main(int argc, char* argv[]) { |
|
typedef long long S; |
|
typedef double T; |
|
typedef long long A; |
|
typedef int I; |
|
const int components = 4; |
|
|
|
typedef T vec __attribute__((vector_size(sizeof(T) * components))); |
|
typedef I veci __attribute__((vector_size(sizeof(I) * components))); |
|
|
|
if(argc <= 2) { |
|
return -1; |
|
} |
|
|
|
const std::string& out_name = argv[2]; |
|
const std::string& in_name = argv[1]; |
|
|
|
|
|
|
|
json args; |
|
std::ifstream infile; |
|
infile.open(in_name); |
|
infile >> args; |
|
infile.close(); |
|
|
|
|
|
const long long iterations = args["iterations"]; |
|
|
|
const size_t width = args["width"]; |
|
const size_t height = args["height"]; |
|
T x_0, x_1, y_0, y_1; |
|
x_0 = args["canvas range"][0][0]; |
|
y_0 = args["canvas range"][0][1]; |
|
x_1 = args["canvas range"][1][0]; |
|
y_1 = args["canvas range"][1][1]; |
|
|
|
const size_t size = width * height; |
|
const size_t channels = args["channels"]; |
|
A* img; |
|
img = new A[width * height * channels](); |
|
S p_0, q_0, p_1, q_1; |
|
p_0 = args["circle range"][0][0]; |
|
q_0 = args["circle range"][0][1]; |
|
p_1 = args["circle range"][1][0]; |
|
q_1 = args["circle range"][1][1]; |
|
|
|
T radius = args["radius"]; |
|
T threshold = args["threshold"]; |
|
|
|
S p_2, q_2; |
|
p_2 = args["starting rational"][0]; |
|
q_2 = args["starting rational"][1]; |
|
|
|
S s = 0; |
|
|
|
vec x_scale_vec; |
|
vec y_scale_vec; |
|
vec x_0_vec; |
|
vec y_0_vec; |
|
veci zero_vec; |
|
veci width_vec; |
|
veci height_vec; |
|
|
|
for(int i = 0; i < components; i++) { |
|
x_0_vec[i] = x_0; |
|
y_0_vec[i] = y_0; |
|
x_scale_vec[i] = width / (x_1 - x_0); |
|
y_scale_vec[i] = height / (y_1 - y_0); |
|
zero_vec[i] = 0; |
|
width_vec[i] = width; |
|
height_vec[i] = height; |
|
} |
|
|
|
S total_orbits; |
|
|
|
for(S total_orbits = 0; !args.contains("total orbits") || total_orbits < args["total orbits"]; total_orbits += components) { |
|
vec c_real; |
|
vec c_imag; |
|
veci i_vec; |
|
veci qs2_vec; |
|
|
|
S iterations2 = 0; |
|
|
|
for(int i = 0; i < components; i++) { |
|
i_vec[i] = 0; |
|
S p = p_0 * q_2 + p_1 * p_2; |
|
S q = q_0 * q_2 + q_1 * p_2; |
|
|
|
s += q; |
|
|
|
if(q > iterations2) { |
|
iterations2 = q; |
|
} |
|
|
|
{ |
|
T t = 2 * M_PI * T(p) / T(q); |
|
std::complex<T> mu = std::polar(radius, t); |
|
const auto P = mu / T(2); |
|
const auto c = P - P * P; |
|
qs2_vec[i] = q * iterations; |
|
c_real[i] = c.real(); |
|
c_imag[i] = c.imag(); |
|
} |
|
} |
|
|
|
iterations2 *= iterations; |
|
|
|
vec z_real = c_real; |
|
vec z_imag = c_imag; |
|
|
|
vec z0_real[channels]; |
|
vec z0_imag[channels]; |
|
|
|
for(int i = 0; i < channels; i++) { |
|
vec z_real_sq = z_real * z_real; |
|
vec z_imag_sq = z_imag * z_imag; |
|
vec z_real_imag = z_real * z_imag; |
|
vec z_abs_sq = z_real_sq + z_imag_sq; |
|
z_real = z_real_sq - z_imag_sq + c_real; |
|
z_imag = z_real_imag + z_real_imag + c_imag; |
|
z0_real[i] = z_real; |
|
z0_imag[i] = z_imag; |
|
} |
|
|
|
size_t size = width * height; |
|
{ |
|
for(int i = 0; i < iterations2; i++, i_vec += 1) { |
|
vec z_real_sq = z_real * z_real; |
|
vec z_imag_sq = z_imag * z_imag; |
|
vec z_real_imag = z_real * z_imag; |
|
vec z_abs_sq = z_real_sq + z_imag_sq; |
|
z_real = z_real_sq - z_imag_sq + c_real; |
|
z_imag = z_real_imag + z_real_imag + c_imag; |
|
|
|
for(int j = 0; j < channels; j++) { |
|
A* img2 = &img[j * size]; |
|
vec x = z_real - z0_real[(i - j - 1) % channels]; |
|
vec y = z_imag - z0_imag[(i - j - 1) % channels]; |
|
|
|
veci x_s = __builtin_convertvector((x - x_0_vec) * y_scale_vec, veci); |
|
veci y_s = __builtin_convertvector((y - y_0_vec) * y_scale_vec, veci); |
|
veci index = y_s * width_vec + x_s; |
|
veci mask = (zero_vec <= x_s) && (x_s < width_vec) && (zero_vec <= y_s) && (y_s < height_vec) && (i_vec < qs2_vec); |
|
|
|
for(int k = 0; k < components; k++) { |
|
if(mask[k]) { |
|
size_t index_k = index[k]; |
|
img2[index_k] ++; |
|
} |
|
} |
|
} |
|
|
|
z0_real[i % channels] = z_real; |
|
z0_imag[i % channels] = z_imag; |
|
} |
|
} |
|
|
|
if(args.contains("refresh iterations") && s >= args["refresh iterations"]) { |
|
json status; |
|
status["current rational"] = {p_2, q_2}; |
|
std::ofstream o("status.json"); |
|
o << status << std::endl; |
|
o.close(); |
|
s = 0; |
|
std::cerr << p_2 << "/" << q_2 << std::endl; |
|
cnpy::npy_save(out_name, img, {channels, height, width}, "w"); |
|
} |
|
|
|
{ |
|
S t = ((p_2 / q_2) * 2 + 1) * q_2 - p_2; |
|
p_2 = q_2; |
|
q_2 = t; |
|
} |
|
|
|
} |
|
|
|
cnpy::npy_save(out_name, img, {channels, height, width}, "w"); |
|
delete [] img; |
|
|
|
return 0; |
|
} |