B4J Tutorial Newton Fractals - all in B4J

USE THE B4J PROJECT IN POST #19 BELOW.

I have converted this Github project to a B4J project (a number of B4J classes in the B4J project to match the classes in the Github project). The project is just about 99% B4J but using a bit of JavaObject for "java.awt.Point" and "java.awt.Color". No other external libraries required.

When the B4J project starts the default formula is z^6 -1. It takes a while to draw the fractal so just be patient until the fractal is displayed. You can also edit the formula in the text fields and then click on button "Generate". You can create some very nice looking fractals (code is in the B4J project so amend it to your liking - probably mostly in class NewtonFractal depending on what you want to accomplish).

There is however something strange (timing wise) that I cannot put my finger on and maybe someone can shed some light on it:
1. When I run the B4J project for the first time it takes a "long" time to create the image (eg z^6 -1)
2. Once the image has been rendered I edit/change the formula (eg to z^8 + 15z^4 - 16z^0 --->>> as per image below) without quitting the B4J project and click on Generate again - the image is rendered much FASTER than on the initial run of the B4J project
3. If I then edit the formula to be the same as the startup formula (z^6 -1) without quitting the B4J project the image is also rendered much FASTER" than when the B4J project runs for the first time.

Why this initial "SLOW" rendering?




1690622052723.png


1690624522123.png


1690624805611.png


1690625952419.png


1690627905594.png


1690629669591.png


1690630398803.png


1690631313821.png


1690631564767.png


1690632467582.png


1690632722301.png


1690632974568.png
 

Attachments

  • b4aNewtonFractalViewer.zip
    7.7 KB · Views: 191
Last edited:

Johan Schoeman

Expert
Licensed User
Longtime User
Attached the test program, it is yours but with the new new display routine and Logs for the time measurements.
Could not resist - started up and downloaded your sample project. It is very much faster! Thanks for the mod Klaus

Change this line in class NewtonFractal to be as follows:

B4X:
    Dim DEFAULT_ZOOM As Double = 83

It will center the image a bit better.

1690645014868.png
 

William Lancee

Well-Known Member
Licensed User
Longtime User
#21 is mesmerizing. I know it is a static image, but with my eyes the center is NOT stable, it seems to be continually growing (which is not possible).

I did look at other aspects of the code. The classes are very small and compact.
RootPoint could be a Type, but I doubt that would speed up the calculations.

Arithmetic with Complex Double Numbers take up a lot of CPU cycles.
As @klaus suggested, is it possible to do with none-complex Float or even Int?

In any case, with @klaus changes, the rendering ceases to be a performance factor.
 

Daestrum

Expert
Licensed User
Longtime User
I did play around with your original code, removed the list and just used an int array(x,y) just for the colour and no x,y (done in a loop).
The drawing was faster ( I used pixelwriter on the canvas as that just takes x,y,32bColor ) but the calculation stage is the killer.
 

Daestrum

Expert
Licensed User
Longtime User
Got it down to 58 seconds in release, but doesn't seem as long as it updates the display while waiting.

Some of the changes to the original code

Got rid of the list entirely (not needed and not replaced with anything)
Moved a lot of local variables to global ones (some saved 15 seconds on a run)
Gave compiler hints on the maths - added parenthesis to a lot of the calcs
 

Attachments

  • NewtonFractalViewerDaestrum.zip
    7.5 KB · Views: 123
Last edited:

Johan Schoeman

Expert
Licensed User
Longtime User
Here is another one - it is based on this web posting and this Github project. Have compiled the Github project to the attached Jar - copy the Jar to your additional B4J libs folder (jFractalLibrary.jar).

Have done some minor mods to the inline Java code to bring back an array of Ints and then use it with BitmapCreator to display the image.

This lib only caters for z^n -1 where n > 1

Note the code in the B4J project to alter the Exponent of "z" and to select between color or Grayscale:

Set z^n and Color/Grayscale:
    'set the exponent for z in f(x) = z^exp - 1
    Dim exp As Int = 7                 
    nativeMe.RunMethod("setExp", Array(exp))
  
    'set to True for a color image, set to False for a Grayscale image
    Dim isColor As Boolean = True



1690724865234.png



1690724988496.png



z^15 -1 in color
1690725739369.png


z^15 -1 in Grayscale
1690725819227.png
 

Attachments

  • jFractalLibrary.jar
    8.6 KB · Views: 108
  • b4jFractalLibrary.zip
    3 KB · Views: 96
Last edited:

klaus

Expert
Licensed User
Longtime User
I have also spent some time on the program.
I replaced the myList by an Array of Ints to store only the colors without the x and y coordinates.
The time to draw the image is now below 30 milliseconds.

I have also looked at the calculation routines but no real improvements.

Attached the last version.
 

Attachments

  • b4aNewtonFractalViewerKlaus2.zip
    7.3 KB · Views: 128

William Lancee

Well-Known Member
Licensed User
Longtime User
@Johan Schoeman Comment the ' #JavaCompilerPath: 22, C:\jdk-22\bin\ in Main

