Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.Random/3.3/RandomEnumerable.cs @ 16883

Last change on this file since 16883 was 16580, checked in by bburlacu, 6 years ago

#2976: Merged r16496 into stable.

  • Property svn:mergeinfo set to (toggle deleted branches)
    /trunk/HeuristicLab.Random/3.3/RandomEnumerable.csmergedeligible
    /branches/1721-RandomForestPersistence/HeuristicLab.Random/3.3/RandomEnumerable.cs10321-10322
    /branches/2916_IndexedDataTableSerialization/HeuristicLab.Random/3.3/RandomEnumerable.cs15918
    /branches/Algorithms.GradientDescent/HeuristicLab.Random/3.3/RandomEnumerable.cs5516-5520
    /branches/Async/HeuristicLab.Random/3.3/RandomEnumerable.cs13329-15286
    /branches/Benchmarking/sources/HeuristicLab.Random/3.3/RandomEnumerable.cs6917-7005
    /branches/CloningRefactoring/HeuristicLab.Random/3.3/RandomEnumerable.cs4656-4721
    /branches/CodeEditor/HeuristicLab.Random/3.3/RandomEnumerable.cs11700-11806
    /branches/DataAnalysis Refactoring/HeuristicLab.Random/3.3/RandomEnumerable.cs5471-5808
    /branches/DataAnalysis SolutionEnsembles/HeuristicLab.Random/3.3/RandomEnumerable.cs5815-6180
    /branches/DataAnalysis/HeuristicLab.Random/3.3/RandomEnumerable.cs4458-4459,​4462,​4464
    /branches/DataPreprocessing/HeuristicLab.Random/3.3/RandomEnumerable.cs10085-11101
    /branches/GP.Grammar.Editor/HeuristicLab.Random/3.3/RandomEnumerable.cs6284-6795
    /branches/GP.Symbols (TimeLag, Diff, Integral)/HeuristicLab.Random/3.3/RandomEnumerable.cs5060
    /branches/HLScript/HeuristicLab.Random/3.3/RandomEnumerable.cs10331-10358
    /branches/HeuristicLab.DatasetRefactor/sources/HeuristicLab.Random/3.3/RandomEnumerable.cs11570-12508
    /branches/HeuristicLab.Problems.DataAnalysis.Trading/HeuristicLab.Random/3.3/RandomEnumerable.cs6123-9799
    /branches/HeuristicLab.Problems.Orienteering/HeuristicLab.Random/3.3/RandomEnumerable.cs11130-12721
    /branches/HiveStatistics/sources/HeuristicLab.Random/3.3/RandomEnumerable.cs12440-12877
    /branches/LogResidualEvaluator/HeuristicLab.Random/3.3/RandomEnumerable.cs10202-10483
    /branches/NET40/sources/HeuristicLab.Random/3.3/RandomEnumerable.cs5138-5162
    /branches/NSGA-II Changes/HeuristicLab.Random/3.3/RandomEnumerable.cs12033-12122
    /branches/ParallelEngine/HeuristicLab.Random/3.3/RandomEnumerable.cs5175-5192
    /branches/ProblemInstancesRegressionAndClassification/HeuristicLab.Random/3.3/RandomEnumerable.cs7568-7810
    /branches/QAPAlgorithms/HeuristicLab.Random/3.3/RandomEnumerable.cs6350-6627
    /branches/Restructure trunk solution/HeuristicLab.Random/3.3/RandomEnumerable.cs6828
    /branches/RuntimeOptimizer/HeuristicLab.Random/3.3/RandomEnumerable.cs8943-9078
    /branches/ScatterSearch (trunk integration)/HeuristicLab.Random/3.3/RandomEnumerable.cs7787-8333
    /branches/SlaveShutdown/HeuristicLab.Random/3.3/RandomEnumerable.cs8944-8956
    /branches/SpectralKernelForGaussianProcesses/HeuristicLab.Random/3.3/RandomEnumerable.cs10204-10479
    /branches/SuccessProgressAnalysis/HeuristicLab.Random/3.3/RandomEnumerable.cs5370-5682
    /branches/Trunk/HeuristicLab.Random/3.3/RandomEnumerable.cs6829-6865
    /branches/UnloadJobs/HeuristicLab.Random/3.3/RandomEnumerable.cs9168-9215
    /branches/VNS/HeuristicLab.Random/3.3/RandomEnumerable.cs5594-5752
    /branches/crossvalidation-2434/HeuristicLab.Random/3.3/RandomEnumerable.cs12948-12950
    /branches/histogram/HeuristicLab.Random/3.3/RandomEnumerable.cs5959-6341
    /branches/symbreg-factors-2650/HeuristicLab.Random/3.3/RandomEnumerable.cs14232-14825
    /trunk/sources/HeuristicLab.Problems.TestFunctions.MultiObjective/HeuristicLab.Random/3.3/RandomEnumerable.cs14175
    /trunk/sources/HeuristicLab.Random/3.3/RandomEnumerable.cs9493,​9496,​9498,​9504-9506,​9515-9517,​9520-9521,​9523,​9530-9531,​9534-9537,​9540,​9542-9544,​9552-9555,​9568-9569,​9587,​9590-9592,​9600,​9607-9608,​9610-9611,​9613,​9618,​9623-9624,​9626,​9647-9649,​9652,​9657-9660,​9664-9666,​9675,​9692,​9695,​9699,​9702,​9710,​9714,​9718-9720,​9740-9741,​9751-9752,​9755,​9762,​9764-9775,​9777-9778,​9782-9786,​9792,​9794-9795,​9803-9812,​9816-9822,​9824-9825,​9828,​9830,​9833,​9837-9841,​9845,​9848-9851,​9855,​9859-9860,​9863,​9865-9868,​9871,​9893-9897,​9900-9902,​9905-9907,​9910,​9915-9916,​9919-9921,​9928,​9930,​9934-9935,​9938-9941,​9944,​9946,​9949,​9955-9956,​9958-9959,​9964-9965,​9973-9975,​9978,​9980-9982,​9988-9989,​9991-9992,​9994-9995,​9997,​10000-10005,​10009-10010,​10015,​10130,​10149-10150,​10154,​10170-10171,​10173-10176,​10195-10196,​10212-10213,​10231,​10261,​10273,​10291-10292,​10295,​10298,​10323-10324,​10346,​10348,​10355,​10359-10360,​10362-10363,​10365-10366,​10368,​10375,​10378,​10391,​10401,​10406-10407,​10414,​10417-10418,​10428,​10432-10433,​10435,​10440,​10448,​10453,​10460,​10465-10466,​10469-10470,​10472,​10474-10477,​10480,​10484,​10486,​10488-10500,​10503-10504,​10506,​10510-10512,​10519-10523,​10526,​10531,​10540-10541,​10543,​10545,​10561-10566,​10575-10578,​10596-10597,​10599,​10601-10607,​10639,​10642-10643,​10646,​10651-10653,​10727,​10731,​10745,​10747,​10761,​10767,​10774,​10787-10791,​10793-10794,​10796,​10799-10800,​10826,​10857-10862,​10865,​10885,​10889,​10894-10896,​10924,​10926-10927,​10937,​10941,​10953,​10955-10956,​10958-10961,​10963,​10975,​10983-10986,​10988-10989,​10996,​11007-11008,​11012-11014,​11019,​11024-11027,​11031,​11034-11035,​11048,​11050-11052,​11056-11058,​11060,​11065-11067,​11071,​11074-11082,​11086-11088,​11091-11093,​11095-11097,​11099-11100,​11102,​11108,​11111-11117,​11123-11128,​11131,​11135,​11153,​11156,​11161,​11214,​11241,​11243,​11248-11251,​11256,​11263,​11274,​11280,​11282-11283,​11285-11287,​11290,​11292,​11294-11296,​11298,​11300,​11302,​11306,​11308-11309,​11313,​11315,​11317,​11324,​11326,​11330-11332,​11337-11348,​11352-11353,​11361-11362,​11364-11367,​11380-11382,​11384,​11389,​11391-11392,​11394,​11403-11404,​11410-11411,​11417-11420,​11422,​11426-11430,​11432,​11434-11437,​11439-11448,​11450,​11453,​11455-11457,​11464,​11466-11467,​11469-11472,​11474,​11477-11480,​11483,​11494-11498,​11504,​11514-11515,​11523-11525,​11532-11533,​11536,​11540-11542,​11544-11545,​11547-11549,​11555,​11557,​11581,​11592,​11596-11597,​11599-11600,​11605,​11608,​11610,​11615-11616,​11618,​11623,​11631,​11634,​11650-11652,​11657,​11675,​11679-11680,​11703-11706,​11715,​11717,​11721,​11723-11725,​11734-11736,​11756-11758,​11762-11764,​11766,​11771-11772,​11781-11782,​11784,​11787-11790,​11794,​11807-11811,​11815-11816,​11818-11819,​11822,​11825-11831,​11833-11837,​11839-11840,​11853-11854,​11856,​11877-11879,​11882,​11890,​11909,​11912-11918,​11921,​11930,​11933-11934,​11936,​11938-11939,​11942,​11945,​11948,​11950-11951,​11955-11956,​11958-11961,​11963,​11967,​11970-11971,​11978,​11982-11984,​11987-11994,​11996,​11998-12004,​12015-12744,​12755,​12770,​12772,​12787,​12790-12798,​12801,​12807,​12810-12812,​12816-12819,​12835-12837,​12839,​12844-12846,​12851,​12855,​12868,​12873,​12875,​12878-12879,​12883,​12885-12886,​12889,​12894-12907,​12911-12918,​12920-12921,​12925-12927,​12932,​12934,​12936-12938,​12940,​12946-12948,​12953-12954,​12959-12961,​12971-12973,​12975-12978,​12981-12983,​12986-12987,​13000-13005,​13008,​13014,​13016,​13024-13027,​13030,​13033-13034,​13036,​13038-13040,​13051,​13054-13060,​13064-13066,​13078,​13080,​13087,​13093-13094,​13100-13104,​13109,​13116,​13118-13121,​13131,​13133,​13136-13143,​13154,​13157-13160,​13162-13165,​13167-13169,​13173,​13180-13181,​13183,​13186,​13198,​13200-13201,​13203-13205,​13209-13210,​13212,​13214,​13217-13219,​13222-13228,​13230-13239,​13241-13245,​13247-13257,​13260-13261,​13266-13271,​13288,​13300,​13307-13309,​13311,​13313-13315,​13318,​13392-13393,​13395,​13402,​13406,​13411,​13413-13415,​13419-13420,​13425,​13427-13430,​13433-13434,​13438-13442,​13445-13447,​13450,​13458,​13471,​13473-13474,​13484,​13491,​13494,​13498-13504,​13507-13514,​13516-13517,​13525-13526,​13529,​13534-13535,​13539-13540,​13549-13550,​13552,​13560,​13566-13567,​13570-13573,​13579-13582,​13584-13586,​13592-13593,​13597,​13614,​13616,​13621,​13626-13629,​13635,​13644-13646,​13648,​13650-13655,​13657-13662,​13666,​13669-13671,​13675-13684,​13690-13693,​13695,​13697-13705,​13707-13709,​13711,​13715,​13721,​13724,​13746,​13760-13761,​13764-13766,​13779,​13784-13786,​13796,​13800-13802,​13807,​13813,​13826,​13838,​13863,​13869,​13889-13891,​13895,​13898-13901,​13916-13917,​13921-13922,​13925,​13932-13935,​13938-13939,​13941-13942,​13958,​13963-13964,​13975,​13978,​13983-13987,​13992-13993,​13998,​14000-14001,​14007-14008,​14011,​14014-14017,​14024-14026,​14032,​14034,​14036-14037,​14056-14057,​14071,​14082-14083,​14095-14096,​14098-14100,​14102-14103,​14107,​14109-14110,​14118-14122,​14124-14127,​14130-14132,​14135-14136,​14140,​14142,​14144,​14150,​14152,​14155-14160,​14162-14164,​14167-14169,​14174-14175,​14177-14179,​14181,​14189,​14191,​14196,​14198,​14200,​14202-14207,​14209,​14221-14224,​14226-14230,​14234-14236,​14244-14247,​14250,​14255-14258,​14260,​14267-14268,​14270-14273,​14282,​14284-14300,​14307,​14314-14316,​14319,​14322,​14332,​14340-14350,​14352-14358,​14367-14369,​14371-14372,​14376,​14378,​14381-14382,​14384,​14388,​14390-14391,​14393-14394,​14396,​14400,​14405,​14407-14408,​14412,​14418,​14422-14423,​14425,​14432-14439,​14443,​14457-14458,​14463-14465,​14468-14469,​14475-14476,​14478-14479,​14481-14483,​14486,​14493-14494,​14504,​14506-14509,​14516-14517,​14519,​14522-14523,​14527-14529,​14531-14533,​14548,​14553,​14561,​14582,​14597,​14623,​14630,​14647,​14651-14652,​14654,​14656,​14659-14660,​14662-14663,​14672,​14685,​14687,​14692,​14697,​14706,​14708-14709,​14718,​14721-14722,​14726,​14732,​14734,​14737-14738,​14740,​14748-14750,​14769-14770,​14772-14775,​14779-14781,​14786,​14789-14791,​14793,​14805,​14809-14810,​14817,​14819-14820,​14826-14832,​14839-14843,​14845-14847,​14851-14854,​14857,​14860-14865,​14871,​14877,​14882,​14886,​14889-14890,​14899,​14901,​14904,​14911-14912,​14916,​14918,​14936-14938,​14940,​14943-14951,​14955,​14971,​14978-14979,​14982,​14984,​14987,​14992,​14995,​15002-15010,​15013,​15015-15016,​15023-15024,​15026,​15029,​15040,​15042,​15044,​15046-15054,​15058,​15067-15077,​15079-15080,​15083-15088,​15091-15096,​15098-15099,​15102-15107,​15110-15114,​15119-15126,​15129,​15135,​15139,​15156-15158,​15160,​15162-15169,​15172-15173,​15178-15181,​15184-15185,​15187,​15191-15192,​15194,​15198,​15201,​15203,​15205-15211,​15213-15214,​15221-15228,​15230,​15233-15236,​15240-15241,​15246-15248,​15264-15266,​15271,​15276,​15287-15288,​15300-15302,​15312,​15325-15327,​15329,​15335-15336,​15339,​15357-15358,​15361,​15367-15368,​15370-15372,​15376,​15383,​15388,​15390,​15393,​15395-15398,​15400,​15402,​15408-15409,​15419,​15427,​15447-15448,​15452,​15461,​15464,​15478,​15480-15481,​15483,​15486,​15498-15499,​15502,​15505,​15513,​15517-15518,​15532,​15534,​15545,​15548,​15551,​15556,​15560,​15570,​15591,​15594,​15596,​15598,​15607,​15610-15611,​15621-15623,​15626,​15637-15638,​15645,​15665,​15667,​15672-15674
