Strange behaviour

M

Michele

Please forgive me for the neverending code down here but I cannot find a
rational explanation of the output of this simple program (really!).
Soluzione class has a double[,] field to represent a matrix. A method
named init() fills this matrix with random numbers. The main constructor
requires an int param (fCosto) which is _not_used_ inside init(). Every
time I instantiate a Soluzione object the matrix is filled by init().
The incredible thing is that if I create more than 9 objects where fCosto
= 3, there is always at least one of them whose matrix contains absurd
values! This does _not_ happen for objects constructed passing 1,2 or 4!

Any suggestions?

I compile with .NET 1.1 SP1 fully patched.

Thanks in advance!

Michael

------------------------------------------------------------------------------------
using System;
using TransGene;

using System.Collections;
namespace Test
{
class Tester: IComparer
{
[STAThread]
static void Main(string[] args)
{
Tester t = new Tester();
int[] prod = {5,5,20,15,15};
int[] req = {8,8,8,8,8,20};
int tot = 10;
Soluzione[] p1 = new Soluzione[tot];
Soluzione[] p2 = new Soluzione[tot];
for (int i = 0; i < p1.Length; i++) {
p1 = new Soluzione(prod, req, 3);
p2 = new Soluzione(prod, req, 1);
}
Array.Sort(p1,t);
Array.Sort(p2,t);
Console.WriteLine("Fitness "+p1[0].GetFCosto()
+"="+ p1[0].Fitness());
Console.Write(p1[0]);
Console.WriteLine("Fitness "+p2[0].GetFCosto()
+"="+ p2[0].Fitness());
Console.Write(p2[0]);
Console.ReadLine();
}

public int Compare(object o1, object o2) {
Soluzione x = (Soluzione) o1;
Soluzione y = (Soluzione) o2;
// ordino in modo decrescente
return x.Confronta(y);
}
}
}
--------------------------------------------------------------------------------------------

using System;

