Galaxiset
Galaxiset

Reputation: 69

Random number not creating random results

First I would like to say that I am aware of different topics on true Randomness with seeds and how new Random() is created depending on Environment.TickCount. Despite all that I couldn't figure out what my problem is. I'm trying to create a population of 100 graphs for use in Graph Coloring Genetic Algorithm. Every single population consists of set number of edges and set number of nodes. Every node has an index number and a random initial color. That initial color is what I want to random. The colors are ints between 1 and 10. But every single population looks the same, same nodes got same colors. I probably might have missed something simple but I just cannot figure it out. Any help would be appreciated.

CreatePopulation.cs

class CreatePopulation
{

    private static Solution CreateRandomSolution(Graph graph, int colorsCount)
    {
        Solution solution = new Solution(graph, colorsCount);
        for (int node = 0; node < graph.Nodes.Count; node++)
        {
            solution.assignColor(node, Program.RandomNumber(1, 10));
        }

        return solution;
    }

    public static List<Solution> CreateRandomPopulation(Graph graph, int populationSize)
    {
        List<Solution> list = new List<Solution>();
        for (int i = 0; i < populationSize; i++)
        {
            list.Add(CreateRandomSolution(graph, 10));
        }
            return list;
    }

}

Solution.cs holding future implementation of fitness methods and other methods needed for algorithm

  class Solution
{
    private int colorsCount;
    private List<Vertex> edges;
    private List<Node> nodes;

    private Solution(List<Vertex> edges, List<Node> nodes, int colorsCount)
    {
        this.colorsCount = colorsCount;
        this.edges = edges;
        this.nodes = nodes;
    }

    public Solution(Graph graph, int colorsCount)
    {
        edges = graph.Vertices;
        this.colorsCount = colorsCount;
        this.nodes = graph.Nodes;
    }

    public void assignColor(int index, int color)
    {
        nodes[index].color = color;
    }

}

Program.cs with main function

 class Program
{
    public static readonly Random Random = new Random();

    private static double MutationRate = 0.05;

    private static double CrossoverRate = 0.7;

    private static int Colors = 10;

    private static int GenerationCount = 100;

    private static int PopulationSize = 100;

    private static readonly object syncLock = new object();

    public static int RandomNumber(int min, int max)
    {
        lock (syncLock)
        {
            return Random.Next(min, max);
        }
    }

    static void Main(string[] args)
    {
        var graph = new Graph(@"C:\Users\Pawel\Desktop\lab1\GraphColoring-branch\bin\Debug\geom20.col");
        var initPopulation = CreatePopulation.CreateRandomPopulation(graph, PopulationSize);
        Console.ReadLine();
    }


}

Node.cs

namespace Graph
{
    class Node
    {
        public int number { get; set; }
        public int color { get; set; }

        public Node(int number)
        {
            this.number = number;
        }
        public Node() { }
    }
}

Update Changed the way I create a new List in Solution.cs but would like to know if it can be done in a nicer way.

 public Solution(Graph graph, int colorsCount)
    {
        this.edges = graph.Vertices;
        this.colorsCount = colorsCount;
        this.nodes = new List<Node>(graph.Nodes.Count);
        for (int i = 0; i < graph.Nodes.Count; i++)
        {
            this.nodes.Add(new Node{color = graph.Nodes[i].color, number = graph.Nodes[i].number});
        }
    }

Upvotes: 0

Views: 118

Answers (1)

Scott Chamberlain
Scott Chamberlain

Reputation: 127543

The problem is every single one of your Solution objects are working from the same instance of List<Vertex> and List<Node>. So Random is working correctly, the real problem is you are overwriting the values for the previous solutions when generate the next solution.


The only constructor I see you use is

Solution solution = new Solution(graph, colorsCount);

In there you do

public Solution(Graph graph, int colorsCount)
{
    edges = graph.Vertices;
    this.colorsCount = colorsCount;
    this.nodes = graph.Nodes;
}

This is just copying the reference of graph.Vertices and graph.Nodes, if any Solution modifies one of the items in the collections all Solutions get modified.

To fix this you need to make a deep copy of those two lists. You did not show what a Vertex or Node was, however if they are classes just doing

public Solution(Graph graph, int colorsCount)
{
    edges = graph.Vertices.ToList();
    this.colorsCount = colorsCount;
    this.nodes = graph.Nodes.ToList();
}

will not be enough because that will only create a shallow copy of the list, your call to nodes[index].color = color; will still modify the nodes in all of the other graphs because although the lists are now separate references the elements in the list are still shared across Solution objects. You need something similar to

class Solution
{
    private int colorsCount;
    private List<Vertex> edges;
    private List<Node> nodes;

    private Solution(List<Vertex> edges, List<Node> nodes, int colorsCount)
    {
        this.colorsCount = colorsCount;
        this.edges = edges;
        this.nodes = nodes.Select(old => old.Clone()).ToList();
    }

    public Solution(Graph graph, int colorsCount)
    {
        edges = graph.Vertices;
        this.colorsCount = colorsCount;
        this.nodes = graph.Nodes.Select(old => old.Clone()).ToList();
    }

    public void assignColor(int index, int color)
    {
        nodes[index].color = color;
    }

}


class Node
{
    public int number { get; set; }
    public int color { get; set; }

    public Node(int number)
    {
        this.number = number;
    }
    public Node() { }

    public Node Clone()
    {
        var newNode = new Node();
        newNode.number = this.number;
        newNode.color = this.color;
        return newNode;
    }
}

Upvotes: 2

Related Questions