File size: 13.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Core;
26
27namespace HeuristicLab.Random {
28  public static class RandomEnumerable {
29    public static IEnumerable<int> SampleRandomNumbers(int maxElement, int count) {
30      return SampleRandomNumbers(Environment.TickCount, 0, maxElement, count);
31    }
32
33    public static IEnumerable<int> SampleRandomNumbers(int start, int end, int count) {
34      return SampleRandomNumbers(Environment.TickCount, start, end, count);
35    }
36
37    //algorithm taken from progamming pearls page 127
38    //IMPORTANT because IEnumerables with yield are used the seed must be specified to return always
39    //the same sequence of numbers without caching the values.
40    public static IEnumerable<int> SampleRandomNumbers(int seed, int start, int end, int count) {
41      int remaining = end - start;
42      var mt = new FastRandom(seed);
43      for (int i = start; i < end && count > 0; i++) {
44        double probability = mt.NextDouble();
45        if (probability < ((double)count) / remaining) {
46          count--;
47          yield return i;
48        }
49        remaining--;
50      }
51    }
52
53    /// <summary>
54    /// Chooses one elements from a sequence giving each element an equal chance.
55    /// </summary>
56    /// <remarks>
57    /// Runtime complexity is O(1) for sequences that are of type <see cref="IList{T}"/> and
58    /// O(N) for all other.
59    /// </remarks>
60    /// <exception cref="ArgumentException">If the sequence is empty.</exception>
61    /// <typeparam name="T">The type of the items to be selected.</typeparam>
62    /// <param name="source">The sequence of elements.</param>
63    /// <param name="random">The random number generator to use, its NextDouble() method must produce values in the range [0;1)</param>
64    /// <param name="count">The number of items to be selected.</param>
65    /// <returns>An element that has been chosen randomly from the sequence.</returns>
66    public static T SampleRandom<T>(this IEnumerable<T> source, IRandom random) {
67      if (!source.Any()) throw new ArgumentException("sequence is empty.", "source");
68      return source.SampleRandom(random, 1).First();
69    }
70
71    /// <summary>
72    /// Chooses <paramref name="count"/> elements from a sequence with repetition with equal chances for each element.
73    /// </summary>
74    /// <remarks>
75    /// Runtime complexity is O(count) for sequences that are <see cref="IList{T}"/> and
76    /// O(N * count) for all other. No exception is thrown if the sequence is empty.
77    ///
78    /// The method is online.
79    /// </remarks>
80    /// <typeparam name="T">The type of the items to be selected.</typeparam>
81    /// <param name="source">The sequence of elements.</param>
82    /// <param name="random">The random number generator to use, its NextDouble() method must produce values in the range [0;1)</param>
83    /// <param name="count">The number of items to be selected.</param>
84    /// <returns>A sequence of elements that have been chosen randomly.</returns>
85    public static IEnumerable<T> SampleRandom<T>(this IEnumerable<T> source, IRandom random, int count) {
86      var listSource = source as IList<T>;
87      if (listSource != null) {
88        while (count > 0) {
89          yield return listSource[random.Next(listSource.Count)];
90          count--;
91        }
92      } else {
93        while (count > 0) {
94          var enumerator = source.GetEnumerator();
95          enumerator.MoveNext();
96          T selectedItem = enumerator.Current;
97          int counter = 1;
98          while (enumerator.MoveNext()) {
99            counter++;
100            if (counter * random.NextDouble() < 1.0)
101              selectedItem = enumerator.Current;
102          }
103          yield return selectedItem;
104          count--;
105        }
106      }
107    }
108
109    /// <summary>
110    /// Chooses <paramref name="count"/> elements from a sequence without repetition with equal chances for each element.
111    /// The items are returned in the same order as they appear in the sequence.
112    /// </summary>
113    /// <remarks>
114    /// Runtime complexity is O(N) for all sequences.
115    /// No exception is thrown if the sequence contains less items than there are to be selected.
116    ///
117    /// The method is online.
118    /// </remarks>
119    /// <typeparam name="T">The type of the items to be selected.</typeparam>
120    /// <param name="source">The sequence of elements.</param>
121    /// <param name="random">The random number generator to use, its NextDouble() method must produce values in the range [0;1)</param>
122    /// <param name="count">The number of items to be selected.</param>
123    /// <param name="sourceCount">Optional parameter specifying the number of elements in the source enumerations</param>
124    /// <returns>A sequence of elements that have been chosen randomly.</returns>
125    public static IEnumerable<T> SampleRandomWithoutRepetition<T>(this IEnumerable<T> source, IRandom random, int count, int sourceCount = -1) {
126      if (sourceCount == -1) sourceCount = source.Count();
127      int remaining = sourceCount;
128      foreach (var item in source) {
129        if (random.NextDouble() * remaining < count) {
130          count--;
131          yield return item;
132          if (count <= 0) break;
133        }
134        remaining--;
135      }
136    }
137
138    /// <summary>
139    /// Chooses elements out of a sequence with repetition. The chance that an item is selected is proportional or inverse-proportional
140    /// to the <paramref name="weights"/>.
141    /// </summary>
142    /// <remarks>
143    /// In case both <paramref name="inverseProportional"/> and <paramref name="windowing"/> are false values must be &gt; 0,
144    /// otherwise an InvalidOperationException is thrown.
145    ///
146    /// The method internally holds two arrays: One that is the sequence itself and another one for the values.
147    /// </remarks>
148    /// <typeparam name="T">The type of the items to be selected.</typeparam>
149    /// <param name="source">The sequence of elements.</param>
150    /// <param name="random">The random number generator to use, its NextDouble() method must produce values in the range [0;1)</param>
151    /// <param name="count">The number of items to be selected.</param>
152    /// <param name="weights">The weight values for the items.</param>
153    /// <param name="windowing">Whether to scale the proportional values or not.</param>
154    /// <param name="inverseProportional">Determines whether to choose proportionally (false) or inverse-proportionally (true).</param>
155    /// <returns>A sequence of selected items. The sequence might contain the same item more than once.</returns>
156    public static IEnumerable<T> SampleProportional<T>(this IEnumerable<T> source, IRandom random, int count, IEnumerable<double> weights, bool windowing = true, bool inverseProportional = false) {
157      return source.SampleProportional(random, weights, windowing, inverseProportional).Take(count);
158    }
159
160    /// <summary>
161    /// Same as <seealso cref="SampleProportional<T>"/>, but chooses an item exactly once.
162    /// </summary>
163    /// <remarks>
164    /// In case both <paramref name="inverseProportional"/> and <paramref name="windowing"/> are false values must be &gt; 0,
165    /// otherwise an InvalidOperationException is thrown.
166    ///
167    /// The method internally holds two arrays: One that is the sequence itself and another one for the values.
168    ///
169    /// The method does not check if the number of elements in source and weights are the same.
170    /// </remarks>
171    /// <typeparam name="T">The type of the items to be selected.</typeparam>
172    /// <param name="source">The sequence of elements.</param>
173    /// <param name="random">The random number generator to use, its NextDouble() method must produce values in the range [0;1)</param>
174    /// <param name="count">The number of items to be selected.</param>
175    /// <param name="weights">The weight values for the items.</param>
176    /// <param name="windowing">Whether to scale the proportional values or not.</param>
177    /// <param name="inverseProportional">Determines whether to choose proportionally (true) or inverse-proportionally (false).</param>
178    /// <returns>A sequence of selected items. Might actually be shorter than <paramref name="count"/> elements if source has less than <paramref name="count"/> elements.</returns>
179    public static IEnumerable<T> SampleProportionalWithoutRepetition<T>(this IEnumerable<T> source, IRandom random, int count, IEnumerable<double> weights, bool windowing = true, bool inverseProportional = false) {
180      return source.SampleProportionalWithoutRepetition(random, weights, windowing, inverseProportional).Take(count);
181    }
182    #region Proportional Helpers
183    private static IEnumerable<T> SampleProportional<T>(this IEnumerable<T> source, IRandom random, IEnumerable<double> weights, bool windowing, bool inverseProportional) {
184      var sourceArray = source.ToArray();
185      var valueArray = PrepareProportional(weights, windowing, inverseProportional);
186      double total = valueArray.Sum();
187
188      while (true) {
189        int index = 0;
190        double ball = valueArray[index], sum = random.NextDouble() * total;
191        while (ball < sum)
192          ball += valueArray[++index];
193        yield return sourceArray[index];
194      }
195    }
196    private static IEnumerable<T> SampleProportionalWithoutRepetition<T>(this IEnumerable<T> source, IRandom random, IEnumerable<double> weights, bool windowing, bool inverseProportional) {
197      var valueArray = PrepareProportional(weights, windowing, inverseProportional);
198      var list = new LinkedList<Tuple<T, double>>(source.Zip(valueArray, Tuple.Create));
199      double total = valueArray.Sum();
200
201      while (list.Count > 0) {
202        var cur = list.First;
203        double ball = cur.Value.Item2, sum = random.NextDouble() * total; // assert: sum < total. When there is only one item remaining: sum < ball
204        while (ball < sum && cur.Next != null) {
205          cur = cur.Next;
206          ball += cur.Value.Item2;
207        }
208        yield return cur.Value.Item1;
209        list.Remove(cur);
210        total -= cur.Value.Item2;
211      }
212    }
213
214    private static double[] PrepareProportional(IEnumerable<double> weights, bool windowing, bool inverseProportional) {
215      double maxValue = double.MinValue, minValue = double.MaxValue;
216      double[] valueArray = weights.ToArray();
217
218      for (int i = 0; i < valueArray.Length; i++) {
219        if (valueArray[i] > maxValue) maxValue = valueArray[i];
220        if (valueArray[i] < minValue) minValue = valueArray[i];
221      }
222      if (minValue == maxValue) {  // all values are equal
223        for (int i = 0; i < valueArray.Length; i++) {
224          valueArray[i] = 1.0;
225        }
226      } else {
227        if (windowing) {
228          if (inverseProportional) InverseProportionalScale(valueArray, maxValue);
229          else ProportionalScale(valueArray, minValue);
230        } else {
231          if (minValue < 0.0) throw new InvalidOperationException("Proportional selection without windowing does not work with values < 0.");
232          if (inverseProportional) InverseProportionalScale(valueArray, 2 * maxValue);
233        }
234      }
235      return valueArray;
236    }
237    private static void ProportionalScale(double[] values, double minValue) {
238      for (int i = 0; i < values.Length; i++) {
239        values[i] = values[i] - minValue;
240      }
241    }
242    private static void InverseProportionalScale(double[] values, double maxValue) {
243      for (int i = 0; i < values.Length; i++) {
244        values[i] = maxValue - values[i];
245      }
246    }
247    #endregion
248
249    /// <summary>
250    /// Shuffles an enumerable and returns a new enumerable according to the Fisher-Yates shuffle.
251    /// </summary>
252    /// <remarks>
253    /// Note that the source enumerable is transformed into an array.
254    ///
255    /// The implementation is described in http://stackoverflow.com/questions/1287567/c-is-using-random-and-orderby-a-good-shuffle-algorithm.
256    /// </remarks>
257    /// <typeparam name="T">The type of the items that are to be shuffled.</typeparam>
258    /// <param name="source">The enumerable that contains the items.</param>
259    /// <param name="random">The random number generator, its Next(n) method must deliver uniformly distributed random numbers in the range [0;n).</param>
260    /// <returns>An enumerable with the elements shuffled.</returns>
261    public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, IRandom random) {
262      T[] elements = source.ToArray();
263      for (int i = elements.Length - 1; i > 0; i--) {
264        // Swap element "i" with a random earlier element (including itself)
265        int swapIndex = random.Next(i + 1);
266        yield return elements[swapIndex];
267        elements[swapIndex] = elements[i];
268        // we don't actually perform the swap, we can forget about the
269        // swapped element because we already returned it.
270      }
271      if (elements.Length > 0)
272        yield return elements[0];
273    }
274  }
275}
276
Note: See TracBrowser for help on using the repository browser.