Error Programming Cholesky decomposition in FORTRAN 90 - algorithm

Im struggling with my thesis on wave energy devices. Since I am a newbie to FORTRAN 90, I would like to improve my programming skills. Therefore, I just picked up an example from
http://rosettacode.org/wiki/Cholesky_decomposition
and tried to implement what is explained in the homepage. Basically it is about to program the Cholesky factorization of a 3x3 matrix A. I know there are already packages that do the decomposition for Fortran, but I would like to experience myself the effort in learning how to program.
There is no error in compilation, but the results do not match. I basically find out all the elements despite of the element L(3,3). Attached, you can find the code I've created from scratch in Fortran 90:
Program Cholesky_decomp
implicit none
!size of the matrix
INTEGER, PARAMETER :: m=3 !rows
INTEGER, PARAMETER :: n=3 !cols
REAL, DIMENSION(m,n) :: A, L
REAL :: sum1, sum2
INTEGER i,j,k
! Assign values to the matrix
A(1,:)=(/ 25, 15, -5 /)
A(2,:)=(/ 15, 18, 0 /)
A(3,:)=(/ -5, 0, 11 /)
! Initialize values
L(1,1)=sqrt(A(1,1))
L(2,1)=A(2,1)/L(1,1)
L(2,2)=sqrt(A(2,2)-L(2,1)*L(2,1))
L(3,1)=A(3,1)/L(1,1)
sum1=0
sum2=0
do i=1,n
do k=1,i
do j=1,k-1
if (i==k) then
sum1=sum1+(L(k,j)*L(k,j))
L(k,k)=sqrt(A(k,k)-sum1)
elseif (i > k) then
sum2=sum2+(L(i,j)*L(k,j))
L(i,k)=(1/L(k,k))*(A(i,k)-sum2)
else
L(i,k)=0
end if
end do
end do
end do
!write output
do i=1,m
print "(3(1X,F6.1))",L(i,:)
end do
End program Cholesky_decomp
Can you tell me what is the mistake in the code? I get L(3,3)=0 when it should be L(3,3)=3. I'm totally lost, and just for the record: on the Rosetta code homepage there is no solution for fortran, so any any hint is appreciated.
Thank you very much in advance.

You want to set sum1 and sum2 to zero for each iteration of the i and k loops.

I've finally found out how to solve the problem for greater order, 4x4 matrices, etc. as presented in the link I attached above. Here is the final code:
Program Cholesky_decomp
!*************************************************!
!LBH # ULPGC 06/03/2014
!Compute the Cholesky decomposition for a matrix A
!after the attached
!http://rosettacode.org/wiki/Cholesky_decomposition
!note that the matrix A is complex since there might
!be values, where the sqrt has complex solutions.
!Here, only the real values are taken into account
!*************************************************!
implicit none
INTEGER, PARAMETER :: m=3 !rows
INTEGER, PARAMETER :: n=3 !cols
COMPLEX, DIMENSION(m,n) :: A
REAL, DIMENSION(m,n) :: L
REAL :: sum1, sum2
INTEGER i,j,k
! Assign values to the matrix
A(1,:)=(/ 25, 15, -5 /)
A(2,:)=(/ 15, 18, 0 /)
A(3,:)=(/ -5, 0, 11 /)
!!!!!!!!!!!!another example!!!!!!!
!A(1,:) = (/ 18, 22, 54, 42 /)
!A(2,:) = (/ 22, 70, 86, 62 /)
!A(3,:) = (/ 54, 86, 174, 134 /)
!A(4,:) = (/ 42, 62, 134, 106 /)
! Initialize values
L(1,1)=real(sqrt(A(1,1)))
L(2,1)=A(2,1)/L(1,1)
L(2,2)=real(sqrt(A(2,2)-L(2,1)*L(2,1)))
L(3,1)=A(3,1)/L(1,1)
!for greater order than m,n=3 add initial row value
!for instance if m,n=4 then add the following line
!L(4,1)=A(4,1)/L(1,1)
do i=1,n
do k=1,i
sum1=0
sum2=0
do j=1,k-1
if (i==k) then
sum1=sum1+(L(k,j)*L(k,j))
L(k,k)=real(sqrt(A(k,k)-sum1))
elseif (i > k) then
sum2=sum2+(L(i,j)*L(k,j))
L(i,k)=(1/L(k,k))*(A(i,k)-sum2)
else
L(i,k)=0
end if
end do
end do
end do
!write output
do i=1,m
print "(3(1X,F6.1))",L(i,:)
end do
End program Cholesky_decomp
Look forward to hear about comments, better ways to program it, corrections and any kind of feedback. Thanks 2 francescalus for answering so quickly!
Regards, lbh

