#region License Information
/* HeuristicLab
* Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using HeuristicLab.Algorithms.ParameterlessPopulationPyramid;
using HeuristicLab.Random;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ParameterlessPopulationPyramid.Test {
[TestClass]
public class EnumerableBoolEqualityComparerTest {
private static EnumerableBoolEqualityComparer compare = new EnumerableBoolEqualityComparer();
MersenneTwister rand = new MersenneTwister();
private void randFill(IList data, MersenneTwister rand) {
for (int i = 0; i < data.Count; i++) {
data[i] = rand.Next(2) == 1;
}
}
[TestMethod]
[TestProperty("Time", "short")]
[TestCategory("Algorithms.ParameterlessPopulationPyramid")]
public void EnumerableBoolEqualsTest() {
bool[] array = new bool[10];
// Referencially equal
randFill(array, rand);
Assert.IsTrue(compare.Equals(array, array));
// Clones equal
var another = (bool[])array.Clone();
Assert.IsTrue(compare.Equals(array, another));
// Flipping a bit makes unequal
int flip = rand.Next(array.Length - 1);
another[flip] = !another[flip];
Assert.IsFalse(compare.Equals(array, another));
// Equality doesn't depend on container
List list = new List(array);
Assert.IsTrue(compare.Equals(list, array));
Assert.IsFalse(compare.Equals(list, another));
}
[TestMethod]
[TestProperty("Time", "short")]
[TestCategory("Algorithms.ParameterlessPopulationPyramid")]
public void EnumerableBoolHashCollisionTest() {
int collisions = 0;
bool[] array = new bool[100];
randFill(array, rand);
int original = compare.GetHashCode(array);
bool[] another = (bool[])array.Clone();
// Perform random walk around string checking for hash collisions
for (int i = 0; i < array.Length * array.Length; i++) {
int flip = rand.Next(array.Length - 1);
another[flip] = !another[flip];
int hash = compare.GetHashCode(another);
if (hash == original) {
// unequal sequences with same hash value
if (!array.SequenceEqual(another)) collisions++;
} else {
// unequal hash should mean unequal sequence
Assert.IsFalse(array.SequenceEqual(another));
}
// Keep the walk from getting too far afield
if (i % array.Length == 0) {
another = (bool[])array.Clone();
}
}
// A very lose upper bound, this only fails if you get more than sqrt(N) collisions per attempt
Assert.IsTrue(collisions < array.Length);
}
[TestMethod]
[TestProperty("Time", "short")]
[TestCategory("Algorithms.ParameterlessPopulationPyramid")]
public void EnumerableBoolHashSetTest() {
HashSet set = new HashSet(compare);
bool[] array = new bool[40];
randFill(array, rand);
set.Add(array);
// Same object not added
set.Add(array);
Assert.AreEqual(1, set.Count);
// Copy of object not allowed
var another = (bool[])array.Clone();
set.Add(another);
Assert.AreEqual(1, set.Count);
// Flipping a bit makes unequal
int flip = rand.Next(array.Length - 1);
another[flip] = !another[flip];
set.Add(another);
Assert.AreEqual(2, set.Count);
// Add random solutions which are 1 bit different from array to the set
set.Clear();
List added = new List();
for (int i = 0; i < array.Length * 10; i++) {
// flip a bit at random
another = (bool[])array.Clone();
flip = rand.Next(array.Length - 1);
another[flip] = !another[flip];
bool unique = set.Add(another);
bool actuallyUnique = true;
foreach (var previous in added) {
if (previous.SequenceEqual(another)) {
actuallyUnique = false;
}
}
Assert.AreEqual(actuallyUnique, unique);
if (actuallyUnique) {
added.Add(another);
}
}
}
}
}