Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / C# / September 2007

Tip: Looking for answers? Try searching our database.

Strange behaviour

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Michele - 31 Aug 2007 16:26 GMT
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[i] = new Soluzione(prod, req, 3);
                p2[i] = 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
-----------------------------------------------------------------------------------------------
Jon Skeet [C# MVP] - 31 Aug 2007 16:43 GMT
> Please forgive me for the neverending code down here but I cannot find a
> rational explanation of the output of this simple program (really!).
[quoted text clipped - 5 lines]
> = 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
Stanimir Stoyanov - 31 Aug 2007 16:49 GMT
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
Michele - 31 Aug 2007 18:49 GMT
In data 31 agosto 2007 alle ore 17:49:28, Stanimir Stoyanov  
<admin@nospam.stoyanoff.info> ha scritto:

> Hello Michele,
>
[quoted text clipped - 14 lines]
> 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[i]<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
Stanimir Stoyanov - 31 Aug 2007 19:01 GMT
> One more question, it's a matter of style:

> Which version of AllNegative a good programmer should use?
>
[quoted text clipped - 10 lines]
>      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
Jon Skeet [C# MVP] - 31 Aug 2007 19:27 GMT
> > One more question, it's a matter of style:
>
[quoted text clipped - 15 lines]
> 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.

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too

Stanimir Stoyanov - 31 Aug 2007 19:50 GMT
> 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
Jon Skeet [C# MVP] - 31 Aug 2007 20:08 GMT
> > Or in .NET 3.5:
> >
[quoted text clipped - 5 lines]
> 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 :)

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too

Christof Nordiek - 03 Sep 2007 13:55 GMT
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?
>
[quoted text clipped - 10 lines]
>      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
Jon Skeet [C# MVP] - 03 Sep 2007 14:01 GMT
<snip>

> 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
Ged - 03 Sep 2007 14:07 GMT
> 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

Signature

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

-----------------------------------------------------------------------
This signature isn't automatic. I have to type it manually every time.

> In data 31 agosto 2007 alle ore 17:49:28, Stanimir Stoyanov
>> One more question, it's a matter of style:
[quoted text clipped - 24 lines]
>
> Christof

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.