Related

Solving a crackme with z3py

I want to solve a crackme with Z3. The crackme is pretty huge, but it can be simplified to what follows::
#! /usr/bin/python
import sys
T='Fguad2x-GP5_QqNi'
key=sys.argv[1]
if len(key) != 3:
print "Bad key length"
exit(1)
out=[]
for c in key:
out.append(T[ord(c)>>4 ])
out.append(T[ord(c) & 0xf])
if ''.join(out)=='--xPxN':
print "You win"
The solution is 'win'.
This sort of things could be solved with z3 I guess. I begin with translated all logic from crackme in a z3 style:
#! /usr/bin/python
from z3 import *
#Preparing data
map_array='Fguad2x-GP5_QqNi'
T=Array('T',IntSort(),IntSort())
for i,j in enumerate(map_array):
T = Store(T, ord(j), i)
sol='--xPxN'
#We know input has 3 characters
a=BitVec('a',8)
b=BitVec('b',8)
c=BitVec('c',8)
#Ignite
s=Solver()
#String key is printable
s.add(BV2Int(a)>=65,BV2Int(a)<=122)
s.add(BV2Int(b)>=65,BV2Int(b)<=122)
s.add(BV2Int(c)>=65,BV2Int(c)<=122)
#Adding constraints
s.add(Select(T,BV2Int(a>>4))==ord(sol[0]))
s.add(Select(T,BV2Int(a&0xf))==ord(sol[1]))
s.add(Select(T,BV2Int(b>>4))==ord(sol[2]))
s.add(Select(T,BV2Int(b&0xf))==ord(sol[3]))
s.add(Select(T,BV2Int(c>>4))==ord(sol[4]))
s.add(Select(T,BV2Int(c&0xf))==ord(sol[5]))
#Verify solving
print s.check()
print s.model()
Now, I have some questions:
s.check() says 'sat' so I have at least one solution?
is there a better way to define an array?
is there a way to use the characters directly?
How to get only a, b and c after solution? s.model() shows a very strange output:
$ ./stovlfw.py
sat
[b = 1,
a = 136,
c = 0,
T = [3 -> 78,
65 -> 120,
2 -> 80,
1 -> 45,
0 -> 45,
else -> 45],
k!0 = [3 -> 78,
65 -> 120,
2 -> 80,
1 -> 45,
0 -> 45,
else -> 45]]
This seems to be in contradiction with constraints (??) I'm doing something wrong, but where?
Thanks
Arrays in z3 don't behave as their C counterpart. They should not be used to model small finite collections of values. It is usually much more efficient to create different variables using list comprehensions.
Here's my alternative approach. Make a Function in z3 that lets you choose nth char from a string.
#! /usr/bin/python
from z3 import *
#Preparing data
nth = Function('nth', StringSort(), IntSort(), BitVecSort(8))
final = String('final')
sol='--xPxN'
#We know input has 3 characters
a=BitVec('a',8)
b=BitVec('b',8)
c=BitVec('c',8)
#Ignite
s=Solver()
#Adding constraints
for i,j in enumerate('Fguad2x-GP5_QqNi'):
s.add(nth(final,i)==ord(j))
s.add(nth(final,BV2Int(a>>4))==ord(sol[0]))
s.add(nth(final,BV2Int(a&0xf))==ord(sol[1]))
s.add(nth(final,BV2Int(b>>4))==ord(sol[2]))
s.add(nth(final,BV2Int(b&0xf))==ord(sol[3]))
s.add(nth(final,BV2Int(c>>4))==ord(sol[4]))
s.add(nth(final,BV2Int(c&0xf))==ord(sol[5]))
#String key is printable
s.add((a)>=65,(a)<=122)
s.add((b)>=65,(b)<=122)
s.add((c)>=65,(c)<=122)
#Verify solving Fguad2x-GP5_QqNi
print s.check()
print s.model()
print ''.join(chr(s.model()[i].as_long()) for i in [a,b,c])
s.model() can be used as a dict to retrieve variable values.
PS : upgrade your z3 to latest version for this to work.

