Skip to content

Commit ad17ea4

Browse files
committed
optimized some parts of the series approximation
1 parent 6b45392 commit ad17ea4

File tree

7 files changed

+85
-56
lines changed

7 files changed

+85
-56
lines changed

output.png

-5.9 MB
Loading

src/bin/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ fn main() {
5353
println!("Zoom: {}", zoom);
5454

5555
let mut renderer = FractalRenderer::new(
56-
2000,
57-
2000,
56+
1000,
57+
1000,
5858
zoom,
5959
iterations.parse::<usize>().unwrap(),
6060
center_re,
6161
center_im,
62-
0.001,
62+
0.01,
6363
false,
6464
32
6565
);

src/math/perturbation.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ impl Perturbation {
2222

2323
if z_norm < reference.data[pixel.iteration - reference.start_iteration].z_tolerance {
2424
pixel.glitched = true;
25-
pixel.delta_current.reduce();
2625
break;
2726
}
2827

2928
if z_norm > 1e16 {
3029
pixel.escaped = true;
31-
pixel.delta_current.reduce();
30+
pixel.delta_current.mantissa = pixel.delta_current.to_float();
31+
pixel.delta_current.exponent = 0;
3232
break;
3333
}
3434
}

src/math/series_approximation.rs

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ impl SeriesApproximation {
6161

6262
// Calculate the new coefficents
6363
for k in 2..=self.order {
64-
let mut sum = ComplexExtended::new2(0.0, 0.0, 0);
64+
let mut sum = self.coefficients[0] * self.coefficients[k];
6565

66-
for j in 0..=((k - 1) / 2) {
66+
for j in 1..=((k - 1) / 2) {
6767
sum += self.coefficients[j] * self.coefficients[k - j];
6868
}
6969
sum *= 2.0;
@@ -80,21 +80,19 @@ impl SeriesApproximation {
8080
// this section takes about half of the time
8181
for i in 0..self.original_probes.len() {
8282
// step the probe points using perturbation
83-
self.current_probes[i] = self.coefficients[0] * self.current_probes[i] * 2.0 + self.current_probes[i] * self.current_probes[i] + self.original_probes[i];
83+
self.current_probes[i] = self.current_probes[i] * (self.coefficients[0] * 2.0 + self.current_probes[i]);
84+
self.current_probes[i] += self.original_probes[i];
85+
86+
// TODO this probably does not need to be done every iteration
8487
self.current_probes[i].reduce();
8588

8689
// get the new approximations
87-
let mut series_probe = ComplexExtended::new2(0.0, 0.0, 0);
88-
let mut derivative_probe = ComplexExtended::new2(0.0, 0.0, 0);
90+
let mut series_probe = self.next_coefficients[1] * self.approximation_probes[i][0];
91+
let mut derivative_probe = self.next_coefficients[1] * self.approximation_probes_derivative[i][0];
8992

90-
for k in 1..=self.order {
93+
for k in 2..=self.order {
9194
series_probe += self.next_coefficients[k] * self.approximation_probes[i][k - 1];
92-
derivative_probe += self.next_coefficients[k] * self.approximation_probes_derivative[i][k - 1] * k as f64;
93-
94-
if k % 16 == 0{
95-
series_probe.reduce();
96-
derivative_probe.reduce();
97-
}
95+
derivative_probe += self.next_coefficients[k] * self.approximation_probes_derivative[i][k - 1];
9896
};
9997

10098
let relative_error = (self.current_probes[i] - series_probe).norm();
@@ -138,24 +136,23 @@ impl SeriesApproximation {
138136
self.original_probes.push(delta_probe);
139137
self.current_probes.push(delta_probe);
140138

141-
let mut delta_probe_n = Vec::with_capacity(self.order + 1);
142-
let mut delta_probe_n_derivative = Vec::with_capacity(self.order + 1);
139+
let mut delta_probe_n = delta_probe;
140+
141+
let mut delta_probe_n_2 = Vec::with_capacity(self.order + 1);
142+
let mut delta_probe_n_derivative_2 = Vec::with_capacity(self.order + 1);
143143

144144
// The first element will be 1, in order for the derivative to be calculated
145-
delta_probe_n.push(delta_probe);
146-
delta_probe_n_derivative.push(ComplexExtended::new2(1.0, 0.0, 0));
145+
delta_probe_n_2.push(delta_probe_n);
146+
delta_probe_n_derivative_2.push(ComplexExtended::new2(1.0, 0.0, 0));
147147

148148
for i in 1..=self.order {
149-
let mut delta_probe1 = delta_probe_n[i - 1] * delta_probe;
150-
let mut delta_probe2 = delta_probe_n_derivative[i - 1] * delta_probe;
151-
delta_probe1.reduce();
152-
delta_probe2.reduce();
153-
delta_probe_n.push(delta_probe1);
154-
delta_probe_n_derivative.push(delta_probe2);
149+
delta_probe_n_derivative_2.push((delta_probe_n * (i + 1) as f64));
150+
delta_probe_n *= delta_probe;
151+
delta_probe_n_2.push(delta_probe_n);
155152
}
156153

157-
self.approximation_probes.push(delta_probe_n);
158-
self.approximation_probes_derivative.push(delta_probe_n_derivative);
154+
self.approximation_probes.push(delta_probe_n_2);
155+
self.approximation_probes_derivative.push(delta_probe_n_derivative_2);
159156
}
160157

161158
// Get the current reference, and the current number of iterations done
@@ -181,31 +178,43 @@ impl SeriesApproximation {
181178
}
182179

183180
pub fn evaluate(&self, point_delta: ComplexExtended) -> ComplexExtended {
184-
let mut approximation = self.coefficients[1] * point_delta;
185-
let mut original_point_n = point_delta * point_delta;
181+
// 1907 ms packing opus 4K
182+
// Horner's rule
183+
let mut approximation = self.coefficients[self.order];
186184

187-
for k in 2..=self.order {
188-
approximation += self.coefficients[k] * original_point_n;
189-
original_point_n *= point_delta;
190-
191-
if k % 16 == 0 {
192-
approximation.reduce();
193-
original_point_n.reduce();
194-
}
195-
};
185+
for k in (1..=(self.order - 1)).rev() {
186+
approximation *= point_delta;
187+
approximation += self.coefficients[k];
188+
}
196189

190+
approximation *= point_delta;
191+
approximation.reduce();
197192
approximation
198193
}
199194

200-
// pub fn evaluate_derivative(&self, point_delta: ComplexFixed<f64>) -> ComplexFixed<f64> {
195+
// pub fn evaluate_derivative(&self, point_delta: ComplexExtended) -> FloatExtended {
201196
// let mut original_point_derivative_n = ComplexExtended::new(1.0, 0, 0.0, 0);
202197
// let mut approximation_derivative = ComplexExtended::new(0.0, 0, 0.0, 0);
203-
//
198+
204199
// for k in 1..=self.order {
205200
// approximation_derivative += k as f64 * self.coefficients[k] * original_point_derivative_n;
206201
// original_point_derivative_n *= ComplexExtended::new(point_delta.re, 0, point_delta.im, 0);
207202
// };
208-
//
203+
209204
// approximation_derivative.to_float()
205+
206+
207+
// let mut approximation_derivative = self.coefficients[self.order] * self.order as f64;
208+
209+
// for k in (1..=(self.order - 1)).rev() {
210+
// approximation *= point_delta;
211+
// approximation += self.coefficients[k] * k as f64;
212+
// }
213+
214+
// approximation *= point_delta;
215+
// approximation.reduce();
216+
// approximation
217+
218+
210219
// }
211220
}

src/renderer.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ impl FractalRenderer {
6969

7070
println!("Rendering...");
7171

72+
// Series approximation currently has some overskipping issues
73+
// this can be resolved by root finding and adding new probe points
7274
let mut series_approximation = SeriesApproximation::new(
7375
self.center_location.clone(),
7476
self.approximation_order,
@@ -120,9 +122,11 @@ impl FractalRenderer {
120122
println!("{:<14}{:>6} ms", "Iteration", time.elapsed().as_millis());
121123

122124
let time = Instant::now();
123-
Colouring::Iteration.run(&pixel_data, &mut self.image, self.maximum_iteration, delta_pixel, &reference);
125+
Colouring::IterationSmooth.run(&pixel_data, &mut self.image, self.maximum_iteration, delta_pixel, &reference);
124126
println!("{:<14}{:>6} ms", "Coloring", time.elapsed().as_millis());
125127

128+
let time = Instant::now();
129+
126130
// Remove all non-glitched points from the remaining points
127131
pixel_data.retain(|packet| {
128132
packet.glitched
@@ -157,7 +161,7 @@ impl FractalRenderer {
157161

158162
Perturbation::iterate(&mut pixel_data, &r, r.current_iteration);
159163

160-
Colouring::Iteration.run(&pixel_data, &mut self.image, self.maximum_iteration, delta_pixel, &r);
164+
Colouring::IterationSmooth.run(&pixel_data, &mut self.image, self.maximum_iteration, delta_pixel, &r);
161165

162166
// Remove all non-glitched points from the remaining points
163167
pixel_data.retain(|packet| {

src/util/colouring.rs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use crate::math::Reference;
55
pub enum Colouring {
66
Iteration,
77
IterationSquareRoot,
8-
Histogram,
8+
IterationSmooth,
9+
IterationHistogram,
910
// Distance
1011
}
1112

@@ -56,21 +57,18 @@ impl Colouring {
5657
colours.push((red, green, blue))
5758
}
5859

60+
let escape_radius_ln = 1e16f64.ln();
61+
5962
match self {
6063
Colouring::Iteration => {
61-
// No smooth colouring at the moment
62-
6364
for pixel in pixel_data {
6465
let (r, g, b) = if pixel.glitched && image.display_glitches {
6566
(255, 0, 0)
6667
} else if pixel.iteration >= maximum_iteration {
6768
(0, 0, 0)
6869
} else {
69-
let z_norm = (reference.data[pixel.iteration - reference.start_iteration].z_fixed + pixel.delta_current.to_float()).norm();
70-
let smooth = 1.0 - (z_norm.ln()).log2();
71-
7270
// 0.1656
73-
let hue = (7.0f64 * (pixel.iteration as f64 + smooth) + 8192.0) as usize % 8192;
71+
let hue = (250 * pixel.iteration) % 8192;
7472

7573
let colour = colours[hue];
7674

@@ -98,7 +96,28 @@ impl Colouring {
9896
image.plot(pixel.image_x, pixel.image_y, r, g, b);
9997
}
10098
},
101-
Colouring::Histogram => {
99+
Colouring::IterationSmooth => {
100+
for pixel in pixel_data {
101+
let (r, g, b) = if pixel.glitched && image.display_glitches {
102+
(255, 0, 0)
103+
} else if pixel.iteration >= maximum_iteration {
104+
(0, 0, 0)
105+
} else {
106+
let z_norm = (reference.data[pixel.iteration - reference.start_iteration].z_fixed + pixel.delta_current.mantissa).norm_sqr();
107+
let smooth = 1.0 - (z_norm.ln() / escape_radius_ln).log2();
108+
109+
// 0.1656
110+
let hue = (250.0f64 * (pixel.iteration as f64 + smooth)) as usize % 8192;
111+
112+
let colour = colours[hue];
113+
114+
(colour.0 as u8, colour.1 as u8, colour.2 as u8)
115+
};
116+
117+
image.plot(pixel.image_x, pixel.image_y, r, g, b);
118+
}
119+
},
120+
Colouring::IterationHistogram => {
102121
let mut iteration_counts = vec![0usize; maximum_iteration + 2];
103122

104123
for pixel in pixel_data {

src/util/complex_extended.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ impl AddAssign for ComplexExtended {
8787
self.mantissa += other.mantissa;
8888
}
8989
}
90-
// self.reduce();
9190
}
9291
}
9392

@@ -103,7 +102,6 @@ impl SubAssign for ComplexExtended {
103102
self.exponent = other.exponent;
104103
self.mantissa -= other.mantissa;
105104
}
106-
self.reduce();
107105
}
108106
}
109107

@@ -112,7 +110,6 @@ impl MulAssign<ComplexExtended> for ComplexExtended {
112110
fn mul_assign(&mut self, other: Self) {
113111
self.mantissa *= other.mantissa;
114112
self.exponent += other.exponent;
115-
// self.reduce();
116113
}
117114
}
118115

0 commit comments

Comments
 (0)