POV-Ray : Newsgroups : povray.general : Isosurface hills : Function expansion and optimization Server Time
10 Aug 2024 09:18:13 EDT (-0400)
  Function expansion and optimization  
From: Lummox JR
Date: 19 Mar 2000 00:15:34
Message: <38D463C7.5117@aol.com>
Chris Huff wrote:
> Ah, ok. I somehow had the impression you were using MegaPOV source as
> your base. I found the code neatly arranged in a single block starting
> with this:
> #ifdef IsoBlobPatch
> /* Functions added by Lummox JR, June 1999 */

Hmm. That's interesting; I'll have to check out the MegaPOV code at some
point.
I think the additional functions can easily be separated from the
isoblob sections at any rate, though. The isoblob code is fairly
independent of the function changes I made.

> > I really don't know how this could be included in the function code
> > without greatly modifying it, since the code wasn't intended to go past
> > 3 arguments per function. (The so-called 4-argument functions are
> > actually just a declared function number plus 3 more arguments.) I've
> > always wanted to see if that could be arbitrarily extended; the
> > challenge is definitely intriguing enough for me to take it up sometime.
> 
> I would certainly be interested in the results. It would also be nice to
> allow user defined functions to have a variable number of parameters,
> how possible do you think that would be?

I'd really love to see that too. What would probably be a lot more
useful, however, would be a set of functions to work on vectors.

Another change I've contemplated before is the addition of two new
functions: precalc() and expr(), which would basically be used to give
the function "local variables" of a sort. Each function could be
analyzed after parsing, and reorganized to do any repeated or
unnecessary calculations first. As an example of what I mean:

sqrt(x^2+y^2)+sqrt(x^2+z^2)+sqrt(y^2+z^2)

There are several very simple changes that can be made here:

- Any ^2 reference can be changed to sqr(), which will be faster.
  (Similarly, optimization can change things to sqrt() and cub().)
- sqr(x), sqr(y), and sqr(z) can all be precalculated and then used
  later.

The optimized expression, although it looks more complicated, would save
considerable evaluation time:

precalc(sqr(z),
  precalc(sqr(y),
    precalc(sqr(x),
      sqrt(expr(3)+expr(2))+sqrt(expr(3)+expr(1)+sqrt(expr(2)+expr(1))
  )))

And as you can see, expr(N) references the Nth cached value; basically
all the code has to do is check the very bottom of the stack and work
upward, since the precalc() function has already calculated the first
value. (Actually, the code I've got in mind is 0-based, not 1-based, but
you get the idea.)
These functions wouldn't really be user-accessible; the possibility of
screwing things up is too great. The resulting code might or might not
be longer--sometimes length will be saved, and other times the overhead
of the extra numbers will take a toll.
I've written some test code (which I haven't even looked at in months)
that will analyze the function for a repeated expression, keeping track
of whether it actually has a complete expression or not, and whether the
constants match, etc. It looks for the longest expressions first, to
maximize the savings. And if those can be further broken down, so be it. 

> > BTW, I've gone ahead and added the Noise_raw function to texture.c. I
> > gave it a function name "bozo", to avoid having to add one more keyword
> > to the parser.
> 
> Sounds interesting, although the use of "bozo" would have to be changed
> before it is distributed...
> Maybe call it rnoise()?

I dunno; I think "bozo" makes sense enough for the purpose. People
writing a function aren't likely to confuse it with the pigment, which
matches noise3d() anyway. I'd prefer a better name for it myself,
though, so perhaps rnoise would be a very worthwhile change. I chose
this one because it's a pain in the butt to add tokens to the parser.

> > I added two new functions while I was in there:
> >
> > range(v,min,max)  -- basically a shortcut for min(max(v,min),max)
> 
> Why not call it "clamp()"? I think it is more explanatory.
> BTW, I use this code when I need this function, although having it hard
> coded is probably a good idea:
> #declare clamp = function {min(y, max(x, z))}
> clamp(value, minimum, maximum)

Clamp() is explanatory, sure, although I think range() is equally
explanatory in this case. Actually "range" was the first word that came
to mind, since the goal is to constrain values to a specific range. The
beauty of using range is that its purpose is fairly evident, and it
already has a token in the parser. No token modifications required.

I'd like some open critique of my function-optimization idea, really. I
haven't tested any of the code I have in mind, though when I developed
it I did a number of mental run-throughs. And of course more can be
done.
I think any of these optimizations are possible and even desirable,
however:

- Any expression made more than once (or a function with all the same
  arguments) can be calculated once and re-used. The longer the
  expression or the more it is used, it will be more likely to save
  both space and time. (Testing for a complete expression is difficult,
  since you have to check on how each function affects the stack.)
- Any operations based solely on constants can be evalulated at
  optimization time and reduced to one single constant. Thus sqrt(2)
  and even a simple -(1) needn't be calculated each time.
- n+(-m) can be changed to n-m
- n*(a/m) can be changed to (n*a)/m by association
- n*(-1) or n/(-1) can be changed to (-n)
- n*a+n*b can be replaced with n*(a+b)
- n*n or n^2 can be replaced with sqr(n)
- sqr(n)*n or n^3 can be replaced with cub(n)
- n^a*n^b can be replaced with n^(a+b)

This basic design won't catch some simple things like (x-y)=-(y-x), but
it's a good starting point. I'd be willing to bet that a lot of
functions use the same complex expression more than once (mine often
do), and as such any optimization at parse-time would be of enormous
benefit down the line.

Lummox JR


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.