How do I properly use a for loop in Ruby?

I'm trying to improve my Ruby skills using the Project Euler series of questions and I'm wondering why this code does not work for this question: "Even Fibonacci numbers, Problem 2"
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
My code:
def fibo(n)
first, second, sequence = 0,1,[]
for e in n
first, second = second, first + second
sequence << e if e%2 == 0
end
sequence.inject(:+)
end
puts fibo(4000000)
Any help would be appreciated!
In the line:
for e in n
4,000,000 is being substituted for n, so you are saying:
for e in 4000000
which is not a valid statement - you cannot iterate on an integer.
If you would like to iterate through all the values from 0 to n, try:
for e in (0..n)
This iterates through the values in the range 0 to n.
However, there is a deeper problem here. It looks as though you want to iterate up to the value 4000000, but instead your code would iterate through the first 4000000 Fibonacci numbers, which is much more than you want. You may want to consider saying:
while second <= 4000000
I suggest you check out Ruby Koans if you're starting out with Ruby. It's a fun way of getting used to the ways of the language.
That said your code is not calculating Fibonacci correctly, it's not summing the Fibonacci numbers and also has some other errors (for e in n is not valid because n is not an Enumerator type). Fix it like this:
def fibo(n)
first, second, sum = 0, 1, 0
loop do
first, second = second, first + second
sum += second if second%2 == 0
break if second >= n
end
sum
end

Basic Gauss Elimination solver yields wrong result

I'm a newbie to Fortran and I need to write a Gauss Elimination code to solve a 4x4 matrix. My code below returns a wrong result and I couldn't debug the problem. I'd much appreciate if you can help me.
common /grid/ A(100,100), NEQ, C(100), X(100)
open(10, file="NEQ.txt", status='unknown')
read(10,*) NEQ
close (10)
open(12, file="C1.txt", status='unknown')
do i=1,NEQ
read(12,*) C(i)
enddo
close (12)
open(11, file="A1.txt", status='unknown')
do i=1,NEQ
read(11,*) (A(i,k), k=1,NEQ)
enddo
close (11)
call SOL
open(13, file="X.txt", status='unknown')
do i=1,NEQ
write(13,*) X(i)
enddo
close (13)
stop
end
subroutine SOL
common /grid/ A(100,100), NEQ, C(100), X(100)
c Forward Reduction Phase:
do 10 K=2,NEQ
do 10 I=K,NEQ
R=A(I,K-1)/A(K-1,K-1)
C(I)=C(I)-R*C(K-1)
do 10 J=K-1,NEQ
10 A(I,J)=A(I,J)-R*A(K-1,J)
c Back Substitution Phase:
X(NEQ)=C(NEQ)/A(NEQ,NEQ)
do 30 K=NEQ-1,1,-1
X(K)=C(K)
do 20 J=K+1,NEQ
20 X(K)=X(K)-A(K,J)*X(J)
30 X(K)=X(K)/A(K,K)
return
end
For my case NEQ is read from a text file as 4
And my A1.txt is:
18, -6, -6, 0
-6, 12, 0, -6
-6, 0, 12, -6
0, -6, -6, 18
And C1.txt is:
60
0
20
0
The resultant X matrix cames out to be:
8.3333330
6.6666665
8.3333321
4.9999995
Instead of:
13.13
14.17
15.83
15.00
As Vladimir F has commented, it is extremely helpful to use at least Fortran 90 if you have to write any new code at all. It offers far better options than Fortran 77 for keeping your code structured and organised (and readable). I would like to add that implicit none is also an invaluable statement for reducing error.
That said, here is an example of what your algorithm might look like in Fortran 90 (I have written it as a function):
function gaussian_elimination(A, C) result(X)
implicit none
real, intent(inout) :: C(:), A(size(C), size(C))
real :: X(size(C))
real :: R(size(C))
integer :: i, j, neq
neq = size(C)
! Forward reduction, only two loops since reduction is now row by row
do i = 1, neq
R = A(:,i)/A(i,i)
do j = i+1, neq
A(j,:) = A(j,:) - R(j)*A(i,:)
C(j) = C(j) - R(j)*C(i)
enddo
enddo
! Back substitution, only one loop
do i = neq, 1, -1
x(i) = (C(i) - sum(A(i, i+1:) * x(i+1:))) / A(i,i)
enddo
end function gaussian_elimination
This only leaves me to wonder why you think that your result X = [8.33, 6.67, 8.33, 5.00] is incorrect? It is the right solution, which you can verify by multiplying the matrix A with it: matmul(A, X) should be (nearly) equal to C.

