


                    * * * * * * * * * * * * * * * *
                    *                             *
                    *   PHC  and  PTC  tutorial   *
                    *                             *
                    *            v 2.0            *
                    *                             *
                    *           May 1997          *
                    *                             *
                    * * * * * * * * * * * * * * * *




    1 - PHC Method: Overlaying two fractals ("16-bit PHC")
        1-1 - Assignment statements
        1-2 - Bailout tests
        1-3 - Examples
              1-3-1 - Mandel and Julia types
              1-3-2 - Mandel and Newton types
    2 - First PTC Method: Overlaying three fractals ("24-bit PTC")
    3 - Second PTC Method: Overlaying four fractals ("32-bit PTC")
    4 - Speed ups
        4-1 - Avoid exponentiation...
        4-2 - Avoid unnecessary calculations...
        4-3 - Use the algebraic rules...
    5 - How to write or modify PHC and PTC formulas
    6 - Conversion of existing formulas
        6-1 - Example 1
        6-2 - Example 2
        6-3 - Example 3
        6-4 - Example 4: bailout tests
    7 - Notes about the formula parser
        7-1 - Calculation modes
        7-2 - What's wrong with 3 * trunc(cr / 3) ?
        7-3 - Precedence
    8 - Limitations of PHC and PTC
    9 - Conclusion




    This document is Copyright (c) 1996-1997 by Sylvie Gallet.
    I encourage you to copy and distribute it, so long as you leave it
    unchanged.  It may NOT be used for commercial purposes without my
    explicit prior permission.

    Any comments, questions, corrections... are welcome.
    My addresses are:

             CompuServe:  Sylvie_Gallet  [101324,3444]
               Internet:  sylvie_gallet@compuserve.com



    Pseudo-HiColor (PHC) was co-discovered by Jim Deutch who wrote the
    very first PHC formula and Lee Skinner who realized the enormous
    possibilities that this technique offers.  Given the great interest
    aroused by PHC, the Fractint developers decided to implement three
    new variables that make formulas much simpler; a big thank you to
    Tim Wegner, Jonathan Osuch and George Martin for doing this!

    And a MEGA thanks for the IF..ELSE instruction they implemented in
    Fractint 19.6.  This very powerful instruction considerably improves
    the readability of the formulas that use conditional statements and
    makes them generally faster.

    In this second version of the PHC and PTC tutorial, I have rewritten
    both the explanatory material and the formulas to take advantage
    of the express branching instructions available now with Fractint 19.6.
    Some historical perspective may be helpful. Branching instructions have
    evolved from the technique described by Bradley Beacham in his formula
    tutorial, to the more direct conditional assignments commonly seen now,
    to the new IF..ELSE instructions. PHC formulas originally contained
    rather complex calculations to achieve the checkerboard effect required,
    but were much simplified when the "whitesq", "scrnpix", and "scrnmax"
    predefined variables were added to the formula parser.

    Because of these developments, the same PHC formula may be found in
    different formula files with much different instructions, depending on
    the "state of the art" when the particular version of the formula was
    written. I have included samples of formulas written in the previous
    style in the accompanying phctutor.frm. This should help the Fractint
    user to understand how the old formulas worked and make easier the
    conversion of existing formulas written in the prior old formats.

    Pseudo-TrueColor (PTC) is an extension of the PHC concept.  All the
    PHC and PTC formulas included in this document are by the author of
    these lines.

    Thanks to Lee Skinner and George Martin for their help, suggestions
    and encouragements.




