public readonly long MaxIndex;         // long to support 20! or less

        // ************************************************************************
        public PermutationOuelletLexico(T[] sortedValues)
        {
            _sortedValues = sortedValues;
            Result        = new T[_sortedValues.Length];

            MaxIndex = Factorial.GetFactorial(_sortedValues.Length);
        }
        // ************************************************************************
        public static void ExecuteForEachPermutationMT(int[] sortedValues, Action <int[]> action)
        {
            int  coreCount      = Environment.ProcessorCount;       // Hyper treading are taken into account (ex: on a 4 cores hyperthreaded = 8)
            long itemsFactorial = Factorial.GetFactorial(sortedValues.Length);
            long partCount      = (long)Math.Ceiling((double)itemsFactorial / (double)coreCount);
            long startIndex     = 0;

            var tasks = new List <Task>();

            for (int coreIndex = 0; coreIndex < coreCount; coreIndex++)
            {
                long stopIndex = Math.Min(startIndex + partCount, itemsFactorial);

                PermutationMixOuelletSaniSinghHuttunen mix = new PermutationMixOuelletSaniSinghHuttunen(sortedValues, startIndex, stopIndex);
                Task task = Task.Run(() => mix.ExecuteForEachPermutation(action));
                tasks.Add(task);

                if (stopIndex == itemsFactorial)
                {
                    break;
                }

                startIndex = startIndex + partCount;
            }

            Task.WaitAll(tasks.ToArray());
        }
Example #3
0
        // ************************************************************************
        /// <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)");
            }

            List <T> leftValues = new List <T>(_sortedValues);

            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);

                T item = Result[index] = leftValues[resultItemIndex];

                leftValues.Remove(item);
            }
        }
        // ************************************************************************
        /// <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;
            }
        }