Non-repeating pseudo random number stream with 'clumping'

I'm looking for a method to generate a pseudorandom stream with a somewhat odd property - I want clumps of nearby numbers.
The tricky part is, I can only keep a limited amount of state no matter how large the range is. There are algorithms that give a sequence of results with minimal state (linear congruence?)
Clumping means that there's a higher probability that the next number will be close rather than far.
Example of a desirable sequence (mod 10): 1 3 9 8 2 7 5 6 4
I suspect this would be more obvious with a larger stream, but difficult to enter by hand.
Update:
I don't understand why it's impossible, but yes, I am looking for, as Welbog summarized:
Non-repeating
Non-Tracking
"Clumped"
Cascade a few LFSRs with periods smaller than you need, combining them to get a result such than the fastest changing register controls the least significant values. So if you have L1 with period 3, L2 with period 15 and L3 with some larger period, N = L1(n) + 3 * L2(n/3) + 45 * L3(n/45). This will obviously generate 3 clumped values, then jump and general another 3 clumped values. Use something other than multiplication ( such as mixing some of the bits of the higher period registers ) or different periods to make the clump spread wider than the period of the first register. It won't be particularly smoothly random, but it will be clumpy and non-repeating.
For the record, I'm in the "non-repeating, non-random, non-tracking is a lethal combination" camp, and I hope some simple though experiments will shed some light. This is not formal proof by any means. Perhaps someone will shore it up.
So, I can generate a sequence that has some randomness easily:
Given x_i, x_(i+1) ~ U(x_i, r), where r > x_i.
For example:
if x_i = 6, x_(i+1) is random choice from (6+epsilon, some_other_real>6). This guarantees non-repeating, but at the cost that the distribution is monotonically increasing.
Without some condition (like monotonicity), inherent to the sequence of generated numbers themselves, how else can you guarantee uniqueness without carrying state?
Edit: So after researching RBarryYoung's claim of "Linear Congruential Generators" (not differentiators... is this what RBY meant), and clearly, I was wrong! These sequences exist, and by necessity, any PRNG whose next number is dependent only on the current number and some global, non changing state can't have repeats within a cycle (after some initial burn it period).
By defining the "clumping features" in terms of the probability distribution of its size, and the probability distribution of its range, you can then use simple random generators with the underlying distribution and produce the sequences.
One way to get "clumpy" numbers would be to use a normal distribution.
You start the random list with your "initial" random value, then you generate a random number with the mean of the previous random value and a constant variance, and repeat as necessary. The overall variance of your entire list of random numbers should be approximately constant, but the "running average" of your numbers will drift randomly with no particular bias.
>>> r = [1]
>>> for x in range(20):
r.append(random.normalvariate(r[-1], 1))
>>> r
[1, 0.84583267252801408, 0.18585962715584259, 0.063850022580489857, 1.2892164299497422,
0.019381814281494991, 0.16043424295472472, 0.78446377124854461, 0.064401889591144235,
0.91845494342245126, 0.20196939102054179, -1.6521524237203531, -1.5373703928440983,
-2.1442902977248215, 0.27655425357702956, 0.44417440706703393, 1.3128647361934616,
2.7402744740729705, 5.1420432435119352, 5.9326297626477125, 5.1547981880261782]
I know it's hard to tell by looking at the numbers, but you can sort of see that the numbers clump together a little bit - the 5.X's at the end, and the 0.X's on the second row.
If you need only integers, you can just use a very large mean and variance, and truncate/divide to obtain integer output. Normal distributions by definition are a continuous distribution, meaning all real numbers are potential output - it is not restricted to integers.
Here's a quick scatter plot in Excel of 200 numbers generated this way (starting at 0, constant variance of 1):
scatter data http://img178.imageshack.us/img178/8677/48855312.png
Ah, I just read that you want non-repeating numbers. No guarantee of that in a normal distribution, so you might have to take into account some of the other approaches others have mentioned.
I don't know of an existing algorithm that would do this, but it doesn't seem difficult to roll your own (depending on how stringent the "limited amount of state" requirement is). For example:
RANGE = (1..1000)
CLUMP_ODDS = .5
CLUMP_DIST = 10
last = rand(RANGE)
while still_want_numbers
if rand(CLUMP_ODDS) # clump!
next = last + rand(CLUMP_DIST) - (CLUMP_DIST / 2) # do some boundary checking here
else # don't clump!
next = rand(RANGE)
end
print next
last = next
end
It's a little rudimentary, but would something like that suit your needs?
In the range [0, 10] the following should give a uniform distribution. random() yields a (pseudo) random number r with 0 <= r < 1.
x(n + 1) = (x(n) + 5 * (2 * random() - 1)) mod 10
You can get your desired behavior by delinearizing random() - for example random()^k will be skewed towards small numbers for k > 1. An possible function could be the following, but you will have to try some exponents to find your desired distribution. And keep the exponent odd, if you use the following function... ;)
x(n + 1) = (x(n) + 5 * (2 * random() - 1)^3) mod 10
How about (psuedo code)
// clumpiness static in that value retained between calls
static float clumpiness = 0.0f; // from 0 to 1.0
method getNextvalue(int lastValue)
float r = rand(); // float from 0 to 1
int change = MAXCHANGE * (r - 0.5) * (1 - clumpiness);
clumpiness += 0.1 * rand() ;
if (clumpiness >= 1.0) clumpiness -= 1.0;
// -----------------------------------------
return Round(lastValue + change);
Perhaps you could generate a random sequence, and then do some strategic element swapping to get the desired property.
For example, if you find 3 values a,b,c in the sequence such that a>b and a>c, then with some probability you could swap elements a and b or elements a and c.
EDIT in response to comment:
Yes, you could have a buffer on the stream that is whatever size you are comfortable with. Your swapping rules could be deterministic, or based on another known, reproducible psuedo-random sequence.
Does a sequence like 0, 94, 5, 1, 3, 4, 14, 8, 10, 9, 11, 6, 12, 7, 16, 15, 17, 19, 22, 21, 20, 13, 18, 25, 24, 26, 29, 28, 31, 23, 36, 27, 42, 41, 30, 33, 34, 37, 35, 32, 39, 47, 44, 46, 40, 38, 50, 43, 45, 48, 52, 49, 55, 54, 57, 56, 64, 51, 60, 53, 59, 62, 61, 69, 68, 63, 58, 65, 71, 70, 66, 73, 67, 72, 79, 74, 81, 77, 76, 75, 78, 83, 82, 85, 80, 87, 84, 90, 89, 86, 96, 93, 98, 88, 92, 99, 95, 97, 2, 91 (mod 100) look good to you?
This is the output of a small ruby program (explanations below):
#!/usr/bin/env ruby
require 'digest/md5'
$seed = 'Kind of a password'
$n = 100 # size of sequence
$k = 10 # mixing factor (higher means less clumping)
def pseudo_random_bit(k, n)
Digest::MD5.hexdigest($seed + "#{k}|#{n}")[-1] & 1
end
def sequence(x)
h = $n/2
$k.times do |k|
# maybe exchange 1st with 2nd, 3rd with 4th, etc
x ^= pseudo_random_bit(k, x >> 1) if x < 2*h
# maybe exchange 1st with last
if [0, $n-1].include? x
x ^= ($n-1)*pseudo_random_bit(k, 2*h)
end
# move 1st to end
x = (x - 1) % $n
# maybe exchange 1st with 2nd, 3rd with 4th, etc
# (corresponds to 2nd with 3rd, 4th with 5th, etc)
x ^= pseudo_random_bit(k, h+(x >> 1)) if x < 2*(($n-1)/2)
# move 1st to front
x = (x + 1) % $n
end
x
end
puts (0..99).map {|x| sequence(x)}.join(', ')
The idea is basically to start with the sequence 0..n-1 and disturb the order by passing k times over the sequence (more passes means less clumping). In each pass one first looks at the pairs of numbers at positions 0 and 1, 2 and 3, 4 and 5 etc (general: 2i and 2i+1) and flips a coin for each pair. Heads (=1) means exchange the numbers in the pair, tails (=0) means don't exchange them. Then one does the same for the pairs at positions 1 and 2, 3 and 4, etc (general: 2i+1 and 2i+2). As you mentioned that your sequence is mod 10, I additionally exchanged positions 0 and n-1 if the coin for this pair dictates it.
A single number x can be mapped modulo n after k passes to any number of the interval [x-k, x+k] and is approximately binomial distributed around x. Pairs (x, x+1) of numbers are not independently modified.
As pseudo-random generator I used only the last of the 128 output bits of the hash function MD5, choose whatever function you want instead. Thanks to the clumping one won't get a "secure" (= unpredictable) random sequence.
Maybe you can chain together 2 or more LCGs in a similar manner described for the LSFRs described here. Incement the least-significant LCG with its seed, on full-cycle, increment the next LCG. You only need to store a seed for each LCG. You could then weight each part and sum the parts together. To avoid repititions in the 'clumped' LstSig part you can randomly reseed the LCG on each full cycle.

