Skip to content

Commit 7a7bc89

Browse files
authored
Merge pull request #13 from jackyarndley/development
add in minor optimizations
2 parents 793e060 + e56fa1f commit 7a7bc89

File tree

8 files changed

+98
-63
lines changed

8 files changed

+98
-63
lines changed

output.png

54.8 MB
Loading

src/bin/main.rs

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

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

6767
let time = Instant::now();

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/reference.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ impl Reference {
2323
maximum_iteration,
2424
z,
2525
c,
26-
data: Vec::new()
26+
data: Vec::with_capacity(1000)
2727
}
2828
}
2929

src/math/series_approximation.rs

Lines changed: 53 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::mem::swap;
88
pub struct SeriesApproximation {
99
pub current_iteration: usize,
1010
maximum_iteration: usize,
11-
delta_pixel: FloatExtended,
11+
delta_pixel_square: FloatExtended,
1212
z: ComplexArbitrary,
1313
c: ComplexArbitrary,
1414
pub order: usize,
@@ -22,7 +22,7 @@ pub struct SeriesApproximation {
2222
}
2323

2424
impl SeriesApproximation {
25-
pub fn new(c: ComplexArbitrary, order: usize, maximum_iteration: usize, delta_pixel: FloatExtended, delta_top_left: ComplexExtended) -> Self {
25+
pub fn new(c: ComplexArbitrary, order: usize, maximum_iteration: usize, delta_pixel_square: FloatExtended, delta_top_left: ComplexExtended) -> Self {
2626
let mut coefficients = vec![ComplexExtended::new2(0.0, 0.0, 0); order as usize + 1];
2727

2828
coefficients[0] = to_extended(&c);
@@ -32,7 +32,7 @@ impl SeriesApproximation {
3232
SeriesApproximation {
3333
current_iteration: 1,
3434
maximum_iteration,
35-
delta_pixel,
35+
delta_pixel_square,
3636
z: c.clone(),
3737
c,
3838
order,
@@ -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,33 +80,31 @@ 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

100-
let relative_error = (self.current_probes[i] - series_probe).norm();
101-
let mut derivative = derivative_probe.norm();
98+
let relative_error = (self.current_probes[i] - series_probe).norm_square();
99+
let mut derivative = derivative_probe.norm_square();
102100

103101
// Check to make sure that the derivative is greater than or equal to 1
104102
if derivative.to_float() < 1.0 {
105103
derivative = FloatExtended::new(1.0, 0);
106104
}
107105

108106
// Check that the error over the derivative is less than the pixel spacing
109-
if relative_error / derivative > self.delta_pixel {
107+
if relative_error / derivative > self.delta_pixel_square {
110108
self.z -= &self.c;
111109
self.z.sqrt_mut();
112110
return false;
@@ -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: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,15 @@ impl FractalRenderer {
6969

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

72+
let delta_pixel_extended = FloatExtended::new(delta_pixel, -self.zoom.exponent);
73+
74+
// Series approximation currently has some overskipping issues
75+
// this can be resolved by root finding and adding new probe points
7276
let mut series_approximation = SeriesApproximation::new(
7377
self.center_location.clone(),
7478
self.approximation_order,
7579
self.maximum_iteration,
76-
FloatExtended::new(delta_pixel, -self.zoom.exponent),
80+
delta_pixel_extended * delta_pixel_extended,
7781
ComplexExtended::new(delta_top_left, -self.zoom.exponent),
7882
);
7983

@@ -120,9 +124,11 @@ impl FractalRenderer {
120124
println!("{:<14}{:>6} ms", "Iteration", time.elapsed().as_millis());
121125

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

130+
let time = Instant::now();
131+
126132
// Remove all non-glitched points from the remaining points
127133
pixel_data.retain(|packet| {
128134
packet.glitched
@@ -157,7 +163,7 @@ impl FractalRenderer {
157163

158164
Perturbation::iterate(&mut pixel_data, &r, r.current_iteration);
159165

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

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

src/util/colouring.rs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
use crate::util::image::Image;
22
use crate::util::PixelData;
3+
use crate::math::Reference;
34

45
pub enum Colouring {
56
Iteration,
67
IterationSquareRoot,
7-
Histogram,
8+
IterationSmooth,
9+
IterationHistogram,
810
// Distance
911
}
1012

1113
impl Colouring {
12-
pub fn run(&self, pixel_data: &Vec<PixelData>, image: &mut Image, maximum_iteration: usize, _delta_pixel: f64) {
14+
pub fn run(&self, pixel_data: &Vec<PixelData>, image: &mut Image, maximum_iteration: usize, _delta_pixel: f64, reference: &Reference) {
1315
// Palette is temporarily here
1416
let mut colours = Vec::new();
1517

@@ -55,18 +57,18 @@ impl Colouring {
5557
colours.push((red, green, blue))
5658
}
5759

60+
let escape_radius_ln = 1e16f64.ln();
61+
5862
match self {
5963
Colouring::Iteration => {
60-
// No smooth colouring at the moment
61-
6264
for pixel in pixel_data {
6365
let (r, g, b) = if pixel.glitched && image.display_glitches {
6466
(255, 0, 0)
6567
} else if pixel.iteration >= maximum_iteration {
6668
(0, 0, 0)
6769
} else {
6870
// 0.1656
69-
let hue = (250.0f64 * pixel.iteration as f64) as usize % 8192;
71+
let hue = (250 * pixel.iteration) % 8192;
7072

7173
let colour = colours[hue];
7274

@@ -94,7 +96,28 @@ impl Colouring {
9496
image.plot(pixel.image_x, pixel.image_y, r, g, b);
9597
}
9698
},
97-
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 => {
98121
let mut iteration_counts = vec![0usize; maximum_iteration + 2];
99122

100123
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)