Hi,
For homework we must optimise a code that generates pictures with fractals.
We already tried to divide the picture in smaller ones with 2 for loops (and divided runtime by 3), but we also wish to accelerate it further by making several goroutines while launching the function. This brought only negligible amelioration.
How can we do to speed up the program?
Also, please check the function plottingSmallSquares. Why does this function not work as anonymous function inside of the Julia function? When doing that, we get only vertical lines.
Thank you in advance for the replies.
//this program creates pictures with Julia
//imports omitted
type ComplexFunc func(complex128) complex128
var Funcs []ComplexFunc = []ComplexFunc{
func(z complex128) complex128 { return z*z - 0.61803398875 },
func(z complex128) complex128 { return z*z + complex(0, 1) },
//more functions omitted for clarity
}
func main() {
wgr1 := new(sync.WaitGroup)
//this is the function that can be ameliorated
for n, fn := range Funcs {
//sending one to wait group
//the done is executed in the parallelPainting function
wgr1.Add(1)
go parallelPainting(fn, n, wgr1)
}
wgr1.Wait()
}
func parallelPainting(fn ComplexFunc, n int, wgr1 *sync.WaitGroup) {
err := CreatePng("picture-"+strconv.Itoa(n)+".png", fn, 1024)
wgr1.Done()
if err != nil {
log.Fatal(err)
}
}
// CreatePng creates a PNG picture file with a Julia image of size n x n.
func CreatePng(filename string, f ComplexFunc, n int) (err error) {
file, err := os.Create(filename)
if err != nil {
return
}
defer file.Close()
err = png.Encode(file, Julia(f, n))
return
}
// Julia returns an image of size n x n of the Julia set for f.
func Julia(f ComplexFunc, n int) image.Image {
wg := new(sync.WaitGroup)
bounds := image.Rect(-n/2, -n/2, n/2, n/2)
img := image.NewRGBA(bounds)
s := float64(n / 4)
divisor := 10
//division of the image in 100 smaller squares
width := bounds.Max.X - bounds.Min.X
height := bounds.Max.Y - bounds.Min.Y
sizeX := width / divisor
sizeY := height / divisor
startX := bounds.Min.X
startY := bounds.Min.Y
for startX, stopX := bounds.Min.X, startX+sizeX; startX < width; startX, stopX = stopX, startX+sizeX {
for startY, stopY := bounds.Min.Y, startY+sizeY; startY < height; startY, stopY = stopY, startY+sizeY {
wg.Add(1)
go plottingSmallSquares(f, n, img, startX, stopX, startY, stopY, s, wg)
}
}
wg.Wait()
return img
}
func plottingSmallSquares(f ComplexFunc, n int, img *image.RGBA, startX int, stopX int, startY int, stopY int, s float64, wg *sync.WaitGroup) {
for i := startX; i < stopX; i++ {
for j := startY; j < stopY; j++ {
n := Iterate(f, complex(float64(i)/s, float64(j)/s), 256)
r := uint8(0)
g := uint8(0)
b := uint8(n % 32 * 8)
img.Set(i, j, color.RGBA{r, g, b, 255})
}
}
wg.Done()
}
// Iterate sets z_0 = z, and repeatedly computes z_n = f(z_{n-1}), n ≥ 1,
// until |z_n| > 2 or n = max and returns this n.
func Iterate(f ComplexFunc, z complex128, max int) (n int) {
for ; n < max; n++ {
if real(z)*real(z)+imag(z)*imag(z) > 4 {
break
}
z = f(z)
}
return
}
```