#region License Information /* HeuristicLab * Copyright (C) 2002-2012 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; using System.Collections.Generic; using System.Linq; using HeuristicLab.Core; namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Common { public static class ExtensionMethods { /// /// Simply enumerates the sequence by moving over all elements. /// /// The type of the items that are to be enumerated. /// The enumerable that contains the items. public static void Enumerate(this IEnumerable source) { var enumerator = source.GetEnumerator(); while (enumerator.MoveNext()) ; } /// /// Selects an element from an enumerable randomly with equal probability for each element. If the sequence is empty, selected will be false and default(T) will be returned. /// /// The type of the items that are to be selected. /// The enumerable that contains the items. /// The random number generator, its NextDouble() method must return a value in the range [0;1). /// True if an element was selected, false otherwise (only because of an empty sequence). /// The selected item. public static T ChooseRandomOrDefault(this IEnumerable source, IRandom random, out bool selected) { if (source == null) throw new ArgumentNullException("SelectRandomOrDefault: source is null"); uint counter = 1; selected = false; T selectedItem = default(T); foreach (T item in source) { if (counter * random.NextDouble() < 1.0) { // use multiplication instead of division selectedItem = item; selected = true; } counter++; } return selectedItem; } /// /// Selects an element from an enumerable randomly with equal probability for each element. /// /// The type of the items that are to be selected. /// The enumerable that contains the items. /// The random number generator, its NextDouble() method must return a value in the range [0;1). /// The selected item. public static T ChooseRandom(this IEnumerable source, IRandom random) { if (source == null) throw new ArgumentNullException("SelectRandom: source is null"); if (!source.Any()) throw new ArgumentException("SelectRandom: sequence is empty."); uint counter = 1; T selectedItem = default(T); foreach (T item in source) { if (counter * random.NextDouble() < 1.0) // use multiplication instead of division selectedItem = item; counter++; } return selectedItem; } /// /// Shuffles an enumerable and returns an new enumerable according to the Fisher-Yates shuffle. /// /// /// Source code taken from http://stackoverflow.com/questions/1287567/c-is-using-random-and-orderby-a-good-shuffle-algorithm. /// Note that this is an online shuffle, but the source enumerable is transformed into an array. /// /// The type of the items that are to be shuffled. /// The enumerable that contains the items. /// The random number generator, its Next(int) method must deliver uniformly distributed random numbers. /// An enumerable with the elements shuffled. public static IEnumerable Shuffle(this IEnumerable source, IRandom random) { T[] elements = source.ToArray(); // Note i > 0 to avoid final pointless iteration for (int i = elements.Length - 1; i > 0; i--) { // Swap element "i" with a random earlier element it (or itself) int swapIndex = random.Next(i + 1); yield return elements[swapIndex]; elements[swapIndex] = elements[i]; // we don't actually perform the swap, we can forget about the // swapped element because we already returned it. } // there is one item remaining that was not returned - we return it now yield return elements[0]; } /// /// Walks an operator graph in that it jumps from one operator to all its operator parameters and yields each operator it touches. /// Cycles are detected and not walked twice. /// /// The operator where the walk starts (is also yielded). /// An enumeration of all the operators that could be found. public static IEnumerable Walk(this IOperator initial) { var open = new Stack(); var visited = new HashSet(); open.Push(initial); while (open.Any()) { IOperator current = open.Pop(); if (visited.Contains(current)) continue; visited.Add(current); foreach (var parameter in current.Parameters.OfType()) { if (typeof(IOperator).IsAssignableFrom(parameter.DataType)) { if (parameter.Value != null) open.Push((IOperator)parameter.Value); } } yield return current; } } } }