Fast Mandelbrot

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
einstein1969
Expert
Posts: 941
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Fast Mandelbrot

#1 Post by einstein1969 » 09 Jun 2014 10:58

Hi to all expert and fractal's fans!

I would like to carry out a project in color on the Mandelbrot set, using:

  • the mathematical Wsh (jscript is faster than vbscript?) or batch (ieee754 penpen's work)
  • some Aacini's utility (for the management of the mouse)
  • multi-threaded batch (to use multiple cores)
  • color gradient
  • deep zoom
  • .... and more ...

I would not do it all alone. Who's' with me?


References:


jeb wrote:One of my next goals is to use multiple threads for the mandelbrot.
So on a Core-I7 it could be 8 times faster.

jeb


A base to start:

Code: Select all

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Mandelbrot
::
:: Use font raster 8x8 or Lucida console 5
:: Tested on Windows 7 32bit
::
::
:: v.0.1 Initial Version. Based on Aacini/jeb code.
::
::  - Tune Env + Implemented a queue for speedup call findstr, quadruple speed!
::  - rewritten core of Iteration , 10% more Speed
::  - fixed bug that overflow the core iteration loop. Reduce FixedPoint precis. from 4 to 3 digit.
::  - Flips X coordinates to match with real Mandelbrot
::  - Palette rainbow!
::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@echo off & Setlocal EnableDelayedExpansion
cls

 :: for raster 8x8
 mode 88,60

 :: for raster 6x4
 rem mode 188,100

 :: for Lucida console 5
 rem mode 330,140

 call :init

 :: increase the queue lenght for more speed! QueueLen=1 => Disabled, 16=lowresolution 128=Highresolution
 set QueueLen=4

 rem 1=42 2=71 3=90 4=105 6=125 8=138 16=160 chars/sec

 rem                                X
 rem               X                X
 rem           X   X                X
 rem       X   X   X                X
 rem     X X   X   X                X
 rem   X X X   X   X                X
 rem X X X X   X   X                X
 rem X X X X   X   X                X
 rem 1 2 3 4   6   8                16

 REM Working values: maximum screen coordinates and iteration level
 set /A maxX=Cols-15, maxY=Lines-5, maxLevel=56, one=1000

 :: to 3 decimal because go overflow.
 call :IntAsFP   $xLeft=-2.100
 call :IntAsFP    $yTop= 1.125
 call :IntAsFP  $xRight= 0.800
 call :IntAsFP $yBottom=-1.125

 :: a particolar/Zoom
 call :IntAsFP   $xLeft=-0.420
 call :IntAsFP    $yTop= 1.000
 call :IntAsFP  $xRight= 0.250
 call :IntAsFP $yBottom= 0.580


 set /A "$xStep=($xRight-$xLeft)/maxX, $yStep=($yTop-$yBottom)/maxY, four=4*one*one"

 set "chars=°±²Û"
 set "char_0=ú"

 set "Colors=04 4C CE EA A2 22 2A AB B9 91 15 50 "
 set "Color_0=a"

 cls
 echo(&echo(

 set /A $yPos=$yTop+$yStep, nChar=0

 set t0=%time%

 for /L %%y in (0,1,%maxY%) do (
   set /P ".=%BS%       " <NUL
   set /A $yPos-=$yStep, $xPos=$xLeft-$xStep
   for /L %%x in (0,1,%maxX%) do (

      set /A "$xPos+=$xStep, $xIter=$xPos, $yIter=$yPos, $xSquare=$xIter*$xIter, $ySquare=$yIter*$yIter, $root=$xSquare+$ySquare"
      set level=
     
      for /L %%i in (1,1,%maxLevel%) do if not defined level (
            if !$root! lss %four% (
               :: check overflow!
               set /A "$yIter=2*$xIter*$yIter/%one%+$yPos, $xIter=($root-2*$ySquare)/%one%+$xPos, $ySquare=$yIter*$yIter, $root=$xIter*$xIter+$ySquare"
            ) else set level=%%i
      )

      if not defined level set level=0

      set /a nChar+=1
     
      for %%l in (!level!) do (

        :: color/char mapping
        set /a "ic=((%%l-1) %% 4), ico=((%%l-1)/4 %% 12)*3"

        if !level! gtr 0 (
           for %%i in (!ic!) do set char=!chars:~%%i,1!
           for %%i in (!ico!) do set col=!Colors:~%%i,3!
        ) else (
          set char=!char_0!
          set col=!Color_0!
        )

        rem ex call :ColorText !showColor[%%l]! "!showChar[%%l]!"
        rem ex (echo !showChar[%%l]!\..\') > colorPrint.txt & findstr /a:!showColor[%%l]! /f:colorPrint.txt "."

        rem if queue full than flush and queue
        if !Queue! geq !QueueLen! (
           (echo !QueueChar!\..\') > colorPrint.txt & %FS% /a:!QueueColor! /f:colorPrint.txt "."
           set QueueChar=!char!
           set QueueColor=!col!
           set Queue=1
        ) else (
          rem if same color than queue
          if "!QueueColor!"=="!col!" (
             set QueueChar=!QueueChar!!char!
             set /a Queue+=1
          ) else (
           rem not same color. Flush and queue
           if defined QueueChar ( (echo !QueueChar!\..\') > colorPrint.txt & %FS% /a:!QueueColor! /f:colorPrint.txt "." )
           set QueueChar=!char!
           set QueueColor=!col!
           set Queue=1
          )
        )
      )
   )
   rem End of Line. flush queue
   if defined QueueChar (
     (echo !QueueChar!\..\') > colorPrint.txt & %FS% /a:!QueueColor! /f:colorPrint.txt "."
     set QueueChar=
     set QueueColor=
     set Queue=0
   )
   :: Performance Statistic.
   for /F "tokens=1-8 delims=:.," %%a in ("!t0: =0!:!time: =0!") do set /a "a=(((1%%e-1%%a)*60)+1%%f-1%%b)*6000+1%%g%%h-1%%c%%d, a+=(a>>31) & 8640000, Cs=nChar*100*10/a"
   title !cs:~0,-1!.!cs:~-1! Chars/sec
   echo(
 )

 popd

goto :EOF

:IntAsFP Int=FP
   set FP=%2
   If "!FP:~0,1!"=="-" (
      set FP=!FP:~1!
      set sign=-
   )
   If "!FP:~0,1!"=="0" set FP=!FP:~1!
   set %1=!sign!!FP:.=!
   set FP=
   set sign=
exit /B

:Init
   pushd %tmp%

   for /f %%f in ('where findstr') do set FS=%%f

   :: get currenct lines and columns from mode command.
   for /f "skip=2 tokens=2" %%f in ('mode con:') do if not defined Lines (set Lines=%%f) else if not defined Cols set Cols=%%f
(
   for /F "Tokens=1 delims==" %%v in ('set') do set "%%v="
   set /a Lines=%Lines%, Cols=%Cols%
   set FS=%FS%
)
   for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "BS=%%a"
   set BS=%BS%%BS%%BS%%BS%%BS%%BS%
   <nul >"'" set /p ".=%BS%      %BS%"

goto :eof

remove comment from "mode 330,140", set font Lucida console 5 and set higher QueueLen for a nice and fast result! Try!!

UPDATE:

Code: Select all

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Mandelbrot
::
:: Use font raster 8x8 or Lucida console 5
::
:: For use +double Y resolution must disable ClearType but Activate Smoothness font edge in System preference. Sperimental mode.
::
:: Tested on Windows 7 32bit
::
:: v 0.2a New Features: Double resolution in Y
::  - Alpha stage for double resolution in Y. Only 16 color is permitted.
::  - Speed slow for maintain code small.
::  - TODO: double resolution in X, software dithering, resolve bug on queue double resolution
::
:: v.0.1 Initial Version. Based on Aacini/jeb code.
::
::  - Tune Env + Implemented a queue for speedup call of findstr, quadruple speed!
::  - rewritten core of Iteration , 10% more Speed
::  - fixed bug that overflow the core iteration loop. Reduce FixedPoint precis. from 4 to 3 digit.
::  - Flips X coordinates to match with real Mandelbrot
::  - Palette rainbow!
::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@echo off & Setlocal EnableDelayedExpansion
cls

 :: for raster 8x8
 mode 88,60

 :: for raster 6x4
 rem mode 188,100

 :: for Lucida console 5
 rem mode 330,140

 :: for Lucida console 2 Bold (Half resolution / Hardware dither)
 rem mode 480,360

 :: for Lucida console 2 (Hardware dither)
 rem mode 960,360

 :: Sperimental!!!
 :: Use +double Y resolution/16 color with software dithering or single resolution/256 color with hardware dithering
 rem set Double=TRUE

 call :init

 :: increase the queue lenght for more speed! QueueLen=1 => Disabled, 16=lowresolution 128=Highresolution
 set MaxQueueLen=2

 :: Q=current queue Len
 set Q=0

 rem 1=42 2=71 3=90 4=105 6=125 8=138 16=160 chars/sec

 rem                                X
 rem               X                X
 rem           X   X                X
 rem       X   X   X                X
 rem     X X   X   X                X
 rem   X X X   X   X                X
 rem X X X X   X   X                X
 rem X X X X   X   X                X
 rem 1 2 3 4   6   8                16

 REM Working values: maximum screen coordinates and iteration level
 set /A maxX=Cols-15, maxY=Lines-5, maxLevel=48, one=1000

 :: to 3 decimal because go overflow.
 call :IntAsFP   xLeft=-2.100
 call :IntAsFP    yTop= 1.125
 call :IntAsFP  xRight= 0.800
 call :IntAsFP yBottom=-1.125

rem goto :n
 set maxLevel=56
 call :IntAsFP   xLeft=-0.420
 call :IntAsFP    yTop= 1.000
 call :IntAsFP  xRight= 0.250
 call :IntAsFP yBottom= 0.580
:n

 set /A "xStep=(xRight-xLeft)/maxX, yStep=(yTop-yBottom)/maxY, four=4*one*one"

 cls
 echo(&echo(

 set t0=%time%

(
 :: remove unnecessary vars.
 set t0=
 rem set MaxqueueLen=
 rem set one=
 set MaxX=
 set MaxY=
 rem set MaxLevel=
 set Lines=
 set Cols=
 rem set FS=
 rem set four=
 rem set Color_0=
 rem set Char_0=
 set mBS=
 set BS=
 set yTop=
 set yBottom=
 set xRight=
 set xLeft=
 set yStep=
 set xStep=

 set /A a_Cy=%yTop%+%yStep%, nChar=0
 
 for /L %%y in (0,1,%maxY%) do (

   set /P ".=%BS%       " <NUL
   set /A a_Cy-=%yStep%, a_Cx=%xLeft%-%xStep%

   for /L %%x in (0,1,%maxX%) do (

      rem title %xStep% %yStep%

      set /A a_Cx+=%xStep%

      call :I

      if /I "!Double!"=="TRUE" (
         set co1=!col!

         set /A "a_Cy+=(%yStep%/2)"

         call :I

         if "!col!"=="!co1!" (
           set char=Û
           set col=7!col!
         ) else set Col=!col:~0,1!!co1:~0,1!

         set /A "a_Cy-=(%yStep%/2)"
      )

        rem ex call :ColorText !showColor[%%l]! "!showChar[%%l]!"
        rem ex (echo !showChar[%%l]!\..\') > colorPrint.txt & findstr /a:!showColor[%%l]! /f:colorPrint.txt "."

        rem TODO: Use this coloring : (echo Ü)> colorPrint.txt & %FS% /a:%1%2 /f:colorPrint.txt "."

      call :Q



   )
   rem End of Line. flush queue
   if defined QueueChar (
     (echo !QueueChar!\..\') > colorPrint.txt & %FS% /a:!QueueColor! /f:colorPrint.txt "."
     set QueueChar=
     set QueueColor=
     set Q=0
   )
   :: Performance Statistic.
   for /F "tokens=1-8 delims=:.," %%a in ("%t0: =0%:!time: =0!") do set /a "a=(((1%%e-1%%a)*60)+1%%f-1%%b)*6000+1%%g%%h-1%%c%%d, a+=(a>>31) & 8640000, Cs=nChar*100*10/a"
   title !cs:~0,-1!.!cs:~-1! Chars/sec
   set cs=& set a=
   echo(
 )

)

 rem set

 popd

goto :EOF

:Q
(
        rem if queue full than flush and queue
        if !Q! geq %MaxQueueLen% (
           (echo !QueueChar!\..\') > colorPrint.txt & %FS% /a:!QueueColor! /f:colorPrint.txt "."
           set QueueChar=!char!
           set QueueColor=!col!
           set Q=1
        ) else (
          rem if same color than queue
          if "!QueueColor!"=="!col!" (
             set QueueChar=!QueueChar!!char!
             set /a Q+=1
          ) else (
           rem not same color. Flush and queue
           if defined QueueChar ( (echo !QueueChar!\..\') > colorPrint.txt & %FS% /a:!QueueColor! /f:colorPrint.txt "." )
           set QueueChar=!char!
           set QueueColor=!col!
           set Q=1
          )
        )

exit /b )

:I
(
      set /a $x=a_Cx, $y=a_Cy, $m=$x*$x+$y*$y
      set bLev=
     
      :: check overflow!
      for /L %%i in (1,1,%maxLevel%) do if not defined bLev (
        if !$m! lss %four% (
               set /A "a=2*$x*$y/%one%+a_Cy, $x=($m-2*$y*$y)/%one%+a_Cx, $y=a, $m=$x*$x+$y*$y"
        ) else set bLev=%%i
      )

      if not defined bLev set bLev=0

      for %%l in (!bLev!) do (

        :: color/char mapping
        if /I "!Double!"=="TRUE" (
          set /a "ic=0, ico=((%%l-1) %% 12) * 3,  nChar+=1"
          :: Hybrid system color for test.
          rem set /a "ic=((%%l-1) %% 4), ico=((%%l-1)/4 %% 12)*3, nChar+=1"
        ) else set /a "ic=((%%l-1) %% 4), ico=((%%l-1)/4 %% 12)*3, nChar+=1"

        if %%l gtr 0 (
           for %%i in (!ic!) do set char=!chars:~%%i,1!
           for %%i in (!ico!) do set col=!Colors:~%%i,3!
        ) else (
          set char=%char_0%
          set col=%Color_0%
        )
      )

      set ic=& set ico=

 
exit /b )


:IntAsFP Int=FP
   set FP=%2
   If "!FP:~0,1!"=="-" (
      set FP=!FP:~1!
      set sign=-
   )
   If "!FP:~0,1!"=="0" set FP=!FP:~1!
   set %1=!sign!!FP:.=!
   set FP=
   set sign=
exit /B

:Init
   pushd %tmp%

   for /f %%f in ('where findstr') do set FS=%%f

   :: get currenct lines and columns from mode command.
   for /f "skip=2 tokens=2" %%f in ('mode con:') do if not defined Lines (set Lines=%%f) else if not defined Cols set Cols=%%f
(
   for /F "Tokens=1 delims==" %%v in ('set') do set "%%v="
   set /a Lines=%Lines%, Cols=%Cols%
   set FS=%FS%
   set Double=%Double%
)
   for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "BS=%%a"
   set mBS=%BS%%BS%%BS%%BS%%BS%%BS%
   <nul >"'" set /p ".=%mBS%      %mBS%"
   <nul >"Ü" set /p ".=%BS%"

   :: Setting Color palette
   if /I "!Double!"=="TRUE" (
      set "chars=Ü"
      set "char_0=Ü"

      set "Colors=4  C  E  A  2  2  3  B  9  1  5  D  "
      set "Color_0=0"
   ) else (
      set "chars=°±²Û"
      set "char_0=ú"

      set "Colors=04 4C CE EA A2 22 2A AB B9 91 15 50 "
      set "Color_0=a"
   )

     :: Hybrid system color for test.
     rem set "chars=ÛÛÛÛ"
     rem set "chars=ÜÜÜÜ"
     rem set "char_0=ú"
     rem set "Colors=4  C  E  A  2  2  3  B  9  1  5  D  "
     rem set "Color_0=0"

goto :eof


einstein1969
Last edited by einstein1969 on 12 Jun 2014 14:30, edited 5 times in total.

einstein1969
Expert
Posts: 941
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Fast Mandelbrot

#2 Post by einstein1969 » 10 Jun 2014 20:39

I added a code base to start playing.

einstein1969

einstein1969
Expert
Posts: 941
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Fast Mandelbrot

#3 Post by einstein1969 » 12 Jun 2014 14:23

Hi, I have added a new features.

The first code work on Standard max resolution with Lucida Console 5. The pixel size is 3x5 (X,Y)
In this mode we have more than 16 colors.

I have implemented a double resolution in Y. In this mode the number of color is MAX 16.

This is the difference.

3x5 font 16 color , Ugly but is the maximum achieved with standard font! : CLICK to enlarge.
Image

This is the new feature result:
3x5 font 16 color, double resolution in Y. Less ugly with standard font! : CLICK to enlarge.
Image
The final pixel resolution is 3x2.
If you zoom you can view hardware dither/smoothness.
This is achieved with ClearType Disabled and Smooth Edge of screen font ON.
I will add Software dither for try and increase image quality.

PS:
I have seen a font in internet that implement the unicode block U+25XX, compatible with dos windows console.

We should try the font that includes unicode Braille. I think it has more resolution and color gradients.

einstein1969

Aacini
Expert
Posts: 1885
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Fast Mandelbrot

#4 Post by Aacini » 12 Jun 2014 20:22

@einstein1969:

Many years ago I presented a work on the drawing of the Mandelbrot Set. My program, written in C, had two central points in order to be highly efficient: the first one was to perform the loop of floating point operations required to calculate each pixel via an assembly language code segment that use the 8 registers of the FPU stack in a more efficient way than the C compiler:

Code: Select all

    /* Iterative calculation of Level, version in C */

    XSquare = XIter * XIter;
    YSquare = YIter * YIter;
    while ( (int)(XSquare+YSquare) < 4  AND  --Level )
        {
        YIter = 2 * (YIter*XIter) - CYImag;
        XIter = XSquare - YSquare - CXReal;
        XSquare = XIter * XIter;
        YSquare = YIter * YIter;
        }
    endwhile

    #else

    /* Iterative calculation of Level, version in assembler */

    /* The FPU 80x87 stack registers are used this way:

       ST:    YIter
       ST(1): XIter
       ST(2): YSquare
       ST(3): XSquare
       ST(4): CYImag
       ST(5): CXReal

       and 2 registers available for operations
    */

    /*Load CXReal and CYImag                                            */
    asm FLD     CXReal
    asm FLD     CYImag

    /*Load XSquare and YSquare                                          */
    asm FLD     XIter
    asm FMUL    ST,ST
    asm FLD     YIter
    asm FMUL    ST,ST

    /*Load XIter and YIter                                              */
    asm FLD     XIter
    asm FLD     YIter

    /*while ( (int)(XSquare+YSquare) < 4  AND  --Level )                */
    asm FLD     ST(3)           ;/* ST = XSquare, stack push 1          */
    asm FLD     ST(3)           ;/* ST = YSquare, stack push 2          */
    asm jmp     SHORT endwhile1
while1:

    /*    {                                                             */
    /*    YIter = 2 * (YIter*XIter) - CYImag;                           */
    asm FMUL    ST,ST(1)        ;/* YIter = YIter*XIter                 */
    asm FADD    ST,ST           ;/* YIter = 2 * (YIter*XIter)           */
    asm FSUB    ST,ST(4)        ;/* YIter = 2 * (YIter*XIter) - CYImag  */

    /*    XIter = XSquare - YSquare - CXReal;                           */
    asm FLD     ST(3)           ;/* ST = XSquare, stack push 1          */
    asm FSUB    ST,ST(3)        ;/* ST = XSquare - YSquare              */
    asm FSUB    ST,ST(6)        ;/* ST = XSquare - YSquare - CXReal     */
    asm FST     ST(2)           ;/* XIter = ST, and remains in stack    */

    /*    XSquare = XIter * XIter;                                      */
    asm FMUL    ST,ST           ;/* ST = XIter * XIter                  */
    asm FST     ST(4)           ;/* XSquare = ST, and remains in stack  */

    /*    YSquare = YIter * YIter;                                      */
    asm FLD     ST(1)           ;/* ST = YIter, stack push 2            */
    asm FMUL    ST,ST           ;/* ST = YIter * YIter                  */
    asm FST     ST(4)           ;/* YSquare = ST, and remains in stack  */

    /*    }                                                             */
    /*endwhile                                                          */
endwhile1:

    asm FADD                    ;/* ST = XSquare+YSquare, stack drop    */
    asm call    far ptr F_FTOL@ ;/* AX = (int) ST, stack drop           */
    asm cmp     ax,4            ;/* (int)(XSquare+YSquare) < 4 ?        */
    asm jge     exitwhile1      ;/* no: exit while                      */
    asm dec     Level           ;/*       --Level                       */
    asm jnz     while1          ;/* while                               */
exitwhile1:

The second point was related to the fact that the most time consuming pixels in the graphic are the black ones, when the loop iterates up to the maximum level. In order to avoid most black pixels, my method works as a "floodfill" routine that use the first black pixel encountered as a boundary, so black regions are not calculated at all. This method was very fast when the drawing have large black areas, like the initial Mandelbrot Set graphic, but if the amplification advance into smaller regions, with more intricated non black areas, the complexity of the floodfill routine makes the method every time slower.

When I presented my work I prepared a large poster as a companion with the Mandelbrot Set, that was comprised of 4 strips of Z-fold paper with 4 printed pages each (about 33" x 44" total size). In order to use the full resolution of the printer, I had to fill each printed page with the contents of 4x4 screen pages, each of which had the 640x480 maximum resolution of the VGA card (I lively remember it! :) ).

I really would like to participate in this project, but unfortunately I have not much time to spend right now; however, I would like to do a couple comments about it. If the purpose of this project is to draw the Mandelbrot Set in the best and fastest possible way using just standard Batch file capabilities then I am pretty sure that it would be very fun, but the result would not be satisfactory. The drawing of fractal graphics must be done at the maximum possible resolution, that in this case imply to use the 1x1 size font, and this point is more notorious as smaller regions are amplified. Even a 2x2 font would have a much degraded visual appeareance compared vs. the 1x1 one. On the other hand, the drawing of large number of pixels using findstr method is just too slow to be practical.

Just my opinion...

Antonio

einstein1969
Expert
Posts: 941
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Fast Mandelbrot

#5 Post by einstein1969 » 13 Jun 2014 12:49

Thanks Antonio for yor replay.

I agree with you that more is better defined, the result is satisfaction. The project will be added to the use of characters with size 1x1 and the use of other big characters as proposed by dbenham and tested by you (you called them virtual pixels?).
I'm going to define these characters at runtime (if possible) rather than provide them to download or compressed and inserted in the batch file as a resource.
Soon implement it dithering and maybe the quality will be satisfactory even at lower resolutions. We'll see... :?:

As for the speed you need to do some testing before coming to a conclusion. Even before that I was running Fractint I implemented in my old mandelbrot what is now called tesseral. But new discoveries have made it almost obsolete some ways to get better speed. I advise you to take a ride with Kalles Fraktaler if you do not already know.

I would not write everything in assembler and possibly little in WSH. Where the laziness is not inviting us to improve.

The goal is to go deep in the dos batch. The medium is to realize a viewer mandelbrot. But there are othe idea in my mind (a 3D maze for examples).

einstein1969

Post Reply