namespace TransGene
{
public class Soluzione {

private double[,] u;
private int nS;
private int nD;
private int[] prod;
private int[] req;
private int fCosto;

private static Random rand = new Random();

public Soluzione(int[] prod, int[] req, int fCosto) {
nS = prod.Length;
nD = req.Length;
this.req = req;
this.prod = prod;
this.fCosto= fCosto;
u = new double[nS,nD];
this.Init();
}

public Soluzione(Soluzione x) {
nS = x.nS;
nD = x.nD;
req = x.req;
prod = x.prod;
fCosto = x.fCosto;
u = new double[nS,nD];
this.Init();
}

private Soluzione() {
/* costruttore vuoto:
*
* - variabili a 0
* - oggetti a null */
}

public static Soluzione Vuota(Soluzione x) {
Soluzione v = new Soluzione();
v.nS = x.nS;
v.nD = x.nD;
v.req = x.req;
v.prod = x.prod;
v.fCosto = x.fCosto;
v.u = new double[v.nS,v.nD];
return v;
}

private void Init() {
/*Inizializzazione casuale della matrice.
Eseguo nS*nD posizionamenti casuali e
un aggiustamento finale.*/
/* indice di riga (sorgente) */
int si;
/* indice di colonna (destinazione) */
int dj;
/* output corrente della sorgente i */
double sumProdIJ;
/* input corrente della destinazione j*/
double sumReqIJ;
double delta;
double alpha;
for (int c = 0; c < nD*nS; c++) {
si = rand.Next(nS);
dj = rand.Next(nD);
sumProdIJ = 0;
for (int d = 0; d < nD; d++) sumProdIJ += u[si,d];
sumReqIJ = 0;
for (int s = 0; s < nS; s++) sumReqIJ += u[s,dj];
delta = Math.Min(prod[si]-sumProdIJ, req[dj]-sumReqIJ);
alpha = rand.NextDouble();
u[si,dj] += (alpha*delta);
}
/* aggiustamento*/
for (si = 0; si < nS; si++)
for (dj = 0; dj < nD; dj++) {
sumProdIJ = 0;
for (int d = 0; d < nD; d++) sumProdIJ += u[si,d];
sumReqIJ = 0;
for (int s = 0; s < nS; s++) sumReqIJ += u[s,dj];
delta = Math.Min(prod[si]-sumProdIJ, req[dj]-sumReqIJ);
u[si,dj] += delta;
}
}

public double[,] GetU() {
return u;
}

public int GetNS() {
return nS;
}

public int GetND() {
return nD;
}

public Soluzione Clona() {
Soluzione clone = new Soluzione(this);
clone.u = (double[,])this.u.Clone();
return clone;
}

public double Fitness () {
double costo = 0;
double cIJ = 0;
for (int si = 0; si < nS; si++)
for (int dj = 0; dj < nD; dj++) {
switch (fCosto) {
case 1:
cIJ = Math.Pow((Math.Abs(si-dj)+1),2)*u[si,dj];
break;
case 2:
cIJ =
Math.Pow((Math.Abs(si-dj)+1),2)*Math.Pow(u[si,dj], 2);
break;
case 3:
cIJ =
Math.Abs(si*dj-11)*Math.Sqrt(u[si,dj])+Math.Sqrt(u[si,dj]);
break;
case 4:
cIJ = Math.Abs(si*dj-11)*Math.Pow(u[si,dj],
2)+Math.Pow(u[si,dj], 4);
break;
default:
break;
}
costo += cIJ;
}
return costo;
}

public double Merce() {
double merce = 0;
for (int si = 0; si < nS; si++)
for (int dj = 0; dj < nD; dj++)
merce += u[si,dj];
return merce;
}

public Soluzione Muta() {
Soluzione z = this.Clona();
// scelgo a caso un elemento
int si = rand.Next(z.nS);
int dj = rand.Next(z.nD);
double[,] uZ = z.u;
// a caso lo setto al min (0) o al max
uZ[si,dj] = rand.NextDouble() >= 0.5 ? 0 :
Math.Min(prod[si],req[dj]);
// aggiusto la soluzione
for (si = 0; si < z.nS; si++)
for (dj = 0; dj < z.nD; dj++) {
double sumProdIJ = 0;
for (int d = 0; d < z.nD; d++)
sumProdIJ += uZ[si,d];
double sumReqIJ = 0;
for (int s = 0; s < z.nS; s++)
sumReqIJ += uZ[s,dj];
double delta = Math.Min(prod[si]-sumProdIJ,
req[dj]-sumReqIJ);
// alpha = 1 sottinteso
uZ[si,dj] = Math.Max(uZ[si,dj]+delta, 0);
}
return z;
}

public int[] GetProd() {
return prod;
}

public int[] GetReq() {
return req;
}

public int GetFCosto() {
return fCosto;
}

// rimpiazzare con CompareTo
public int Confronta(Soluzione x) {
return this.Fitness().CompareTo(x.Fitness());
}

public bool Uguale(Soluzione x) {
bool uguali = true;
for (int i = 0; i < nS && uguali; i++)
for (int j = 0; j < nD && uguali; j++)
uguali = u[i,j] == x.u[i,j];
return uguali;
}

public override string ToString() {
string s = "";
for (int i = 0; i < nS; i++) {
for (int j = 0; j < nD; j++) {
// s += Math.Round(u[i,j],2).ToString("0.00") + "\t";
s += "u["+i+","+j+"] ="+u[i,j] + "\n";
}
s+="\n";
}
s+="\n";
return s;
}

}

}
----------------------------------------------------------------------------------------------
This is the output
----------------------------------------------------------------------------------------------

Fitness 3=Non un numero reale (that is 'not a number' in Italian)
u[0,0] =0,645759544586035
u[0,1] =0
u[0,2] =0,0175906380334083
u[0,3] =0,349247457857778
u[0,4] =0,0210873891839998
u[0,5] =3,96631497033878

u[1,0] =0,286085618731453
u[1,1] =0,372272107842662
u[1,2] =1,2791667337149
u[1,3] =2,25893076399279
u[1,4] =0,0900398541882886
u[1,5] =0,71350492152991

u[2,0] =3,52830816941484
u[2,1] =5,272095936
u[2,2] =4,32616900310448
u[2,3] =4,57385969305198
u[2,4] =8,75662771182562E-06
u[2,5] =2,29955844180099

u[3,0] =2,10553080996468
u[3,1] =2,26539317651639
u[3,2] =0
u[3,3] =-1,77635683940025E-15 ----> it is negative! absurd!
u[3,4] =0
u[3,5] =10,6290760135189

