public LockMatrix(LockRuleset rules)
        {
            Debug.Assert(rules.GetLockLevelCount() < 32, "rules.GetLockLevelCount()<32");
            Debug.Assert(rules.GetLockLevelCount() > 0, "rules.GetLockLevelCount()>0");
            byte selfSharedLockShift = 0;

            _lockSelfSharedFlag       = new byte[rules.GetLockLevelCount()];
            _lockSwitchMatrix         = new MatrPair[rules.GetLockLevelCount()][];
            _lockSwitchDictionary     = new IReadOnlyDictionary <int, MatrPair> [rules.GetLockLevelCount()];
            _lockSwitchBackDictionary = new IReadOnlyDictionary <int, MatrPair> [rules.GetLockLevelCount()];
            _lockEscalationMatrix     = new MatrPair[rules.GetLockLevelCount(), rules.GetLockLevelCount()][];
            _singleLockSwitchPaths    = new MatrPair[rules.GetLockLevelCount()];
            var allLockLevels = Enumerable.Range(0, rules.GetLockLevelCount()).ToArray();

            foreach (var lockLevel in allLockLevels)
            {
                _lockEscalationMatrix[lockLevel, lockLevel] = new MatrPair[0];
            }

            var allPossibleStates = Enumerable.Range(0, 1 << (rules.GetLockLevelCount())).ToList();
            var powersOf2         = allLockLevels.Select(k => 1 << k).ToArray();
            var twoBitMatrix      = allLockLevels
                                    .Join(allLockLevels, k => true, k => true, (o, i) => new { o, i })
                                    .Where(k => k.o != k.i)
                                    .Select(k => new { ent = (byte)k.i, ex = (byte)k.o, bits = (1 << k.i) | (1 << k.o) })
                                    .ToArray();

            for (byte i = 0b0; i < rules.GetLockLevelCount(); i++)
            {
                if (rules.AreShared(i, i))
                {
                    _lockSelfSharedFlag[i] = selfSharedLockShift++;
                }
                else
                {
                    _lockSelfSharedFlag[i] = 0xFF;
                }
                for (byte j = 0b0; j < rules.GetLockLevelCount(); j++)
                {
                    if (!rules.AreShared(i, j) && i != j)
                    {
                        var mask = (1 << i) | (1 << j);
                        allPossibleStates.RemoveAll(k => (k & mask) == mask);
                    }
                }
            }

            var possibleLockPath = allPossibleStates
                                   .Join(allPossibleStates, _ => true, _ => true, (o, i) => new{ entrance = (uint)(i), exit = (uint)(o), difference = o ^ i })
                                   .Where(k => k.exit > k.entrance && powersOf2.Contains(k.difference))
                                   .ToArray();

            var possibleEscalationPath = allPossibleStates
                                         .Join(allPossibleStates, k => k != 0, k => k != 0, (o, i) => new { entrance = (uint)(i), exit = (uint)(o), difference = o ^ i })
                                         .Join(twoBitMatrix, k => k.difference, k => k.bits, (o, i) => new { o.entrance, o.exit, escState1 = (uint)i.ent, escState2 = (uint)i.ex })
                                         .Where(k => k.entrance > k.exit && k.escState1 > k.escState2 || k.entrance < k.exit && k.escState1 < k.escState2)
                                         .ToArray();

            var additionalPathsForSelfSharedLocks = Enumerable.Range(0, rules.GetLockLevelCount())
                                                    .Where(k => rules.AreShared((byte)k, (byte)k))
                                                    .Join(allPossibleStates, _ => true, _ => true,
                                                          (o, i) => new { entrance = (uint)i, exit = (uint)i | SharenessCheckLock, difference = i & (1 << o) })
                                                    .Where(k => k.difference != 0)
                                                    .ToArray();

            foreach (var pair in possibleLockPath.Concat(additionalPathsForSelfSharedLocks).GroupBy(k => Array.FindIndex(powersOf2, k2 => k2 == k.difference)))
            {
                _lockSwitchMatrix[pair.Key] = pair.Select(k => new MatrPair(k.entrance, k.exit)).OrderBy(k => k.BlockEntrance).ToArray();
                if (pair.Count() == 1)
                {
                    _singleLockSwitchPaths[pair.Key] = pair.Select(k => new MatrPair(k.entrance, k.exit))
                                                       .Single();
                }
                else
                {
                    _lockSwitchDictionary[pair.Key] = pair
                                                      .Select(k => new MatrPair(k.entrance, k.exit))
                                                      .ToDictionary(k => (int)k.BlockEntrance);
                    _lockSwitchBackDictionary[pair.Key] = pair
                                                          .Select(k => new MatrPair(k.entrance, k.exit))
                                                          .ToDictionary(k => (int)k.BlockExit);
                }
            }


            foreach (var pair in possibleEscalationPath.GroupBy(k => k.escState1))
            {
                foreach (var pair2 in pair.GroupBy(k => k.escState2))
                {
                    _lockEscalationMatrix[pair.Key, pair2.Key] = pair2.Select(k => new MatrPair(k.entrance, k.exit)).ToArray();
                }
            }

            SelfSharedLocks = selfSharedLockShift;
        }