Processing math: 100%

Friday, March 17, 2017

Binomial

In a nonlinear model I needed to use the following expression in a model equation:

y=(xk)pk(1p)(xk)

Here x is the only decision variable. The integer version of “n choose k” is well known:

(nk)=n!k!(nk)!

For fractional values we can generalize this to:

(xy)=Γ(x+1)Γ(y+1)Γ(xy+1)

where Γ(.) indicates the gamma function, defined by

Γ(z)=0xz1exdx

image

In GAMS we have the binomial(x,y) function for this. The problem is that x can become rather large, while k is a small integer, say k=0,,4. For some values of x this leads to very inaccurate results and even overflows in subsequent calculations.

E.g.: 

scalars
  x
/112.8/
  k
/2/
;
parameter y;
y(
"binomial"
) = binomial(x,k);
y(
"log"
) = exp(loggamma(x+1)-loggamma(k+1)-loggamma(x-k+1));
display
y;

yields the wrong result:

----      8 PARAMETER y 

binomial 1.0000E+299,    log         6305.520

The logarithmic version is correct.

Instead of using the logarithmic version:

(xk)=exp(logΓ(x+1)logΓ(k+1)logΓ(xk+1))

we can also exploit that k is a small integer. From:

Γ(z+1)=zΓ(z)

we have:

(xk)=x(x1)(xk+1)Γ(xk+1)k!Γ(xk+1)=x(x1)(xk+1)k!=ki=1(xi+1)k!

In GAMS:

scalars
  x
/112.8/
  k
/2/
;
parameter y;
y(
"binomial"
) = binomial(x,k);
y(
"log"
) = exp(loggamma(x+1)-loggamma(k+1)-loggamma(x-k+1));
set i /1*2/
;
y(
"prod") = prod
(i,x-i.val+1)/fact(k);
display
y;

with results:

----     10 PARAMETER y 

binomial 1.0000E+299,    log         6305.520,    prod        6305.520

I used this last “product” version in the model.

Note that the overflow in the binomial function does not happen for all (or even most) large values:

scalars
  x
/1112.8/
  k
/2/
;
parameter y;
y(
"binomial"
) = binomial(x,k);
y(
"log"
) = exp(loggamma(x+1)-loggamma(k+1)-loggamma(x-k+1));
set i /1*2/
;
y(
"prod") = prod
(i,x-i.val+1)/fact(k);
display
y;

gives:

----     10 PARAMETER y 

binomial 618605.520,    log      618605.520,    prod     618605.520

No comments:

Post a Comment