@klaus modifications have reduced the times to the following on my system:

run 1: 5788 msec
run 2: 4880 msec
run 3: 4794 msec
run 4: 4743 msec

Observations:
1. About a second difference between first and subsequent runs
2. I changed Double to Float. No difference in image, but also no difference in times on my 64 bit machine.
3. Overall, great performance
 

William Lancee

Well-Known Member
Licensed User
Longtime User
If you comment out the 2 lines in NewtonFractal and if you add @klaus rendering
B4X:
            Main.drawToIV(x,y,cc)
            If x = width-1 Then Sleep(0)
The times are comparable.

These two lines draw the image one line at a time.
 

klaus

Expert
Licensed User
Longtime User
Daestrom uses also BitmapCreator in his program.
The difference is that in the doInBackground routine he is setting the pixel color directly and updates the image in the ImageView which slows down the drawing.
Which means that the image is updated 560000 times.
I fill an Array of Ints in the doInBackground routine and when the calculation is finished I display the entire image.
 
Last edited:

Johan Schoeman

Expert
Licensed User
Longtime User
#21 is mesmerizing. I know it is a static image, but with my eyes the center is NOT stable, it seems to be continually growing (which is not possible).
I have also noticed it. Interesting indeed how our eyes can play silly buggers with us ?
 

Johan Schoeman

Expert
Licensed User
Longtime User
If you comment out the 2 lines in NewtonFractal and if you add @klaus rendering
B4X:
            Main.drawToIV(x,y,cc)
            If x = width-1 Then Sleep(0)
The times are comparable.

These two lines draw the image one line at a time.
Can you post the project with your mod?
 

William Lancee

Well-Known Member
Licensed User
Longtime User
I left a stray line in
' Dim temp(width) As Int

Note times vary with parameters.
 
Last edited:

Daestrum

Expert
Licensed User
Longtime User
Now down to 8.9 seconds for the image to complete.
(Thanks @klaus for pointing out the redrawing too often)

Now it a draws a line at a time.
B4X:
#Region Backgroundtask

public Sub doInBackground
	Dim c As JavaObject
	c.Initializestatic("java.awt.Color")
	Log("start")
	Dim st As Long = DateTime.Now
#Region Heavy Task	
	For y = 0 To height - 1
		For x = 0 To  width - 1
			applyNewtonMethod(x,y)
			pnt3.RunMethod("setLocation",Array(x,y))
			c = getColorFromRoot(roots.Get(pnt3))
			Dim cc As Int = c.RunMethod("getRGB",Null)
			Main.bmc.SetColor(x, y, cc)
		Next
		Sleep(0)
		Main.bmc.SetBitmapToImageView(Main.bmc.Bitmap, Main.ImageView1)
	Next
	Main.bmc.SetBitmapToImageView(Main.bmc.Bitmap, Main.ImageView1)
#End Region	
	Log("end : (" & (DateTime.Now - st) & ")ms")
End Sub

#End Region
 

Daestrum

Expert
Licensed User
Longtime User
Changing the line after the Sleep(0) line above to
B4X:
		If y Mod 20 = 0 Then Main.bmc.SetBitmapToImageView(Main.bmc.Bitmap, Main.ImageView1)

Brings the time down to 4.8 seconds. The 20 seems the ideal on my system, a lager number is slower also a smaller number is too.
 

William Lancee

Well-Known Member
Licensed User
Longtime User
@Daestrum
Yes, I tried different block values 1, 2, 3, 4, 5, 10, 20, 40, 50.
I was surprised that it didn't matter very much. You would think that doing rendering every other line would nearly half the time.
Not so. I guess the limit is not the rendering per se but leaving enough non-interruptible time for the computation of the line to complete.

Putting the sleep(0) after the rendering is slightly faster than putting it before.
Presumably, the rendering is going on in a different thread while the computations continue almost immediately.
 

William Lancee

Well-Known Member
Licensed User
Longtime User
My presumption, as usual, was wrong. It is just that the rendering time is very small 538 MICROSeconds per line (on average).
So the total time is mostly due computation: 22 milliseconds average for first two lines and 7 milliseconds average for subsequent lines.

So Java optimization takes place during initial 2 lines of the loop, then settles down.

All in all a pleasure to watch, and thanks to @Johan Schoeman for bringing his art to B4X.

________________________________
All release times on my system
Processor 11th Gen Intel(R) Core(TM) i9-11900K @ 3.50GHz
Installed RAM 32.0 GB (31.9 GB usable)
System type 64-bit operating system, x64-based processor
 

Daestrum

Expert
Licensed User
Longtime User
It's a good exercise to see how miniscule changes to code have a direct bearing on execution speed.
When I first ran the program it took around 150 seconds to fully display the image, now (for me) it takes around 4.8 seconds.
(I have changed a few more places and shaved single digit millis off it further - the 2 * pi is calculated once and plugged in - that alone saved ~60ms overall)

I agree, thank you @Johan Schoeman for posting this - it has been fun.
 
Top