clinton has asked for the wisdom of the Perl Monks concerning the following question:
I'm trying to come up with a formula that I can use to represent distance from a central point, and will return a boost value in a range, eg 0..10.
This formula can accept two (or maybe 3) variables:
 importance: this controls the upper limit of the range, eg 0..10, 0..100
 radius: ie any distance within this inner radius should be pretty much as important as any other point within this radius
 dropoff: (optional) how quickly the boost should drop off as distance increases
My basic formula is:
boost = importance / ((radius + distance) ** dropoff)
For instance, an importance of 100, a dropoff of 0.5 and a radius of 0 gives me a curve like:
16 : @@@@@@@@@@@@@@@@@@@@@@@@@
32 : @@@@@@@@@@@@@@@@@
64 : @@@@@@@@@@@@
128 : @@@@@@@@
256 : @@@@@@
512 : @@@@
1024 : @@@
2048 : @@
4096 : @
8192 : @
But with a radius of 1000, I get a much smaller range:
16 : @@@
32 : @@@
64 : @@@
128 : @@
256 : @@
512 : @@
1024 : @@
2048 : @
4096 : @
8192 : @
I would like to change the formula to make the upper limit of the range dependent only on importance and not on radius. For the life of me I can't figure out how to do that.
PS: distance can be considered to have an upper limit of, eg, 10,000km if that helps
PPS: As an optional extra, it would be nice to be able to configure the rate of dropoff without affecting the upper limit of the range, but I can live without it
Re: [OT] Normalizing the return result of an exponential formula
by kennethk (Abbot) on Apr 14, 2011 at 18:00 UTC

Based on your post and discussion with BrowserUk, my first thought is a Gaussian  see Normal_distribution. The functional form gives you a width parameter and the normalization is known, so it will satisfy your importance and radius requirements. You could probably implement your boost parameter by modifying the exponent on x. Perhaps something like:
#!/usr/bin/perl w
use warnings;
use strict;
sub boost {
my ($x, $importance, $radius, $drop) = @_;
return $importance * exp( ($x/$radius)**$drop );
}
my $imp = 1000;
my $rad = 100;
my $drop = 1;
for (map 2**$_, 1..15) {
my $boost = boost($_, $imp, $rad, $drop);
my $bar = "@" x ($boost/$imp*50);
printf "%6d %s %.1f\n", $_, $bar, $boost;
}
__END__
2 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 980.2
4 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 960.8
8 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 923.1
16 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 852.1
32 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 726.1
64 @@@@@@@@@@@@@@@@@@@@@@@@@@ 527.3
128 @@@@@@@@@@@@@ 278.0
256 @@@ 77.3
512 6.0
1024 0.0
2048 0.0
4096 0.0
8192 0.0
16384 0.0
32768 0.0
Update: Fixed typo in call order.  [reply] [d/l] 

kennethk that looks like just the ticket! Many thanks
 [reply] 
Re: [OT] Normalizing the return result of an exponential formula
by Eliya (Vicar) on Apr 14, 2011 at 17:29 UTC

Maybe I'm misunderstanding, but why not simply return the max value when the distance falls within the radius, and apply the dropoff to what falls outside? In code:
sub boost {
my ($dist, $imp, $rad, $drop) = @_;
if ($dist <= $rad) {
return $imp;
} else {
return $imp / ($dist  $rad + 1) ** $drop;
}
}
my $imp = 1000;
my $rad = 125;
my $drop = 0.5;
for (map 2**$_, 4..13) {
my $boost = boost($_, $imp, $rad, $drop);
my $bar = "@" x ($boost/($imp*0.02));
printf "%6d %s %.1f\n", $_, $bar, $boost;
}
__END__
16 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1000.0
32 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1000.0
64 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1000.0
128 @@@@@@@@@@@@@@@@@@@@@@@@@@@@ 577.4
256 @@@@ 87.4
512 @@ 50.8
1024 @ 33.4
2048 @ 22.8
4096 15.9
8192 11.1
 [reply] [d/l] 

Hi Eliya
That's kinda what I want, I think.
It also handles the case where the distance is 1cm, making the boost way too large. Although, I probably want the decline for distances greater than the radius to be less steep, ie the remaining range should be stretched. Still experimenting, but I think that by combining what you suggest with something like in Re: [OT] Normalizing the return result of an exponential formula, I might get a reasonable result.
Rereading your code, I see you handle the decline, taking the radius into account. That could be it! Thanks
 [reply] [d/l] 