1 - PHC Method: Overlaying two fractals ("16-bit PHC")
======================================================
 It is possible to combine two fractals (say fractal_0 and fractal_1) in
 one image.  Imagine that alternate screen pixels form a checkerboard
 pattern (represented by 0's and 1's) as follows:

                          0 1 0 1 0 . .
                          1 0 1 0 1 . .
                          0 1 0 1 0 . .
                          1 0 1 0 1 . .
                          . . . . . . .

 If one fractal is drawn on the "white squares" (the 1's) and the other
 on the black squares (the 0's), the separate fractals will be visible,
 and at higher screen resolutions you will not be able to see the way the
 individual pixels intermesh with the others.  The effect is as if the two
 fractals were drawn on separate transparent sheets and overlaid.

 Fractint v. 19.5 provides a predefined variable "whitesq", which is
 automatically set to 1 prior to the calculation of a white square pixel,
 and to 0 prior to calculation of a black square pixel.  Let's see how to
 use this variable in a formula.

1-1 - Assignment statements
-+-+-+-+-+-+-+-+-+-+-+-+-+-
 Suppose that fractal_0 and fractal_1 have the following assignment statements:

          fractal_0
            var = something

          fractal_1
            var = somethingelse

 To overlay the two fractals in PHC fashion, you can use the following
 IF..ELSE instruction in a formula:

     IF (whitesq == 0)         ; "whitesq == 0" is TRUE
       var = something
     ELSE                      ; "whitesq == 0" is FALSE
       var = somethingelse
     ENDIF

 or, even more simple:

     IF (whitesq)              ; "whitesq == 1" is TRUE
       var = somethingelse
     ELSE                      ; "whitesq == 1" is FALSE
       var = something
     ENDIF

1-2 - Bailout tests
-+-+-+-+-+-+-+-+-+-
 Suppose that fractal_0 and fractal_1 use the bailout tests bailout_0 and
 bailout_1.  What will be the PHC bailout test?

 Remember that if the answer of a bailout test is "TRUE" (the real portion
 of the complex number is nonzero), the loop must be performed again;
 otherwise, it is time to quit iterating.

 The bailout test of the PHC formula must be the translation in the parser
 language of the following rule:

 PHC_bailout is TRUE only in two cases:

     when (whitesq == 0) and (bailout_0 == TRUE)
   or
     when (whitesq == 1) and (bailout_1 == TRUE)

  Under Fractint 19.6, this expression becomes:
  --------------------------------------------

     IF (whitesq)
       PHC_bailout = bailout_1
     ELSE
       PHC_bailout = bailout_0
     ENDIF
     PHC_bailout

 You'll notice that the IF block is followed by the name of a variable.
 Omitting the last line will produce an error message from Fractint.

1-3 - Examples
-+-+-+-+-+-+-+

1-3-1 - Mandel and Julia types
------------------------------
 This is the easiest case: both fractal use the same iteration instruction
 and the same bailout test.

   mandel { ; Mandel set of z^2 + c
     z = c = pixel :
      z = z*z + c
       |z| <= 4
     }
   julia { ; Julia set of z^2 + (-0.75,0.1234)
     z = pixel , c = (-0.75,0.1234) :
      z = z*z + c
       |z| <= 4
     }

 Since the only difference is the initial value of c, the PHC formula will
 use whitesq only in the init section:

   phc_mj { ; overlay the Mandel set of z^2 + c with
            ; the Julia set of z^2 + (-0.75,0.1234)
            ; Modified for if..else logic, April 1997
     z = pixel
     IF (whitesq)
       c = (-0.75,0.1234)
     ELSE
       c = pixel
     ENDIF
     :
     z = z*z + c
     |z| <= 4
     }

1-3-2 - Mandel and Newton types
-------------------------------
 Here, except "z = pixel", everything is different.

   mandel { ; Mandel set of z^2 + c
     z = c = pixel :
      z = z*z + c
       |z| <= 4
     }
   newton { ; Julia set of Newton's method applied to z^3 - 1 = 0
     z = pixel :
      n = z^3 - 1 , d = 3*z^2
      z = z - n/d
       |n| >= 0.000001
     }

 The resulting PHC formula is:

   phc_mn_A { ; overlay the Mandel set of z^2 + c with the Julia
              ; set of Newton's method applied to z^3 - 1 = 0
              ; Modified for if..else logic, April 1997
     z = pixel :
     IF (whitesq)
       n = z^3 - 1 , d = 3*z^2 , z = z - n/d
       PHC_bailout = |n| >= 0.000001
     ELSE
       z = z*z + pixel , PHC_bailout = |z| <= 4
     ENDIF
     PHC_bailout
     }


2 - First PTC Method: Overlaying three fractals ("24-bit PTC")
==============================================================
 Overlaying three fractals can be done with the following pattern:

                          0 1 2 0 1 2 . .
                          1 2 0 1 2 0 . .
                          2 0 1 2 0 1 . .
                          0 1 2 0 1 2 . .
                          . . . . . . . .

 Fractint v. 19.5 provides a predefined variable "scrnpix", which is set
 to (column, row) prior to calculation of each pixel.  The upper left hand
 corner of the screen is (0,0); at resolution 1024x768, the lower right
 hand corner is therefore (1023,767).

 Here, we'll use scrnpix to assign the value 0, 1 or 2 to a variable r
 (as you can see, I choose a very explicit name!).

 With col = real(scrnpix) and row = imag(scrnpix), the value of r should
 be:
     r = (col + row) modulo 3
 or, using the parser language:
     cr = real(scrnpix) + imag(scrnpix)
     r = cr - 3 * trunc(cr / 3)

 But this instruction doesn't work (see section 7-2).

 The following instruction does work:
     r = cr - 3 * trunc(cr / real(3))

Now, let's see an example:
--------------------------
 Suppose you want to overlay the three following fractals:

   mandel { ; Mandel set of z^2 + c
     z = c = pixel :
      z = z*z + c
       |z| <= 4
     }
   julia { ; Julia set of z^2 + (-0.75,0.1234)
     z = pixel , c = (-0.75,0.1234) :
      z = z*z + c
       |z| <= 4
     }
   newton { ; Julia set of Newton's method applied to z^3 - 1 = 0
     z = pixel :
      n = z^3 - 1 , d = 3*z^2
      z = z - n/d
       |n| >= 0.000001
     }

 We can merge them in the following way:

   ptc_mjn_A { ; overlay the Mandel set of z^2 + c with the Julia set
               ; of z^2 + (-0.75,0.1234) and the Julia set of Newton's
               ; method applied to z^3 - 1 = 0
               ; Modified for if..else logic, April 1997
     cr = real(scrnpix) + imag(scrnpix)
     r = cr - 3 * trunc(cr / real(3))
     z = pixel
     IF (r == 0)
       c = pixel
     ELSEIF (r == 1)
       c = (-0.75,0.1234)
     ENDIF
     :
     IF (r == 2)
       n = z^3 - 1 , d = 3*z^2 , z = z - n/d
       PTC_bailout = |n| >= 0.000001
     ELSE
       z = z*z + c
       PTC_bailout = |z| <= 4
     ENDIF
     PTC_bailout
     }


3 - Second PTC Method: Overlaying four fractals ("32-bit PTC")
==============================================================
 The best dithering is produced by the following pattern:

                          0 1 2 3 0 1 . .
                          2 3 0 1 2 3 . .
                          0 1 2 3 0 1 . .
                          2 3 0 1 2 3 . .
                          . . . . . . . .

 and r is given by the formula:
     r = (col + 2*row) modulo 4
 or, using the parser language:
     cr = real(scrnpix) + 2 * imag(scrnpix)
     r = cr - 4 * trunc(cr / 4)

 and r can then be used as in the previous examples, to combine four
 fractals in one image.

Here is an example:
-------------------
   mand_0 {                        mand_1 {
     z = c = sin(pixel) :            z = c = pixel :
      z = z*z + c                     z = z*z + c
       |real(z)| <= 4                  |z| <= 4
     }                               }
   mand_2 {                        mand_3 {
     z = c = 1/pixel :               z = c = -pixel :
      z = z*z + c                     z = z*z + c
       |imag(z)| <= 4                  |real(z)+imag(z)| <= 4
     }                               }

   ptc_4m_A { ; overlay four Mandels with different initializations
              ; and bailout tests
              ; Isn't it terrific???
              ; Modified for if..else logic, April 1997
     cr = real(scrnpix) + 2 * imag(scrnpix)
     r = cr - 4 * trunc(cr / 4)
     IF (r == 0)
       z = c = sin(pixel)
     ELSEIF (r == 1)
       z = c = pixel
     ELSEIF (r == 2)
       z = c = 1/pixel
     ELSE
       z = c = -pixel
     ENDIF
     :
     z = z*z + c
     IF (r == 0)
       PTC_bailout = |real(z)| <= 4
     ELSEIF (r == 1)
       PTC_bailout = |z| <= 4
     ELSEIF (r == 2)
       PTC_bailout = |imag(z)| <= 4
     ELSE
       PTC_bailout = |real(z)+imag(z)| <= 4
     ENDIF
     PTC_bailout
     }


4 - Speed ups
=============
 The best way to make your formulas run a little faster would be to read or
 reread Bradley Beacham's FRMTUTOR.TXT (that'll save me having to plagiarize
 his work <g>).

4-1 - Avoid exponentiation...
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
 In the newton formula, we can replace
     n = z^3 - 1 , d = 3*z^2
 with
     z2 = z*z , n = z2*z - 1 , d = 3*z2

 This gives:

   newton_B { ; Julia set of Newton's method applied to z^3 - 1 = 0
     z = pixel :
      z2 = z*z , n = z2*z - 1 , d = 3*z2
      z = z - n/d
       |n| >= 0.000001
     }

4-2 - Avoid unnecessary calculations...
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

  Look at this formula:

  mandelvariation {
    z = c = pixel:
    z = z*z + sin(c) - 0.2
    |z| < 4
  }

  Once you notice that the expression sin(c) - .2 is the same value every
  time it is calculated for a pixel (which could be many thousands of times)
  you will get in the habit of writing formulas like this one as follows:

  mandelvariation {
    z = pixel
    c = sin(pixel) - 0.2:
    z = z*z + c
    |z| < 4
  }

  By moving the constant expression into the initialization section, the
  calculation is made only once per pixel.


4-3 - Use the algebraic rules...
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

  An expression such as

  z = (3.5 * a + 3.5 * b) / (10.5 * c)

  is reduced to the simpler

  z = (a + b) / (3 * c)

  While this example seems trivial, cases where such speedups are possible
  abound in existing formulas; in more complicated formulas, the algebraic
  reductions may not be as obvious.


5 - How to write or modify PHC and PTC formulas
===============================================
 As we've seen earlier, the PHC or PTC dithering is based on the value of
 a variable initialized by Fractint (whitesq) or in the formula (r).

 To write a PHC formula, you just have to use "whitesq" at least once.
 A PTC formula will start with these lines:
     cr = real(scrnpix) + imag(scrnpix)
     r = cr - 3 * trunc(cr / real(3))
 or these ones:
     cr = real(scrnpix) + 2 * imag(scrnpix)
     r = cr - 4 * trunc(cr / 4)

 For a good dithering, it's essential to leave the variables "whitesq", "cr"
 and "r" intact.
 For example, if you change:
     r = cr - 3 * trunc(cr / real(3))
 to:
     r = cr - 3 * trunc(cr / real(3.5))
 the values of r will be:
     0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 4, ...

 and the result will be quite disappointing.  Also, it will be helpful if
 you use the templates (including the variable names "r" and "cr") in
 exactly the form shown above.  This will make it easier to identify and
 update formulas using PHC and PTC if future changes to Fractint's formula
 parser would make such updating desirable.


6 - Conversion of existing formulas
===================================
 The following examples show typical old style PHC statements and their
 translation for Fractint 19.6.
 
6-1 - Example 1
+-+-+-+-+-+-+-+
 z = z*z + sin(z)*whitesq + pixel

   IF (whitesq)
      z = z*z + sin(z) + pixel
   ELSE
      z = z*z + pixel
   ENDIF

6-2 - Example 2
+-+-+-+-+-+-+-+
 z = z^(z + whitesq - (whitesq == 0))

   IF (whitesq)
      z = z^(z + 1)
   ELSE
      z = z^(z - 1)
   ENDIF

6-3 - Example 3
+-+-+-+-+-+-+-+
 z = (z*z + pixel)*whitesq + (exp(z) + c)*(whitesq == 0) + p1

   IF (whitesq)
      z = z*z + pixel + p1
   ELSE
      z = exp(z) + c + p1
   ENDIF

6-4 - Example 4: bailout test
+-+-+-+-+-+-+-++-+-+-+-+-+-+-
 The best way to translate a bailout test that uses whitesq is to assign its
 value to a variable and to end the formula with this variable.
 For example:

   (|z| <= 4 && whitesq == 0) || (|n| >= 0.000001 && whitesq)

 will read as follow:

   IF (whitesq)
      PHC_bailout = |n| >= 0.000001
   ELSE
      PHC_bailout = |z| <= 4
   ENDIF
   PHC_bailout

 Of course, if the iterated section already has an IF block controlled by
 whitesq, we can put the "PHC_bailout =" statements in this block as in the
 example below:

   phc_mn_A { ; overlay the Mandel set of z^2 + c with the Julia
              ; set of Newton's method applied to z^3 - 1 = 0
     z = c = pixel :
      n = z^3 - 1 , d = 3*z^2
      z = (z*z + c) * (whitesq == 0) + (z - n/d) * whitesq
       (|z| <= 4 && whitesq == 0) || (|n| >= 0.000001 && whitesq)
   }

   phc_mn_A { ; overlay the Mandel set of z^2 + c with the Julia
              ; set of Newton's method applied to z^3 - 1 = 0
              ; Modified for if..else logic, April 1997
      z = pixel :
      IF (whitesq)
         n = z^3 - 1 , d = 3*z^2 , z = z - n/d
         PHC_bailout = |n| >= 0.000001
      ELSE
         z = z*z + pixel , PHC_bailout = |z| <= 4
      ENDIF
      PHC_bailout
      }


7 - Notes about the formula parser
==================================

7-1 - Calculation modes
-+-+-+-+-+-+-+-+-+-+-+-
 Fractint provides two calculation modes: integer math and floating point
 math.

 Though it often produces very nice images, integer math has an important
 limitation: you can't use numbers greater than 255.999... In integer mode,
 when you *think* you're using say 372, Fractint uses 116 (372-256=116).
 For this reason, the Fractint developers decided to force the floating
 point mode when the formula parser detects the use of one of the predefined
 variables "scrnpix", "scrnmax" and "maxit".

7-2 - What's wrong with 3 * trunc(cr / 3) ?
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
 When you run a formula in floating point mode, the formula parser uses
 some tricks to optimize the code.  Trunc(cr / 3) is the victim of one of
 these tricks.

 The problem is this: trunc(cr/3) is replaced by trunc(cr*(1/3)), but since
 1/3 is represented internally as .33333..., cr*(1/3) is slightly less than
 cr/3.  If cr is a multiple of 3, trunc(cr/3) therefore returns one less
 than you would expect.  For example trunc(6/3) calculates as
 trunc(6*.3333333...) or trunc(1.9999...), which in turn evaluates to 1
 instead of the expected result of 2.

 Replacing 3 with real(3) circumvents this problem and yields the desired
 result.

7-3 - Precedence
-+-+-+-+-+-+-+-+
 Precedence is a way to make mathematical expressions more readable by using
 less parentheses.  For a better comprehension of this section, you might
 want to look at the table of precedence in the Fractint documentation.

 The following expressions are mathematically equivalent because division and
 multiplication have a higher precedence than addition and subtraction (this
 means that divisions and multiplications will be performed before additions
 and subtraction):

                2+(3*((5*3)+(4/5))*(7-5))
                2 + 3 * (5*3 + 4/5) * (7 - 5)

 (they both evaluate to 96.8)
 I must confess that I tend to prefer the second one... (OK, I'm cheating,
 I just added a few white spaces... <g>).

 Now, let's see another example:
 -------------------------------
 In this expression:
               (|z| <= 4) && (whitesq == 0)

 the parentheses mean that the comparisons must be performed before the
 logical AND.  Comparisons have a higher precedence than logical operators
 thus, we can remove the parentheses:
               |z| <= 4 && whitesq == 0

 However, with

       (|z| <= 4 && whitesq == 0) || (|n| >= 0.000001 && whitesq)

 Can we remove the parentheses?  The answer is: no!  Without parentheses,
 and since we know that comparisons are performed first, this expression has
 the following format:
                A && B || C && D

 "&&" and "||" have the same precedence and in such a case, the expression
 must be calculated from the left to the right.  Just look at this:
                (1 && 1) || (1 && 0) =
                   1     ||    0     = 1

                  1 && 1 || 1 && 0 =
                    1    || 1 && 0 =
                         1    && 0 = 0


8 - Limitations of PHC and PTC
==============================
 With the new variables introduced in Fractint 19.5, PHC and PTC formulas
 are now resolution independent and the image can be interrupted, saved and
 restored.  Panning an even number of pixels for PHC images or multiples of
 3 for "24-bit PTC's" and multiples of 4 for "32-bit PTC's is possible
 without artifacts.

 All PHC and PTC formulas require passes=1.

 The use of symmetry in PHC or PTC formulas or par files is not recommended
 since symmetry alters the pattern along the axes and results in horizontal
 or vertical lines.


9 - Conclusion
==============
 That's all for now!  I hope you found this text interesting and useful.
 I'm planning an update of Bradley Beacham's Formula Tutorial which could
 include this text and any subject you'd like to see treated.
