```Contributor: DANIEL DOUBROVKINE

(*
Daniel Doubrovkine - dblock@infomaniak.ch
part of the Expression Calculator 2.0 Multithread, destribute freely
http://www.infomaniak.ch/~dblock/express.htm
(ref. Haussman, Simple Algebra course at the University of Geneva)

"Euler's Indice"
euler's indice is a insomorphe function phi: Zm->Z1*Z2...Zn
means the decomposition of a number into a primes product is unique
with phi(n):=n*(1-1/p1)*...*(1-1/pn) where pi are primes taken once
from the decomposition.
ex: (following algorith steps):
168=2*84
168=2*2*42
168=2*2*2*21
168=2*2*2*3*7 where all are primes!
now, phi(168)=168*(1-1/2)(1-1/3)(1-1/7)=48 (this is always an integer!)
thus, 168 has 48 primes to it.
*)

(*defining a dynamic primes array, so this function will never be limited*)
type
PPrimesArray=^TPrimesArray;
TPrimesArray=record
Prime:longint;
NextPrime:PPrimesArray;
end;

(*adding a prime to the array*)
var
TempPrimes:PPrimesArray;
begin
TempPrimes:=AllPrimes;
while (TempPrimes<>nil) do begin
if TempPrimes^.Prime=Prime then exit;
TempPrimes:=TempPrimes^.NextPrime;
end;
new(TempPrimes);
TempPrimes^.Prime:=Prime;
TempPrimes^.NextPrime:=AllPrimes;
AllPrimes:=TempPrimes;
end;

(*removing the primes array*)
procedure PrimesRemove(AllPrimes: PPrimesArray);
var
TempPrimes:PPrimesArray;
begin
while AllPrimes<>nil do begin
TempPrimes:=AllPrimes;
AllPrimes:=AllPrimes^.NextPrime;
Dispose(TempPrimes);
end;
end;

(*by the way, this routine uses some code from swag*)
function GeneratePrimes(var AllPrimes: PPrimesArray;n: longint):longint;
procedure CalculateTPrime(n: longint);
var
TempPrime: PPrimesArray;
CurrentPrime: LongInt;
prime:boolean;
number,max_div,divisor,lastprime:longint;
begin
CurrentPrime:=AllPrimes^.Prime;
for number:=CurrentPrime to MaxLongInt do begin
max_div:=Round(Sqrt(number)+0.5);
prime:=number mod 2 <> 0;
divisor:=3;
while prime and (divisor0;
divisor:=divisor+2;
end;
if prime then begin
if AllPrimes^.Prime-1) and (n<1) then begin
writeln('Prime requires values |x|>1');
halt;
end;
if n>maxlongint then begin
writeln('prime limit too large');
halt;
end;

n:=abs(n);

if (n<=AllPrimes^.Prime) then begin
TempPrime:=AllPrimes;
while TempPrime<>nil do begin
CurrentPrime:=TempPrime^.Prime;
if n>=TempPrime^.Prime then begin
GeneratePrimes:=TempPrime^.Prime;
exit;
end;
TempPrime:=TempPrime^.NextPrime;
end;
end;
CalculateTPrime(n);
GeneratePrimes:=AllPrimes^.Prime;
end;

function phi(var AllPrimes:PPrimesArray;Value:longint):longint;
var
UsedPrimes:PPrimesArray;
(*this is partailly from swag...*)
procedure Factoring(lin:longint);
var
lcnt:longint;
begin
lcnt:=2;
if GeneratePrimes(AllPrimes,lin)=lin then begin
write(' ',lin);
end else
while(lcnt*lcnt<=lin) do begin
if (lin mod lcnt) = 0 then begin
if GeneratePrimes(AllPrimes,lcnt)<>lcnt then factoring(lcnt)
else begin
write(' ',lcnt);
end;
if GeneratePrimes(AllPrimes,lin div lcnt)<>(lin div lcnt) then factoring(lin div lcnt)
else begin
write(' ',lin div lcnt);
end;
exit;
end;
lcnt:=lcnt+1;
end;
end;

var
FinalResult:real;
TempPrimes:PPrimesArray;
begin
if Value=0 then begin
Phi:=0;
exit;
end;
Value:=Abs(Value);
FinalResult:=Value;
UsedPrimes:=nil;
write('Decomposition of ',Value:0,':');
Factoring(Value);
writeln;
TempPrimes:=UsedPrimes;
while TempPrimes<>nil do begin
FinalResult:=FinalResult*(1-1/TempPrimes^.Prime);
TempPrimes:=TempPrimes^.NextPrime;
end;
phi:=trunc(FinalResult);
PrimesRemove(UsedPrimes);
writeln('Euler''s indice for ',Value:0,' is ',trunc(FinalResult));
writeln('(there are ',trunc(FinalResult),' primes to ',Value,')');
end;

var
AllPrimes: PPrimesArray;
begin
Phi(AllPrimes,168);
PrimesRemove(AllPrimes);
end.

```