public void Execute()
        {
            #region QueryHandle

            QueryHandler <T_SLOT, T_SLOT_INFOS, T_BRAIN> Q =
                new QueryHandler <T_SLOT, T_SLOT_INFOS, T_BRAIN>()
            {
                m_brain                  = m_brain,
                m_inputSlotInfos         = m_inputSlotInfos,
                m_inputSlotCoordinateMap = m_inputSlotCoordinateMap,
                m_socketCount            = m_socketCount,
                m_socketOffsets          = m_socketOffsets,
                m_socketsMirrors         = m_socketsMirrors,
                m_socketsMirrorsIndices  = m_socketsMirrorsIndices,
                m_moduleCount            = m_moduleCount,
                m_modulesWeights         = m_modulesWeights,
                m_modulesHeaders         = m_modulesHeaders,
                m_modulesNeighbors       = m_modulesNeighbors,
                m_results                = m_results,
                m_nullPairLookup         = m_nullPairLookup
            };

            #endregion

            int
                sCount = m_inputSlotInfos.Length,
                nCount = m_modulesNeighbors.Length,
                count,
                index,
                result;

            Antropy     _a;
            SortAntropy antropyComparer = default;

            NativeList <Neighbor>
            contents = new NativeList <Neighbor>(m_socketCount, Allocator.Temp);

            NativeList <int>
            candidates            = new NativeList <int>(m_modulesNeighbors.Length, Allocator.Temp),
                slotSocketIndices = new NativeList <int>(m_socketCount, Allocator.Temp),
                slotIndices       = new NativeList <int>(m_socketCount, Allocator.Temp);

            NativeList <float>
            weights = new NativeList <float>(m_moduleCount, Allocator.Temp);

            NativeList <Antropy>
            open = new NativeList <Antropy>(sCount, Allocator.Temp);

            #region compute initial antropy

            for (int slotIndex = 0; slotIndex < sCount; slotIndex++)
            {
                if (m_results[slotIndex] < 0 &&
                    Q.TryGetCandidates(
                        slotIndex,
                        ref contents,
                        ref candidates,
                        ref weights,
                        out count))
                {
                    _a = new Antropy()
                    {
                        coord      = m_inputSlotInfos[slotIndex].coord,
                        index      = slotIndex,
                        candidates = count,
                        progress   = Q.GetNeighborsResolutionRatio(slotIndex)
                    };

                    if (open.Length != 0)
                    {
                        if (antropyComparer.Compare(_a, open[0]) >= 0)
                        {
                            open[0] = _a;
                        }
                    }
                    else
                    {
                        open.Add(_a);
                    }
                }
            }

            if (open.Length != 0)
            {
                open.Sort(antropyComparer);
            }
            else
            {
                open.Add(new Antropy()
                {
                    index = 0, candidates = m_moduleCount
                });
            }

            // ISSUE : When resolving candidates, some header gets selected because a neighboring socket is UNSET, and thus ignored
            // while the header only accepts NULL for that socket.

            #endregion

            #region collapse

            int   increment = 0;
            float ratio;

            while (open.Length > 0)
            {
                _a             = open.Pop();
                index          = _a.index;
                m_debug[index] = increment / (float)sCount;

                // Collapse

                if (Q.TryGetCandidates(
                        index,
                        ref contents,
                        ref candidates,
                        ref weights,
                        out count))
                {
                    result = candidates[Common.NRandom.GetRandomWeightedIndex(ref weights, NextFloat())];
                }
                else
                {
                    // Uh oh, no candidate found !
                    result = SlotContent.UNSOLVABLE;
                }

                m_results[index] = result;

                // Recalculate antropy of neighboring slots that are currently unset

                if (Q.TryGetMatchingNeighbors(
                        index, SlotContent.UNSET,
                        ref slotSocketIndices,
                        ref slotIndices,
                        out count))
                {
                    for (int s = 0; s < count; s++)
                    {
                        index = slotIndices[s];
                        if (Q.TryGetCandidates(
                                index,
                                ref contents,
                                ref candidates,
                                ref weights,
                                out int antropy))
                        {
                            ratio = Q.GetNeighborsResolutionRatio(index);
                            UpdateAntropy(ref index, ref antropy, ref ratio, ref open);
                        }
                    }
                }

                // Sort open slots which antropy is computed

                open.Sort(antropyComparer);
                increment++;
            }

            #endregion

            open.Release();
            contents.Release();
            candidates.Release();
            slotSocketIndices.Release();
            slotIndices.Release();
            weights.Release();
        }
        public void Execute()
        {
            #region QueryHandle

            QueryHandler <T_SLOT, T_SLOT_INFOS, T_BRAIN> Q =
                new QueryHandler <T_SLOT, T_SLOT_INFOS, T_BRAIN>()
            {
                m_brain                  = m_brain,
                m_inputSlotInfos         = m_inputSlotInfos,
                m_inputSlotCoordinateMap = m_inputSlotCoordinateMap,
                m_socketCount            = m_socketCount,
                m_socketOffsets          = m_socketOffsets,
                m_socketsMirrors         = m_socketsMirrors,
                m_socketsMirrorsIndices  = m_socketsMirrorsIndices,
                m_moduleCount            = m_moduleCount,
                m_modulesWeights         = m_modulesWeights,
                m_modulesHeaders         = m_modulesHeaders,
                m_modulesNeighbors       = m_modulesNeighbors,
                m_results                = m_results,
                m_nullPairLookup         = m_nullPairLookup
            };

            #endregion

            NativeList <Neighbor>
            contents = new NativeList <Neighbor>(m_socketCount, Allocator.Temp);

            NativeList <int>
            candidates      = new NativeList <int>(m_modulesNeighbors.Length, Allocator.Temp),
                unsolvables = new NativeList <int>(10, Allocator.Temp);

            NativeList <float>
            weights = new NativeList <float>(m_moduleCount, Allocator.Temp);

            int
                cCount,
                result;

            for (int slotIndex = 0, count = m_inputSlotInfos.Length; slotIndex < count; slotIndex++)
            {
                if (m_results[slotIndex] >= 0)
                {
                    continue;
                }

                if (Q.TryGetCandidates(
                        slotIndex,
                        ref contents,
                        ref candidates,
                        ref weights,
                        out cCount))
                {
                    result = candidates[NRandom.GetRandomWeightedIndex(ref weights, NextFloat())];
                }
                else
                {
                    result = SlotContent.UNSOLVABLE;
                    unsolvables.Add(slotIndex);
                }

                m_results[slotIndex] = result;
            }

            // Second pass if necessary

            if (unsolvables.Length != 0)
            {
                int index = 0;

                for (int u = 0, uCount = unsolvables.Length; u < uCount; u++)
                {
                    index = unsolvables[u];

                    if (Q.TryGetCandidates(
                            index,
                            ref contents,
                            ref candidates,
                            ref weights,
                            out cCount))
                    {
                        result = candidates[NRandom.GetRandomWeightedIndex(ref weights, NextFloat())];
                    }
                    else
                    {
                        result = SlotContent.UNSOLVABLE;
                    }

                    m_results[index] = result;
                }
            }

            contents.Release();
            candidates.Release();
            unsolvables.Release();
            weights.Release();
        }