// ************************************************************************ /// <summary> /// Sort Index is 0 based and should be less than MaxIndex. Otherwise you get an exception. /// </summary> /// <param name="sortIndex"></param> /// <param name="result">Value is not used as inpu, only as output. Re-use buffer in order to save memory</param> /// <returns></returns> public void GetSortedValuesFor(long sortIndex) { int size = _sortedValues.Length; if (sortIndex < 0) { throw new ArgumentException("sortIndex should greater or equal to 0."); } if (sortIndex >= MaxIndex) { throw new ArgumentException("sortIndex should less than factorial(the lenght of items)"); } _positions[size - 1] = size - 1; #if DEBUG _positions[0] = -1; _positions[1] = -1; _positions[2] = -1; if (sortIndex == 4) { Debug.Assert(false); } #endif long factorielBigger = 1; for (int index = 2; index <= size; index++) { long factorielLower = factorielBigger; factorielBigger = Factorial.GetFactorial(index); // factorielBigger / inverseIndex; int resultItemIndex = size - index + (int)(sortIndex % factorielBigger / factorielLower); int temp = _positions[resultItemIndex]; _positions[resultItemIndex] = size - index; if (resultItemIndex > size - index) { _positions[size - index] = temp; } Dump(_positions); } for (int index = 0; index < size; index++) { Result[_positions[index]] = _sortedValues[index]; } Debug.Print("Result: "); Dump(Result); }
public readonly long MaxIndex; // long to support 20! or less // ************************************************************************ public PermutationOuelletLexico3(T[] sortedValues) { if (sortedValues.Length <= 0) { throw new ArgumentException("sortedValues.Lenght should be greater than 0"); } _sortedValues = sortedValues; Result = new T[_sortedValues.Length]; _valueUsed = new bool[_sortedValues.Length]; MaxIndex = Factorial.GetFactorial(_sortedValues.Length); }
// ************************************************************************ /// <summary> /// Return the permutation relative to the index received. /// Based on _sortedValues. Sort Index is 0 based and should be less than MaxIndex. /// </summary> /// <param name="sortIndex"></param> /// <returns>The result is written in property: Result</returns> public void GetValuesForIndex(long sortIndex) { int size = _sortedValues.Length; if (sortIndex < 0) { throw new ArgumentException("sortIndex should be greater or equal to 0."); } if (sortIndex >= MaxIndex) { throw new ArgumentException("sortIndex should be less than factorial(the lenght of items)"); } for (int n = 0; n < _valueUsed.Length; n++) { _valueUsed[n] = false; } long factorielLower = MaxIndex; for (int index = 0; index < size; index++) { long factorielBigger = factorielLower; factorielLower = Factorial.GetFactorial(size - index - 1); // factorielBigger / inverseIndex; int resultItemIndex = (int)(sortIndex % factorielBigger / factorielLower); int correctedResultItemIndex = 0; for (;;) { if (!_valueUsed[correctedResultItemIndex]) { resultItemIndex--; if (resultItemIndex < 0) { break; } } correctedResultItemIndex++; } Result[index] = _sortedValues[correctedResultItemIndex]; _valueUsed[correctedResultItemIndex] = true; } }
// ************************************************************************ /// <summary> /// Calc the index, relative to the permutation received /// as argument. Based on _sortedValues. Returned index is 0 based. /// </summary> /// <param name="values"></param> /// <returns></returns> public long GetIndexOfValues(T[] values) { int size = _sortedValues.Length; long valuesIndex = 0; List <T> valuesLeft = new List <T>(_sortedValues); for (int index = 0; index < size; index++) { long indexFactorial = Factorial.GetFactorial(size - 1 - index); T value = values[index]; int indexCorrected = valuesLeft.IndexOf(value); valuesIndex = valuesIndex + (indexCorrected * indexFactorial); valuesLeft.Remove(value); } return(valuesIndex); }
// ************************************************************************ public PermutationMixOuelletSaniSinghHuttunen(int[] sortedValues, long indexFirst = -1, long indexLastExclusive = -1) { if (indexFirst == -1) { indexFirst = 0; } if (indexLastExclusive == -1) { indexLastExclusive = Factorial.GetFactorial(sortedValues.Length); } if (indexFirst >= indexLastExclusive) { throw new ArgumentException($"{nameof(indexFirst)} should be less than {nameof(indexLastExclusive)}"); } _indexFirst = indexFirst; _indexLastExclusive = indexLastExclusive; _sortedValues = sortedValues; }
// ************************************************************************ private int RunTest() { try { bool canRun = false; lock (_lockObj) { if (!IsTestRunning) { canRun = true; IsTestRunning = true; } } if (!canRun) { MessageBox.Show("Already running test. Please try later."); return(0); } Action <IEnumerable <int> > actionToDoOnPermutation = null; Predicate <int[]> funcToDoOnPermutation = null; // Direct function for Sam to be fair (I do not want to add an additional indirection) switch (EnumAction) { case EnumAction.Nothing_BestForPerformanceTest: actionToDoOnPermutation = DoNothing; funcToDoOnPermutation = DoNothingFunc; break; case EnumAction.CountItemWithBugWithMultithreadedCode: actionToDoOnPermutation = IncreaseCount; funcToDoOnPermutation = IncreaseCountFunc; break; case EnumAction.CountItemSafeInterlockedIncrement: actionToDoOnPermutation = IncreaseCountSafeInterlockedIncrement; funcToDoOnPermutation = IncreaseCountSafeInterlockedIncrementFunc; break; case EnumAction.CountItemSafeSpinLock: actionToDoOnPermutation = IncreaseCountSafeSpinLock; funcToDoOnPermutation = IncreaseCountSafeSpinLockFunc; break; case EnumAction.DumpPermutatedValuesAndCount: actionToDoOnPermutation = DumpValues; funcToDoOnPermutation = DumpValuesFunc; if (CountOfElementsToPermute > 5) { var result = MessageBox.Show( "The count of item to permute is greater than 5, it could take long to dump every items, are you sure you want to continue?", "Warning", MessageBoxButton.OKCancel); if (result == MessageBoxResult.Cancel) { return(0); } } break; } EnumAlgoPermutation algoPermutation = AlgoPermutation; EnumAlgoPermutation algoPermutationActive; _testCount++; WriteLine($"Test {_testCount} started. Count {CountOfElementsToPermute}!. Action: {EnumUtil.GetEnumDescription(EnumAction)}."); int[] values; Stopwatch stopwatch = new Stopwatch(); // Eric OuelletHeap Algorithm algoPermutationActive = EnumAlgoPermutation.OuelletHeap; if (algoPermutation.HasFlag(algoPermutationActive)) { WriteIntro(algoPermutationActive); _count = 0; values = GetValues(); stopwatch.Reset(); stopwatch.Start(); PermutationOuellet.ForAllPermutation(values, (vals) => { actionToDoOnPermutation?.Invoke(vals); return(false); }); stopwatch.Stop(); WriteResult(algoPermutationActive, stopwatch); } // Eric OuelletHeap indexed Algorithm algoPermutationActive = EnumAlgoPermutation.OuelletIndexed; if (algoPermutation.HasFlag(algoPermutationActive)) { WriteIntro(algoPermutationActive); _count = 0; values = GetValues(); stopwatch.Reset(); stopwatch.Start(); var permutationGenerator = new PermutationOuelletLexico <int>(values); // int[] result = new int[values.Length]; for (long i = 0; i < permutationGenerator.MaxIndex; i++) { permutationGenerator.GetSortedValuesFor(i); { actionToDoOnPermutation?.Invoke(permutationGenerator.Result); } } stopwatch.Stop(); WriteResult(algoPermutationActive, stopwatch); } // Eric OuelletHeap indexed Algorithm v2 algoPermutationActive = EnumAlgoPermutation.OuelletIndexedv2; if (algoPermutation.HasFlag(algoPermutationActive)) { WriteIntro(algoPermutationActive); _count = 0; values = GetValues(); stopwatch.Reset(); stopwatch.Start(); var permutationGenerator = new PermutationOuelletLexico2 <int>(values); // int[] result = new int[values.Length]; for (long i = 0; i < permutationGenerator.MaxIndex; i++) { permutationGenerator.GetSortedValuesFor(i); { actionToDoOnPermutation?.Invoke(permutationGenerator.Result); } } stopwatch.Stop(); WriteResult(algoPermutationActive, stopwatch); } // Eric OuelletHeap indexed Algorithm v3 algoPermutationActive = EnumAlgoPermutation.OuelletIndexedv3; if (algoPermutation.HasFlag(algoPermutationActive)) { WriteIntro(algoPermutationActive); _count = 0; values = GetValues(); stopwatch.Reset(); stopwatch.Start(); var permutationGenerator = new PermutationOuelletLexico3 <int>(values); // int[] result = new int[values.Length]; for (long i = 0; i < permutationGenerator.MaxIndex; i++) { permutationGenerator.GetValuesForIndex(i); { actionToDoOnPermutation?.Invoke(permutationGenerator.Result); } } stopwatch.Stop(); WriteResult(algoPermutationActive, stopwatch); } //// Eric OuelletHeap indexed Algorithm v4 //algoPermutationActive = EnumAlgoPermutation.OuelletIndexedv4; //if (algoPermutation.HasFlag(algoPermutationActive)) //{ // _count = 0; // values = GetValues(); // stopwatch.Reset(); // stopwatch.Start(); // var permutationGenerator = new PermutationOuelletLexico4<int>(values); // // int[] result = new int[values.Length]; // for (int i = 0; i < permutationGenerator.MaxIndex; i++) // { // permutationGenerator.GetValuesForIndex(i); // { // actionDumpValues?.Invoke(permutationGenerator.Result); // } // } // stopwatch.Stop(); // WriteResult(algoPermutationActive, stopwatch); //} algoPermutationActive = EnumAlgoPermutation.SaniSinghHuttunen; if (algoPermutation.HasFlag(algoPermutationActive)) { WriteIntro(algoPermutationActive); _count = 0; values = GetValues(); stopwatch.Reset(); stopwatch.Start(); do { actionToDoOnPermutation?.Invoke(values); }while (PermutationSaniSinghHuttunen.NextPermutation(values)); stopwatch.Stop(); WriteResult(algoPermutationActive, stopwatch); } algoPermutationActive = EnumAlgoPermutation.OuelletIndexedv3HuttunenST; if (algoPermutation.HasFlag(algoPermutationActive)) { WriteIntro(algoPermutationActive); _count = 0; values = GetValues(); stopwatch.Reset(); stopwatch.Start(); PermutationMixOuelletSaniSinghHuttunen mix = new PermutationMixOuelletSaniSinghHuttunen(values); mix.ExecuteForEachPermutation(actionToDoOnPermutation); stopwatch.Stop(); WriteResult(algoPermutationActive, stopwatch); } algoPermutationActive = EnumAlgoPermutation.SimpleVar; if (algoPermutation.HasFlag(algoPermutationActive)) { WriteIntro(algoPermutationActive); _count = 0; values = GetValues(); stopwatch.Reset(); stopwatch.Start(); do { actionToDoOnPermutation?.Invoke(values); }while (!PermutationSimpleVar.NextPermutation(values)); stopwatch.Stop(); WriteResult(algoPermutationActive, stopwatch); } algoPermutationActive = EnumAlgoPermutation.SimpleVarUnsafe; if (algoPermutation.HasFlag(algoPermutationActive)) { WriteIntro(algoPermutationActive); _count = 0; values = GetValues(); stopwatch.Reset(); stopwatch.Start(); PermutationSimpleVarUnsafe permutations = new PermutationSimpleVarUnsafe(); permutations.Permutate(0, values.Length, (int[] vals) => { actionToDoOnPermutation?.Invoke(vals); }); stopwatch.Stop(); WriteResult(algoPermutationActive, stopwatch); } // ErezRobinson Algorithm algoPermutationActive = EnumAlgoPermutation.ErezRobinson; if (algoPermutation.HasFlag(algoPermutationActive)) { WriteIntro(algoPermutationActive); _count = 0; values = GetValues(); stopwatch.Reset(); stopwatch.Start(); foreach (var vals in PermutationErezRobinson.QuickPerm(values)) { actionToDoOnPermutation?.Invoke(vals); } stopwatch.Stop(); WriteResult(algoPermutationActive, stopwatch); } algoPermutationActive = EnumAlgoPermutation.Sam; if (algoPermutation.HasFlag(algoPermutationActive)) { WriteIntro(algoPermutationActive); _count = 0; values = GetValues(); stopwatch.Reset(); stopwatch.Start(); var pf = new PermutationFinder <int>(); pf.Evaluate(values, funcToDoOnPermutation); stopwatch.Stop(); WriteResult(algoPermutationActive, stopwatch); } algoPermutationActive = EnumAlgoPermutation.Ziezi; if (algoPermutation.HasFlag(algoPermutationActive)) { WriteIntro(algoPermutationActive); _count = 0; values = GetValues(); stopwatch.Reset(); stopwatch.Start(); PermutationZiezi.EnumeratePermutation(values, actionToDoOnPermutation); stopwatch.Stop(); WriteResult(algoPermutationActive, stopwatch); } // Pengyang linq algorithm algoPermutationActive = EnumAlgoPermutation.Pengyang; if (algoPermutation.HasFlag(algoPermutationActive)) { WriteIntro(algoPermutationActive); _count = 0; values = GetValues(); stopwatch.Reset(); stopwatch.Start(); foreach (var vals in PermutationPengyang.GetPermutations(values, values.Length)) { actionToDoOnPermutation?.Invoke(vals); } stopwatch.Stop(); WriteResult(algoPermutationActive, stopwatch); } algoPermutationActive = EnumAlgoPermutation.OuelletIndexedMT; if (algoPermutation.HasFlag(algoPermutationActive)) { WriteIntro(algoPermutationActive); _count = 0; values = GetValues(); stopwatch.Reset(); stopwatch.Start(); int[] result = new int[values.Length]; Parallel.For <PermutationOuelletLexico <int> > ( 0, Factorial.GetFactorial(values.Length), () => new PermutationOuelletLexico <int>(GetValues()), (index, state, permutationOuellet) => { permutationOuellet.GetSortedValuesFor(index); actionToDoOnPermutation?.Invoke(permutationOuellet.Result); return(permutationOuellet); }, (permutationOuellet) => { } ); stopwatch.Stop(); WriteResult(algoPermutationActive, stopwatch); } algoPermutationActive = EnumAlgoPermutation.OuelletIndexedv3MT; if (algoPermutation.HasFlag(algoPermutationActive)) { WriteIntro(algoPermutationActive); _count = 0; values = GetValues(); stopwatch.Reset(); stopwatch.Start(); int[] result = new int[values.Length]; Parallel.For <PermutationOuelletLexico3 <int> > ( 0, Factorial.GetFactorial(values.Length), () => new PermutationOuelletLexico3 <int>(GetValues()), (index, state, permutationOuellet) => { permutationOuellet.GetValuesForIndex(index); actionToDoOnPermutation?.Invoke(permutationOuellet.Result); return(permutationOuellet); }, (permutationOuellet) => { } ); stopwatch.Stop(); WriteResult(algoPermutationActive, stopwatch); } algoPermutationActive = EnumAlgoPermutation.OuelletHuttunenMT; if (algoPermutation.HasFlag(algoPermutationActive)) { WriteIntro(algoPermutationActive); _count = 0; values = GetValues(); stopwatch.Reset(); stopwatch.Start(); PermutationMixOuelletSaniSinghHuttunen.ExecuteForEachPermutationMT(values, actionToDoOnPermutation); stopwatch.Stop(); WriteResult(algoPermutationActive, stopwatch); } WriteLine("Test " + _testCount + " ended."); WriteLine("---------------------------------------------------------------"); return(_count); } finally { IsTestRunning = false; } }