Finding Integers With A Certain Property - Project Euler Problem 221

I've become very addicted to Project Euler recently and am trying to do this one next! I've started some analysis on it and have reduced the problem down substantially already. Here's my working:
A = pqr and
1/A = 1/p + 1/q + 1/r so pqr/A =
pq + pr + qr
And because of the first equation:
pq+pr+qr = 1
Since exactly two of p, q and r have
to be negative, we can simplify the
equation down to finding:
abc for which ab = ac+bc+1
Solving for c we get:
ab-1 = (a+b)c
c = (ab-1)/(a+b)
This means we need to find a and b for
which:
ab = 1 (mod a+b)
And then our A value with those a and
b is:
A = abc = ab(ab-1)/(a+b)
Sorry if that's a lot of math! But now all we have to deal with is one condition and two equations. Now since I need to find the 150,000th smallest integer written as ab(ab-1)/(a+b) with ab = 1 (mod a+b), ideally I want to search (a, b) for which A is as small as possible.
For ease I assumed a < b and I have also noticed that gcd(a, b) = 1.
My first implementation is straight forward and even finds 150,000 solutions fast enough. However, it takes far too long to find the 150,000 smallest solutions. Here's the code anyway:
n = 150000
seen = set()
a = 3
while len(seen) < n:
for b in range(2, a):
if (a*b)%(a+b) != 1: continue
seen.add(a*b*(a*b-1)//(a+b))
print(len(seen), (a, b), a*b*(a*b-1)//(a+b))
a += 1
My next thought was to use Stern-Brocot trees but that is just too slow to find solutions. My final algorithm was to use the Chinese remainder theorem to check if different values of a+b yield solutions. That code is complicated and although faster, it isn't fast enough...
So I'm absolutely out of ideas! Anyone got any ideas?
As with many of the Project Euler problems, the trick is to find a technique that reduces the brute force solution into something more straight forward:
A = pqr and
1/A = 1/p + 1/q + 1/r
So,
pq + qr + rp = 1 or -r = (pq - 1)/(p + q)
Without loss of generality, 0 < p < -q < -r
There exists k , 1 <= k <= p
-q = p + k
-r = (-p(p + k) – 1) / (p + -p – k) = (p^2 + 1)/k + p
But r is an integer, so k divides p^2 + 1
pqr = p(p + q)((p^2 + 1)/k + p)
So to compute A we need to iterate over p, and where k can only take values which are divisors of p squared plus 1.
Adding each solution to a set, we can stop when we find the required 150000th Alexandrian integer.
This article about Chinese remainder, fast implementation, can help you : www.codeproject.com/KB/recipes/CRP.aspx
This is more links for tools and libraries :
Tools:
Maxima
http://maxima.sourceforge.net/
Maxima is a system for the manipulation of symbolic and numerical expressions, including differentiation, integration, Taylor series, Laplace transforms, ordinary differential equations, systems of linear equations, polynomials, and sets, lists, vectors, matrices, and tensors. Maxima yields high precision numeric results by using exact fractions, arbitrary precision integers, and variable precision floating point numbers. Maxima can plot functions and data in two and three dimensions.
Mathomatic
http://mathomatic.org/math/
Mathomatic is a free, portable, general-purpose CAS (Computer Algebra System) and calculator software that can symbolically solve, simplify, combine, and compare equations, perform complex number and polynomial arithmetic, etc. It does some calculus and is very easy to use.
Scilab
www.scilab.org/download/index_download.php
Scilab is a numerical computation system similiar to Matlab or Simulink. Scilab includes hundreds of mathematical functions, and programs from various languages (such as C or Fortran) can be added interactively.
mathstudio
mathstudio.sourceforge.net
An interactive equation editor and step-by-step solver.
Library:
Armadillo C++ Library
http://arma.sourceforge.net/
The Armadillo C++ Library aims to provide an efficient base for linear algebra operations (matrix and vector maths) while having a straightforward and easy to use interface.
Blitz++
http://www.oonumerics.org/blitz/
Blitz++ is a C++ class library for scientific computing
BigInteger C#
http://msdn.microsoft.com/pt-br/magazine/cc163441.aspx
libapmath
http://freshmeat.net/projects/libapmath
Welcome to the homepage of the APMath-project. Aim of this project is the implementation of an arbitrary precision C++-library, that is the most convenient in use, this means all operations are implemented as operator-overloadings, naming is mostly the same as that of .
libmat
http://freshmeat.net/projects/libmat
MAT is a C++ mathematical template class library. Use this library for various matrix operations, finding roots of polynomials, solving equations, etc. The library contains only C++ header files, so no compilation is necessary.
animath
http://www.yonsen.bz/animath/animath.html
Animath is a Finite Element Method library entirely implemented in C++. It is suited for fluid-structure interaction simulation, and it is mathematically based on higher-order tetrahedral elements.
OK. Here's some more playing with my Chinese Remainder Theorem solution. It turns out that a+b cannot be the product of any prime, p, unless p = 1 (mod 4). This allows faster computation as we only have to check a+b which are multiples of primes such as 2, 5, 13, 17, 29, 37...
So here is a sample of possible a+b values:
[5, 8, 10, 13, 16, 17, 20, 25, 26, 29, 32, 34, 37, 40, 41, 50, 52, 53, 58, 61, 64, 65, 68, 73, 74, 80, 82, 85, 89, 97, 100]
And here is the full program using the Chinese Remainder Theorem:
cachef = {}
def factors(n):
if n in cachef: cachef[n]
i = 2
while i*i <= n:
if n%i == 0:
r = set([i])|factors(n//i)
cachef[n] = r
return r
i += 1
r = set([n])
cachef[n] = r
return r
cachet = {}
def table(n):
if n == 2: return 1
if n%4 != 1: return
if n in cachet: return cachet[n]
a1 = n-1
for a in range(1, n//2+1):
if (a*a)%n == a1:
cachet[n] = a
return a
cacheg = {}
def extended(a, b):
if a%b == 0:
return (0, 1)
else:
if (a, b) in cacheg: return cacheg[(a, b)]
x, y = extended(b, a%b)
x, y = y, x-y*(a//b)
cacheg[(a, b)] = (x, y)
return (x, y)
def go(n):
f = [a for a in factors(n)]
m = [table(a) for a in f]
N = 1
for a in f: N *= a
x = 0
for i in range(len(f)):
if not m[i]: return 0
s, t = extended(f[i], N//f[i])
x += t*m[i]*N//f[i]
x %= N
a = x
while a < n:
b = n-a
if (a*b-1)%(a+b) == 0: return a*b*(a*b-1)//(a+b)
a += N
li = [5, 8, 10, 13, 16, 17, 20, 25, 26, 29, 32, 34, 37, 40, 41, 50, 52, 53, 58, 61, 64, 65, 68, 73, 74, 80, 82, 85, 89, 97, 100]
r = set([6])
find = 6
for a in li:
g = go(a)
if g:
r.add(g)
#print(g)
else:
pass#print(a)
r = list(r)
r.sort()
print(r)
print(len(r), 'with', len(li), 'iterations')
This is better but I hope to improve it further (for example a+b = 2^n seem to never be solutions).
I've also started considering basic substitutions such as:
a = u+1 and b = v+1
ab = 1 (mod a+b)
uv+u+v = 0 (mod u+v+2)
However, I can't see much improvement with that...

Resources