Re: [OT] Normalizing the return result of an exponential formula
by BrowserUk (Pope) on Apr 14, 2011 at 16:38 UTC

I would like to change the formula to make the upper limit of the range dependent only on importance and not on radius.
Why not just omit the radius from the equation?
That way, the 'boost' become dependant upon just the distance from the perimeter of the circle regardless of the circles size:
sub x{
my( $i, $r, $d, $o ) = @_;
return $i / $d**$o;
}
print x( 100, 0, $_, 0.5 ) for map 2**$_, 4..13;;
25
17.6776695296637
12.5
8.83883476483184
6.25
4.41941738241592
3.125
2.20970869120796
1.5625
1.10485434560398
print x( 100, 1000, $_, 0.5 ) for map 2**$_, 4..13;;
25
17.6776695296637
12.5
8.83883476483184
6.25
4.41941738241592
3.125
2.20970869120796
1.5625
1.10485434560398
Examine what is said, not who speaks  Silence betokens consent  Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
 [reply] [d/l] 

What I was trying to achieve with radius was to give the user the ability to say: "anything within this circle is really important", where that circle might be a country, or a province. So the curve might look like:
16 : @@@@@@@@@@@@@@@@@@@@@@@@@ 
32 : @@@@@@@@@@@@@@@@@@@@@@@@  inside radius
64 : @@@@@@@@@@@@@@@@@@@@@@ 
128 : @@@@@@@@@@@@@@
256 : @@@@@@@@@@
512 : @@@@@@
1024 : @@@
2048 : @@
4096 : @
8192 : @
 [reply] [d/l] 

Then I misunderstand what you meant by "2. radius: ie any distance within this inner radius should be pretty much as important as any other point within this radius"
To me that reads as, everything inside the circle is equally important, but as the distance outside that circle increases, the importance falls off exponentially. This was reinforced by your adding the distance to the radius in your formula.
As that does not appear to be the case, and as you new diagram does nothing to explain the relationship between 'radius' and 'distance', I think you are going to have to explain the relationships between the 4 input variables much more clearly?
For at least me. I'm sometimes quite good at reading between the lines, but with your latest information I cannot reconcile your formula, terminology, and stated goals.Ie.
Is 'distance' measured inside the circle? From the centre toward the edge? Or from the edge toward the centre?
Is 'boost' an exponential decline in 'importance' over 'distance'? As suggested by the term 'dropoff'. (It is a strange name for a decline in anything?)
Examine what is said, not who speaks  Silence betokens consent  Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
 [reply] 

Re: [OT] Normalizing the return result of an exponential formula
by clinton (Priest) on Apr 14, 2011 at 16:34 UTC

I suppose I could do something like:
my $max = 10_000;
$distance = $radius;
$distance = 0
if $distance < 0;
$distance *= $max/($max$radius)
then apply the formula to the new "stretched" distance.
Any more elegant way of handling it? (especially one that incorporates dropoff?)  [reply] [d/l] [select] 
Re: [OT] Normalizing the return result of an exponential formula
by (anonymized user) (Curate) on Apr 18, 2011 at 14:43 UTC

What I am missing:
 how the yvalue should tend to a limit as the distance approaches the radius (quadratically? hyperbolically? exponentially? linearly?.
 Should the function be continuous or discontinuous at the exact radius point.
 What should be the slope of the curve at that point? (or the slope as it tends to it on either side if the function should be discontinuous)
 How should the yvalue decay to 0 as distance tends to infinity (same options as my first question.
Update: I'll rephrase this all in plainer English:
If you were to draw a 2D graph of this with x is distance on the horizontal axis and y is boost on the vertical axis, and that graph represents a function f, so that y=f(x), there will be a starting value for boost where distance is 0 let's say Z = f(0). From your description, this should decay firstly to f(R), so f(R) < Z. After that it drops more rapidly towards zero. So to describe an example formula for f(x), a mathematician needs to know the shape of the curve before and after the point x=R and whether the point at x=R is smooth or a corner or whether it jumps to a different value at that point (otherwise known as a point of discontinuity). Given this information it then possible to translate the function into Perl.
 [reply] 