u[4,0] =1,43431585730299
u[4,1] =0,0902387796409421
u[4,2] =2,37707362514721
u[4,3] =0,817962085097459
u[4,4] =7,888864
u[4,5] =2,39154565281139


Fitness 1=383,121099950505
u[0,0] =4,7550011217406
u[0,1] =0,241038878259402
u[0,2] =0,00395999999999999
u[0,3] =0
u[0,4] =0
u[0,5] =0

u[1,0] =3,0289
u[1,1] =0,5442669362372
u[1,2] =0,910992251562801
u[1,3] =0,366624599999999
u[1,4] =0,1492162122
u[1,5] =0

u[2,0] =0,190926198835202
u[2,1] =1,84422971053786
u[2,2] =3,5556601809682
u[2,3] =0,00214166337232413
u[2,4] =0,031324627313322
u[2,5] =14,3757176189731

u[3,0] =0
u[3,1] =5,192
u[3,2] =3,529387567469
u[3,3] =5,51189017097053
u[3,4] =0,0236308592012779
u[3,5] =0,743091402359193

u[4,0] =0,0251726794242
u[4,1] =0,178464474965537
u[4,2] =0
u[4,3] =2,11934356565715
u[4,4] =7,7958283012854
u[4,5] =4,88119097866772
-----------------------------------------------------------------------------------------------
 
J

Jon Skeet [C# MVP]

Please forgive me for the neverending code down here but I cannot find a
rational explanation of the output of this simple program (really!).
Soluzione class has a double[,] field to represent a matrix. A method
named init() fills this matrix with random numbers. The main constructor
requires an int param (fCosto) which is _not_used_ inside init(). Every
time I instantiate a Soluzione object the matrix is filled by init().
The incredible thing is that if I create more than 9 objects where fCosto
= 3, there is always at least one of them whose matrix contains absurd
values! This does _not_ happen for objects constructed passing 1,2 or 4!

It's very hard to know what's wrong without an explanation of what the
numbers are meant to mean, and why certain values are absurd. Better
than an explanation would be a shorter program which still
demonstrates the problem.

If you're only interested in the results of Init, I suggest that you
start off by removing the Fitness method and all the similarly
"uninteresting" pieces of your code.

Jon
 
S

Stanimir Stoyanov

Hello Michele,

The faulty line is the one which reads:

delta = Math.Min(prod[si] - sumProdIJ, req[dj] - sumReqIJ);

The problem is that sometimes sumReqIJ is very slightly greater than
req[dj], which results in a very small negative number. You can add a check
to round the delta value if it is found to be less than zero:

delta = Math.Min(prod[si] - sumProdIJ, req[dj] - sumReqIJ); // Referenced
row
if (delta < 0)
delta = Math.Round(delta);

Best Regards,
Stanimir Stoyanov
www.stoyanoff.info | www.aeroxp.org
 
M

Michele

In data 31 agosto 2007 alle ore 17:49:28, Stanimir Stoyanov
Hello Michele,

The faulty line is the one which reads:

delta = Math.Min(prod[si] - sumProdIJ, req[dj] - sumReqIJ);

The problem is that sometimes sumReqIJ is very slightly greater than
req[dj], which results in a very small negative number. You can add a
check to round the delta value if it is found to be less than zero:

delta = Math.Min(prod[si] - sumProdIJ, req[dj] - sumReqIJ); //
Referenced row
if (delta < 0)
delta = Math.Round(delta);

Best Regards,
Stanimir Stoyanov
www.stoyanoff.info | www.aeroxp.org

Oh yeah! Thank you very much for your patience! I have forgotten the
lessons of numerical analysis :(

One more question, it's a matter of style:

Which version of AllNegative a good programmer should use?

bool AllNegative(int[] a) {
bool negative = true;
for (int i = 0; i < a.Length && negative; i++)
negative = a<0;
return negative;
}

bool AllNegative(int[] a) {
foreach (int x in a)
if (x>0) return false;
return true;
}

I think the first one is a bit too "compiler styled" :)

Have a nice day!

Michael
 
S

Stanimir Stoyanov

One more question, it's a matter of style:
Which version of AllNegative a good programmer should use?

bool AllNegative(int[] a) {
bool negative = true;
for (int i = 0; i < a.Length && negative; i++)
negative = a<0;
return negative;
}

bool AllNegative(int[] a) {
foreach (int x in a)
if (x>0) return false;
return true;
}


I personally prefer the for-each approach. I believe it does not have any
noticeable performance impact and is more readable.

Best Regards,
Stanimir Stoyanov
www.stoyanoff.info | www.aeroxp.org
 
J

Jon Skeet [C# MVP]

Stanimir Stoyanov said:
One more question, it's a matter of style:
Which version of AllNegative a good programmer should use?

bool AllNegative(int[] a) {
bool negative = true;
for (int i = 0; i < a.Length && negative; i++)
negative = a<0;
return negative;
}

bool AllNegative(int[] a) {
foreach (int x in a)
if (x>0) return false;
return true;
}


I personally prefer the for-each approach. I believe it does not have any
noticeable performance impact and is more readable.


Or in .NET 3.5:

bool AllNegative(int[] a)
{
return a.All(x => x < 0);
}

Note that there's a difference between the two routines above, however
- the first one will return false if there's a zero element, the second
won't.
 
S

Stanimir Stoyanov

Or in .NET 3.5:
bool AllNegative(int[] a)
{
return a.All(x => x < 0);
}

The lambda expession is indeed a more "handy" example but if I had to have
backward compatibility in mind I would use a for-each loop instead.
Note that there's a difference between the two routines above, however
- the first one will return false if there's a zero element, the second
won't.

Good point, I guess it is up to Michele to decide whether or not to exclude
zero.

Best Regards,
Stanimir Stoyanov
www.stoyanoff.info | www.aeroxp.org
 
J

Jon Skeet [C# MVP]

Stanimir Stoyanov said:
Or in .NET 3.5:

bool AllNegative(int[] a)
{
return a.All(x => x < 0);
}

The lambda expession is indeed a more "handy" example but if I had to have
backward compatibility in mind I would use a for-each loop instead.

Sure. I'm just in C# 3 land at the moment, and enjoying all these
examples where it makes life easier :)
 
C

Christof Nordiek

In data 31 agosto 2007 alle ore 17:49:28, Stanimir Stoyanov
One more question, it's a matter of style:
Which version of AllNegative a good programmer should use?

bool AllNegative(int[] a) {
bool negative = true;
for (int i = 0; i < a.Length && negative; i++)
negative = a<0;
return negative;
}

bool AllNegative(int[] a) {
foreach (int x in a)
if (x>0) return false;
return true;
}


besides the difference between for and foreach the first example will always
test each element of the array while the second example only tests until it
finds the first non-negative.
This can have a huge performance impact, depending on the content and length
of the arrays searched.

This is independant of for/foreach since also a for loop can be exited with
return

Christof
 
J

Jon Skeet [C# MVP]

besides the difference between for and foreach the first example will always
test each element of the array while the second example only tests until it
finds the first non-negative.

Nope - the first will quite when it finds the first non-negative
element too. Look at the for loop's condition:

i < a.Length && negative

Jon
 
G

Guest

besides the difference between for and foreach the first example will
always test each element of the array while the second example only tests
until it finds the first non-negative.

Actually, the "i < a.Length && negative" in the loop means it will exit the
loop as soon as it finds the first negative.

So, it is does come purely down to the difference between foreach() and
for() loops ;-)

Personally, I would use the foreach version, as it is easier to read.
I'm not sure which would be better for performance

HTH


--
Ged Moretta
Senior Software Engineer
AppSense Ltd
www.appsense.com

-----------------------------------------------------------------------
This signature isn't automatic. I have to type it manually every time.
Christof Nordiek said:
In data 31 agosto 2007 alle ore 17:49:28, Stanimir Stoyanov
One more question, it's a matter of style:
Which version of AllNegative a good programmer should use?

bool AllNegative(int[] a) {
bool negative = true;
for (int i = 0; i < a.Length && negative; i++)
negative = a<0;
return negative;
}

bool AllNegative(int[] a) {
foreach (int x in a)
if (x>0) return false;
return true;
}


besides the difference between for and foreach the first example will
always test each element of the array while the second example only tests
until it finds the first non-negative.
This can have a huge performance impact, depending on the content and
length of the arrays searched.

This is independant of for/foreach since also a for loop can be exited
with return

Christof
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top