示例#1
0
        private ExploreChildNodesResult ExploreChildNodes <TVertex>(
            QuiverWithPotential <TVertex> qp,
            TransformationRuleTreeNode <TVertex> transformationRuleTree,
            AnalysisStateForSingleStartingVertexOld <TVertex> state,
            SearchTreeNodeOld <TVertex> parentNode,
            QPAnalysisSettings settings)
            where TVertex : IEquatable <TVertex>, IComparable <TVertex>
        {
            bool pathHasNonzeroExtension = false; // Path has no nonzero extension until proven otherwise

            // Explore every child node (determine its equivalence class)
            foreach (var nextVertex in qp.Quiver.AdjacencyLists[parentNode.Vertex])
            {
                var result = ExploreChildNode(transformationRuleTree, state, parentNode, nextVertex, settings);
                switch (result)
                {
                case ExploreChildNodeResult.NotZeroEquivalent:
                    pathHasNonzeroExtension = true;
                    break;

                case ExploreChildNodeResult.NonCancellativityDetected:
                    return(ExploreChildNodesResult.NonCancellativityDetected);

                case ExploreChildNodeResult.TooLongPath:
                    return(ExploreChildNodesResult.TooLongPath);
                }
            }

            return(pathHasNonzeroExtension ? ExploreChildNodesResult.PathHasNonzeroExtension : ExploreChildNodesResult.PathHasNoNonzeroExtension);
        }
        public void AreIsomorphic_OnIsomorphicQuiversButNonIsomorphicPotentials_SameGroupSignaturesAndSameCounts()
        {
            var potential1 = new Potential <char>(new DetachedCycle <char>(new Path <char>('B', 'C', 'E', 'B')), +1)
                             .AddCycle(new DetachedCycle <char>(new Path <char>('A', 'B', 'C', 'A')), -1)
                             .AddCycle(new DetachedCycle <char>(new Path <char>('B', 'D', 'E', 'B')), -1);

            var potential2 = new Potential <char>(new DetachedCycle <char>(new Path <char>('B', 'C', 'E', 'B')), +1)
                             .AddCycle(new DetachedCycle <char>(new Path <char>('A', 'B', 'C', 'A')), -1)
                             .AddCycle(new DetachedCycle <char>(new Path <char>('C', 'E', 'F', 'C')), -1);

            var qp1 = new QuiverWithPotential <char>(potential1);

            var vertices2 = new char[] { 'A', 'B', 'C', 'D', 'E', 'F' };
            var arrows2   = new Arrow <char>[]
            {
                new Arrow <char>('A', 'B'),
                new Arrow <char>('B', 'C'),
                new Arrow <char>('B', 'D'),
                new Arrow <char>('C', 'A'),
                new Arrow <char>('C', 'E'),
                new Arrow <char>('D', 'E'),
                new Arrow <char>('E', 'B'),
                new Arrow <char>('E', 'F'),
                new Arrow <char>('F', 'C'),
            };
            var quiver2 = new Quiver <char>(vertices2, arrows2);
            var qp2     = new QuiverWithPotential <char>(quiver2, potential2);
            var checker = new QPIsomorphismChecker();

            Assert.That(checker.AreIsomorphic(qp1, qp2), Is.False);
        }
        public void Analyze_DoesNotTryToUnionTheSameClasses_2()
        {
            var potential = new Potential <int>(new Dictionary <DetachedCycle <int>, int>
            {
                { new DetachedCycle <int>(0, 1, 2, 3, 4, 0), +1 },
                { new DetachedCycle <int>(0, 5, 4, 0), -1 },
                { new DetachedCycle <int>(3, 4, 6, 3), -1 },
                { new DetachedCycle <int>(2, 3, 7, 2), -1 },
                { new DetachedCycle <int>(1, 2, 8, 1), -1 },
                { new DetachedCycle <int>(0, 1, 9, 0), -1 },

                { new DetachedCycle <int>(0, 5, 10, 0), +1 },
                { new DetachedCycle <int>(4, 6, 11, 4), +1 },
                { new DetachedCycle <int>(3, 7, 12, 3), +1 },
                { new DetachedCycle <int>(2, 8, 13, 2), +1 },
                { new DetachedCycle <int>(1, 9, 14, 1), +1 },

                { new DetachedCycle <int>(0, 15, 5, 10, 0), -1 },
                { new DetachedCycle <int>(4, 16, 6, 11, 4), -1 },
                { new DetachedCycle <int>(3, 17, 7, 12, 3), -1 },
                { new DetachedCycle <int>(2, 18, 8, 13, 2), -1 },
                { new DetachedCycle <int>(1, 19, 9, 14, 1), -1 }
            });
            var qp       = new QuiverWithPotential <int>(potential);
            var analyzer = CreateAnalyzer();
            var settings = CreateSettings(maxPathLength: 20, EarlyTerminationConditions.None);

            Assert.That(() => analyzer.Analyze(qp, settings), Throws.Nothing);
        }
示例#4
0
        /// <summary>
        /// Analyzes a QP with the specified computer of maximal nonzero equivalence class
        /// representatives.
        /// </summary>
        /// <typeparam name="TVertex">The type of the vertices of the quiver.</typeparam>
        /// <param name="qp">The quiver with potential.</param>
        /// <param name="settings">The settings for the analysis.</param>
        /// <param name="computer">A computer of maximal nonzero equivalence class representatives.</param>
        /// <returns>The results of the analysis.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="qp"/> is
        /// <see langword="null"/>, or <paramref name="settings"/> is <see langword="null"/>,
        /// or <paramref name="computer"/> is <see langword="null"/>.</exception>
        /// <exception cref="NotSupportedException">The potential of <paramref name="qp"/> has a
        /// cycle with coefficient not equal to either of -1 and +1,
        /// or some arrow occurs multiple times in a single cycle of the potential of
        /// <paramref name="qp"/>.</exception>
        /// <exception cref="ArgumentException">For some arrow in the potential of
        /// <paramref name="qp"/> and sign, the arrow is contained in more than one cycle of that
        /// sign.</exception>
        public IQPAnalysisResults <TVertex> Analyze <TVertex>(
            QuiverWithPotential <TVertex> qp,
            QPAnalysisSettings settings,
            IMaximalNonzeroEquivalenceClassRepresentativeComputer computer)
            where TVertex : IEquatable <TVertex>, IComparable <TVertex>
        {
            if (qp is null)
            {
                throw new ArgumentNullException(nameof(qp));
            }
            if (settings is null)
            {
                throw new ArgumentNullException(nameof(settings));
            }
            if (computer is null)
            {
                throw new ArgumentNullException(nameof(computer));
            }

            // Simply get the underlying semimonomial unbound quiver and analyze it using the appropriate analyzer
            var semimonomialUnboundQuiver = SemimonomialUnboundQuiverFactory.CreateSemimonomialUnboundQuiverFromQP(qp);
            var suqAnalyzer = new SemimonomialUnboundQuiverAnalyzer();
            var suqSettings = AnalysisSettingsFactory.CreateSemimonomialUnboundQuiverAnalysisSettings(settings);
            var suqResults  = suqAnalyzer.Analyze(semimonomialUnboundQuiver, suqSettings, computer);
            var results     = AnalysisResultsFactory.CreateQPAnalysisResults(suqResults);

            return(results);
        }
示例#5
0
        private void AssertIsSelfInjective <TVertex>(QuiverWithPotential <TVertex> qp)
            where TVertex : IEquatable <TVertex>, IComparable <TVertex>
        {
            var analyzer = new QPAnalyzer();
            var result   = analyzer.Analyze(qp, new QPAnalysisSettings(CancellativityTypes.Cancellativity));

            Assert.That(result.MainResults.IndicatesSelfInjectivity());
        }
        public void AreIsomorphic_SmallQP1()
        {
            var potential1 = new Potential <int>(new DetachedCycle <int>(new Path <int>(1, 2, 3, 1)), +1);
            var potential2 = new Potential <int>(new DetachedCycle <int>(new Path <int>(3, 2, 1, 3)), +1);
            var qp1        = new QuiverWithPotential <int>(potential1);
            var qp2        = new QuiverWithPotential <int>(potential2);
            var checker    = new QPIsomorphismChecker();

            Assert.That(checker.AreIsomorphic(qp1, qp2), Is.True);
        }
示例#7
0
        // After figuring out the use cases (high performance?) for these methods and figuring out
        // whether to change the interface, implement the counterparts of the methods in
        // SemimonomialUnboundQuiverAnalyzer and have the public methods of this class just be a
        // wrapper for said methods in SemimonomialUnboundQuiverAnalyzer (like the Analyze method
        // is right now).
        #region Code to refactor
        public AnalysisResultsForSingleStartingVertexOld <TVertex> AnalyzeWithStartingVertex <TVertex>(
            QuiverWithPotential <TVertex> qp,
            TVertex startingVertex,
            TransformationRuleTreeNode <TVertex> transformationRuleTree,
            QPAnalysisSettings settings)
            where TVertex : IEquatable <TVertex>, IComparable <TVertex>
        {
            // Parameter validation
            if (qp == null)
            {
                throw new ArgumentNullException(nameof(qp));
            }
            if (!qp.Quiver.Vertices.Contains(startingVertex))
            {
                throw new ArgumentException($"The QP does not contain the starting vertex {startingVertex}.");
            }

            // Set up for analysis/graph search
            var  state = new AnalysisStateForSingleStartingVertexOld <TVertex>(startingVertex);
            bool cancellativityFailed   = false;
            bool tooLongPathEncountered = false;

            // Analysis/graph search
            // Keep a stack of "recently explored" nodes
            // In every iteration, pop a recently explored node from the stack and explore (determine
            // the equivalence classes of) its child nodes.
            // It would be cleaner to in every iteration explore the current node (determine its equivalence class)
            // and discover its child nodes (push new equivalence class representatives (which may overlap?) onto
            // the stack for future iterations, but this makes it non-trivial to keep track of the maximal nonzero
            // equivalence classes
            while (state.Stack.Count > 0)
            {
                var node   = state.Stack.Pop();
                var result = ExploreChildNodes(qp, transformationRuleTree, state, node, settings);
                if (result == ExploreChildNodesResult.PathHasNoNonzeroExtension)
                {
                    state.maximalPathRepresentatives.Add(node);
                }
                else if (result == ExploreChildNodesResult.NonCancellativityDetected)
                {
                    cancellativityFailed = true;
                    break;
                }
                else if (result == ExploreChildNodesResult.TooLongPath)
                {
                    tooLongPathEncountered = true;
                    break;
                }
            }

            // Return results
            var results = new AnalysisResultsForSingleStartingVertexOld <TVertex>(state, cancellativityFailed, tooLongPathEncountered);

            return(results);
        }
示例#8
0
 public void Deconstruct(
     out LayerType layerType,
     out IEnumerable <Composition> compositions,
     out QuiverInPlane <int> quiverInPlane,
     out QuiverWithPotential <int> qp)
 {
     layerType     = LayerType;
     compositions  = Compositions;
     quiverInPlane = QuiverInPlane;
     qp            = QP;
 }
示例#9
0
 /// <summary>
 /// Initializes a new instance of the <see cref="InteractiveLayeredQuiverGeneratorOutput"/>
 /// class.
 /// </summary>
 /// <param name="layerType">The layer type of the layered quiver.</param>
 /// <param name="compositions">The compositions that specify the arrows of the layered quiver.</param>
 /// <param name="quiverInPlane">A <see cref="QuiverInPlane{TVertex}"/> representing the
 /// layered quiver.</param>
 /// <param name="qp">A <see cref="QuiverWithPotential{TVertex}"/> representing the layered
 /// quiver.</param>
 public InteractiveLayeredQuiverGeneratorOutput(
     LayerType layerType,
     IEnumerable <Composition> compositions,
     QuiverInPlane <int> quiverInPlane,
     QuiverWithPotential <int> qp)
 {
     LayerType     = layerType ?? throw new ArgumentNullException(nameof(layerType));
     Compositions  = compositions ?? throw new ArgumentNullException(nameof(compositions));
     QuiverInPlane = quiverInPlane ?? throw new ArgumentNullException(nameof(quiverInPlane));
     QP            = qp ?? throw new ArgumentNullException(nameof(qp));
 }
        public void AreIsomorphic_SmallQP4()
        {
            var potential1 = new Potential <int>(new DetachedCycle <int>(new Path <int>(1, 2, 3, 1)), +1)
                             .AddCycle(new DetachedCycle <int>(new Path <int>(4, 5, 6, 4)), +1);
            var potential2 = new Potential <int>(new DetachedCycle <int>(new Path <int>(3, 2, 1, 3)), +1);
            var qp1        = new QuiverWithPotential <int>(potential1);
            var quiver2    = qp1.Quiver;
            var qp2        = new QuiverWithPotential <int>(quiver2, potential2);
            var checker    = new QPIsomorphismChecker();

            Assert.That(checker.AreIsomorphic(qp2, qp1), Is.False);
        }
        // Sets up variables for a call to Analyzer.ComputeMaximalNonzeroEquivalenceClassRepresentativesStartingAt (and possibly other methods)
        private static void DoSetup(
            QuiverWithPotential <int> qp,
            out QPAnalyzer analyzer,
            out TransformationRuleTreeNode <int> ruleTree,
            out QPAnalysisSettings settings)
        {
            analyzer = new QPAnalyzer();
            var ruleCreator = new TransformationRuleTreeCreator();

            ruleTree = ruleCreator.CreateTransformationRuleTree(qp);
            settings = CreateSettings(detectNonCancellativity: false);
        }
示例#12
0
 /// <summary>
 /// Analyzes a QP in a way that utilizes the &quot;periodicity&quot; of the QP and
 /// concurrently.
 /// </summary>
 /// <typeparam name="TVertex">The type of the vertices of the quiver.</typeparam>
 /// <param name="qp">The quiver with potential.</param>
 /// <param name="periods">A collection of consecutive non-empty periods of the QP that are
 /// jointly exhaustive and mutually exclusive.</param>
 /// <param name="settings">The settings for the analysis.</param>
 /// <returns>The results of the analysis.</returns>
 /// <exception cref="ArgumentNullException"><paramref name="qp"/> is
 /// <see langword="null"/>,
 /// or <paramref name="periods"/> is <see langword="null"/>,
 /// or <paramref name="settings"/> is <see langword="null"/>.</exception>
 /// <exception cref="NotSupportedException">The potential of <paramref name="qp"/> has a
 /// cycle with coefficient not equal to either of -1 and +1,
 /// or some arrow occurs multiple times in a single cycle of the potential of
 /// <paramref name="qp"/>.</exception>
 /// <exception cref="ArgumentException">For some arrow in the potential of
 /// <paramref name="qp"/> and sign, the arrow is contained in more than one cycle of that
 /// sign, or some of the periods in <paramref name="periods"/> overlap, or the union of all
 /// periods in <paramref name="periods"/> is not precisely the collection of all vertices
 /// in the quiver.</exception>
 /// <remarks>
 /// <para>Some validation of <paramref name="periods"/> is done, but
 /// <paramref name="periods"/> is not verified to constitute a sequence of consecutive
 /// &quot;periods&quot; of the QP.</para>
 /// </remarks>
 public IQPAnalysisResults <TVertex> AnalyzeUtilizingPeriodicityConcurrently <TVertex>(
     QuiverWithPotential <TVertex> qp,
     IEnumerable <IEnumerable <TVertex> > periods,
     QPAnalysisSettings settings)
     where TVertex : IEquatable <TVertex>, IComparable <TVertex>
 {
     return(AnalyzeUtilizingPeriodicityConcurrently(
                qp,
                periods,
                settings,
                defaultComputer));
 }
        /// <summary>
        /// Prompts the user for a QP.
        /// </summary>
        /// <param name="qp">Output parameter for the QP.</param>
        /// <param name="periods">Output parameter for the periods of the QP.</param>
        /// <param name="fixedPoint">Output parameter for the fixed-point of the QP (or
        /// <see langword="null"/> if there is none).</param>
        /// <returns><see langword="true"/> if the user specified a QP;
        /// <see langword="false"/> otherwise.</returns>
        private bool TryGetQP(
            out QuiverWithPotential <int> qp,
            out IEnumerable <IEnumerable <int> > periods,
            out int?fixedPoint)
        {
            if (!TryGetQPType(out var qpType) || !TryGetNumPeriods(qpType, out int numPeriods))
            {
                qp         = null;
                periods    = null;
                fixedPoint = null;
                return(false);
            }

            switch (qpType)
            {
            case QPType.OddFlower:
                qp         = UsefulQPs.GetOddFlowerQP(numPeriods, DefaultFirstVertex);
                periods    = UsefulQPs.GetPeriodsOfOddFlowerQP(numPeriods, DefaultFirstVertex);
                fixedPoint = null;
                break;

            case QPType.EvenFlowerType1:
                qp         = UsefulQPs.GetEvenFlowerType1QP(numPeriods, DefaultFirstVertex);
                periods    = UsefulQPs.GetPeriodsOfEvenFlowerType1QP(numPeriods, DefaultFirstVertex);
                fixedPoint = null;
                break;

            case QPType.EvenFlowerType2:
                qp         = UsefulQPs.GetEvenFlowerType2QP(numPeriods, DefaultFirstVertex);
                periods    = UsefulQPs.GetPeriodsOfEvenFlowerType2QP(numPeriods, DefaultFirstVertex);
                fixedPoint = null;
                break;

            case QPType.PointedFlower:
                qp      = UsefulQPs.GetPointedFlowerQP(numPeriods, DefaultFirstVertex);
                periods = UsefulQPs.GetPeriodsOfPointedFlowerQPWithoutFixedPoint(numPeriods, DefaultFirstVertex);
                throw new NotImplementedException();
                break;

            default:
                Debug.Fail($"Invalid QP type ({qpType}) specified.");
                qp         = null;
                periods    = null;
                fixedPoint = null;
                return(false);
            }

            return(true);
        }
示例#14
0
        public MaximalNonzeroEquivalenceClassRepresentativesResults <TVertex> ComputeMaximalNonzeroEquivalenceClassRepresentativesStartingAt <TVertex>(
            QuiverWithPotential <TVertex> qp,
            TVertex startingVertex,
            TransformationRuleTreeNode <TVertex> transformationRuleTree,
            QPAnalysisSettings settings)
            where TVertex : IEquatable <TVertex>, IComparable <TVertex>
        {
            var bogusPath       = new Path <TVertex>(qp.Quiver.Vertices.First());
            var analysisResults = AnalyzeWithStartingVertex(qp, startingVertex, transformationRuleTree, settings);
            var outputResults   = new MaximalNonzeroEquivalenceClassRepresentativesResults <TVertex>(
                analysisResults.NonCancellativityDetected ? CancellativityTypes.Cancellativity : CancellativityTypes.None,
                analysisResults.TooLongPathEncountered,
                analysisResults.MaximalPathRepresentatives.Select(node => node.Path),
                longestPathEncountered: bogusPath); // bogus path because this is an old method and the longest path feature is new

            return(outputResults);
        }
        public void AreIsomorphic_OnTriangleQPs()
        {
            var potential1 = new Potential <char>(new DetachedCycle <char>(new Path <char>('B', 'C', 'E', 'B')), +1)
                             .AddCycle(new DetachedCycle <char>(new Path <char>('A', 'B', 'C', 'A')), -1)
                             .AddCycle(new DetachedCycle <char>(new Path <char>('B', 'D', 'E', 'B')), -1)
                             .AddCycle(new DetachedCycle <char>(new Path <char>('C', 'E', 'F', 'C')), -1);

            var potential2 = new Potential <char>(new DetachedCycle <char>(new Path <char>('B', 'C', 'F', 'B')), +1)
                             .AddCycle(new DetachedCycle <char>(new Path <char>('C', 'F', 'E', 'C')), -1)
                             .AddCycle(new DetachedCycle <char>(new Path <char>('B', 'C', 'D', 'B')), -1)
                             .AddCycle(new DetachedCycle <char>(new Path <char>('A', 'F', 'B', 'A')), -1);

            var qp1     = new QuiverWithPotential <char>(potential1);
            var qp2     = new QuiverWithPotential <char>(potential2);
            var checker = new QPIsomorphismChecker();

            Assert.That(checker.AreIsomorphic(qp1, qp2), Is.True);
        }
示例#16
0
        public void TryExtractQP_WorksOnClockwiseCycle(int cycleLength)
        {
            const double Radius          = 1000;
            var          vertices        = Enumerable.Range(1, cycleLength);
            var          arrows          = vertices.Select(k => new Arrow <int>(k, k.Modulo(cycleLength) + 1));
            double       baseAngle       = 2 * Math.PI / cycleLength;
            var          vertexPositions = vertices.ToDictionary(k => k, k => new Point((int)(Radius * Math.Cos(-k * baseAngle)), (int)Math.Round(Radius * Math.Sin(-k * baseAngle))));
            var          quiverInPlane   = new QuiverInPlane <int>(vertices, arrows, vertexPositions);
            var          extractor       = CreateQPExtractor();

            var result            = extractor.TryExtractQP(quiverInPlane, out var qp);
            var expectedQuiver    = new Quiver <int>(vertices, arrows);
            var expectedPotential = new Potential <int>(new DetachedCycle <int>(vertices.AppendElement(1)), +1);
            var expectedQP        = new QuiverWithPotential <int>(expectedQuiver, expectedPotential);

            Assert.That(result, Is.EqualTo(QPExtractionResult.Success));
            Assert.That(qp, Is.EqualTo(expectedQP));
        }
示例#17
0
        /// <remarks>Like <see cref="TryExecuteRecipe(PotentialRecipe, int, out QuiverWithPotential{int})"/>
        /// but with a boolean parameter for throwing.</remarks>
        private bool InternalExecuteRecipe(PotentialRecipe recipe, int initialCycleNumArrows, out QuiverWithPotential <int> qp, bool shouldThrow)
        {
            if (recipe == null)
            {
                throw new ArgumentNullException(nameof(recipe));
            }
            if (initialCycleNumArrows <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(initialCycleNumArrows));
            }

            qp = null;

            var startCycle     = Utility.MakeCycle(0, initialCycleNumArrows);
            var startArrows    = startCycle.CanonicalPath.Arrows;
            var boundaryTuples = startArrows.Select(a => (a, BoundaryArrowOrientation.Right));
            var state          = new RecipeExecutorState
            {
                Potential  = new Potential <int>(startCycle, +1),
                NextVertex = initialCycleNumArrows,
                Boundary   = new CircularList <(Arrow <int>, BoundaryArrowOrientation)>(boundaryTuples),
                PotentiallyProblematicArrows = new HashSet <Arrow <int> >(),
            };

            foreach (var instruction in recipe.Instructions)
            {
                if (shouldThrow)
                {
                    state = instruction.Execute(state);
                }
                else if (!instruction.TryExecute(state, out state))
                {
                    return(false);
                }
            }

            qp = new QuiverWithPotential <int>(state.Potential);
            return(true);
        }
示例#18
0
        public QPExtractionResult TryExtractQP <TVertex>(QuiverInPlane <TVertex> quiverInPlane, out QuiverWithPotential <TVertex> qp)
            where TVertex : IEquatable <TVertex>, IComparable <TVertex>
        {
            if (quiverInPlane is null)
            {
                throw new ArgumentNullException(nameof(quiverInPlane));
            }

            // Not entirely sure that loops are a catastrophy
            if (quiverInPlane.HasLoops())
            {
                qp = null;
                return(QPExtractionResult.QuiverHasLoops);
            }

            if (quiverInPlane.HasAntiParallelArrows())
            {
                qp = null;
                return(QPExtractionResult.QuiverHasAntiParallelArrows);
            }

            // Algorithm:
            // 1. Perform a "face search" on the underlying graph, the output of which is a
            // collection of faces, each described by its bounding cycle (of non-directed edges)
            // 2. For every face, try to get its orientation in the directed quiver:
            //      If the bounding cycle or its reverse is a path in the directed quiver,
            //      determine the orientation (counterclockwise or clockwise).
            //      Else, return "QuiverHasFaceWithInconsistentOrientation"
            // 3. Construct the potential with positive cycles the cycles from step (2) with
            //    clockwise orientation and with negative cycles the cycles from step (2) with
            //    counterclockwise orientation
            // 4. Output the QP and return Success.

            var underlyingGraph = quiverInPlane.GetUnderlyingGraph();
            var faceFinder      = new FaceFinder();

            // Remember that this outputs counterclockwise bounding cycles.
            if (!faceFinder.TryFindFaces(underlyingGraph, out var boundingCyclesAsVertexCollections))
            {
                qp = null;
                return(QPExtractionResult.QuiverIsNotPlane);
            }

            var boundingCycles = boundingCyclesAsVertexCollections.Select(cycleAsVertexInPlaneCollection => cycleAsVertexInPlaneCollection.Select(vertexInPlane => vertexInPlane.Vertex))
                                 .Select(cycleAsVertexCollection => new DetachedCycle <TVertex>(cycleAsVertexCollection));

            var counterclockwiseFaceCycles = new List <DetachedCycle <TVertex> >();
            var clockwiseFaceCycles        = new List <DetachedCycle <TVertex> >();

            foreach (var cycle in boundingCycles)
            {
                // Counterclockwise bounding cycle in the directed quiver (and so on)
                if (cycle.CanonicalPath.Arrows.All(arrow => quiverInPlane.ContainsArrow(arrow)))
                {
                    counterclockwiseFaceCycles.Add(cycle);
                }
                else if (cycle.Reverse().CanonicalPath.Arrows.All(arrow => quiverInPlane.ContainsArrow(arrow)))
                {
                    clockwiseFaceCycles.Add(cycle.Reverse());
                }
                else
                {
                    qp = null;
                    return(QPExtractionResult.QuiverHasFaceWithInconsistentOrientation);
                }
            }

            var counterclockwiseDict = counterclockwiseFaceCycles.ToDictionary(cycle => cycle, cycle => - 1);
            var clockwiseDict        = clockwiseFaceCycles.ToDictionary(cycle => cycle, cycle => + 1);
            var dict      = counterclockwiseDict.Concat(clockwiseDict).ToDictionary(p => p.Key, p => p.Value);
            var potential = new Potential <TVertex>(dict);

            qp = new QuiverWithPotential <TVertex>(quiverInPlane.GetUnderlyingQuiver(), potential);
            return(QPExtractionResult.Success);

            //// Algorithm:
            //// Order the arrows from a vertex cyclically by the angle, say with a dictionary of cyclic lists:
            ////     vertex -> [target1, target2, ...]
            ////
            //// Because clockwise gets positive sign, it might be easier to order things cyclically by -angle
            ////
            //// Keep track of signed arrows "consumed" (the sign corresponding to turning left or right)
            ////
            //// While there is an arrow with a non-consumed sign (a non-consumed signed arrow, say):
            ////     Do a 'left/right (depending on the non-consumed sign) face search' for the arrow
            ////
            //// How a face search is done is documented elsewhere for now.
            ////
            //// This produces a collection of positively oriented faces (represented by the bounding cycle)
            //// and a collection of negatively oriented faces (represented by the bounding cycle)
            ////
            //// Take the bounding cycles of the positively oriented faces as the cycles in the potential with positive sign
            ////  and the bounding cycles of the negatively oriented faces as the cycles in the potential with negative sign


            //var counterclockwiseFaceCycles = SearchForFaces(Orientation.Counterclockwise);
            //var clockwiseFaceCycles = SearchForFaces(Orientation.Clockwise);
            //var leftDict = counterclockwiseFaceCycles.ToDictionary(cycle => cycle, cycle => -1);
            //var rightDict = clockwiseFaceCycles.ToDictionary(cycle => cycle, cycle => +1);
            //var dict = counterclockwiseDict.Concat(clockwiseDict).ToDictionary(p => p.Key, p => p.Value);
            //var potential = new Potential<TVertex>(dict);

            //qp = new QuiverWithPotential<TVertex>(quiverInPlane.GetUnderlyingQuiver(), potential);
            //return QPExtractorResult.Success;

            //IEnumerable<DetachedCycle<TVertex>> SearchForFaces(Orientation searchOrientation)
            //{
            //    var cycles = new HashSet<DetachedCycle<TVertex>>();
            //    var remainingArrows = new HashSet<Arrow<TVertex>>(quiverInPlane.GetArrows());
            //    var remainingArrowsStack = new Stack<Arrow<TVertex>>(quiverInPlane.GetArrows());
            //    while (remainingArrows.Count > 0)
            //    {
            //        Arrow<TVertex> startArrow;
            //        while (!remainingArrows.Contains(startArrow = remainingArrowsStack.Pop())) ;

            //        var path = new Path<TVertex>(startArrow.Source, startArrow.Target);

            //        var prevVertex = startArrow.Source;
            //        var curVertex = startArrow.Target;

            //        // Start the search for this start arrow!
            //        while (true)
            //        {
            //            // Terminate the search if we have found a cycle
            //            if (path.TryExtractTrailingCycle(out var closedPath, out int startIndex))
            //            {
            //                var cycleOrientation = quiverInPlane.GetOrientationOfCycle(closedPath);
            //                // If the orientations agree, then the cycle is a bounding cycle for a (bounded) face
            //                // Else, it bounds the unbounded face (which we do not care about)
            //                if (cycleOrientation == searchOrientation)
            //                {
            //                    var detachedCycle = new DetachedCycle<TVertex>(closedPath);

            //                    // When restarting with a boundary arrow, we might get the same cycle again
            //                    if (!cycles.Contains(detachedCycle)) cycles.Add(new DetachedCycle<TVertex>(closedPath));
            //                }

            //                foreach (var arrow in path.Arrows) remainingArrows.Remove(arrow);
            //                break;
            //            }

            //            // Get next successor (next in the angle sense)
            //            // If no successor, terminate the search (all arrows are direction-boundary arrows)
            //            // Else, update path, prevVertex and curVertex and do next iteration

            //            var successors = quiverInPlane.AdjacencyLists[curVertex];
            //            if (successors.Count == 0)
            //            {
            //                foreach (var arrow in path.Arrows) remainingArrows.Remove(arrow);
            //                break;
            //            }

            //            var baseVertex = curVertex;
            //            var basePos = quiverInPlane.GetVertexPosition(baseVertex);
            //            var successorsAndPredecessor = successors.AppendElement(prevVertex);

            //            // Sort the vertices by angle so that the vertex following the predecessor vertex (prevVertex) is
            //            // the vertex corresponding to a "maximal" turn.
            //            var successorsAndPredecessorSortedByAngle = searchOrientation == Orientation.Clockwise ?
            //                successorsAndPredecessor.OrderBy(vertex => quiverInPlane.GetVertexPosition(vertex), new AngleBasedPointComparer(basePos)) :
            //                successorsAndPredecessor.OrderByDescending(vertex => quiverInPlane.GetVertexPosition(vertex), new AngleBasedPointComparer(basePos));

            //            var successorsAndPredecessorSortedByAngleList = new CircularList<TVertex>(successorsAndPredecessorSortedByAngle);
            //            int predecessorIndex = successorsAndPredecessorSortedByAngleList.IndexOf(prevVertex);
            //            successorsAndPredecessorSortedByAngleList.RotateLeft(predecessorIndex);

            //            var nextVertex = successorsAndPredecessorSortedByAngleList.Skip(1).First();

            //            path = path.AppendVertex(nextVertex);
            //            prevVertex = curVertex;
            //            curVertex = nextVertex;
            //        }
            //    }

            //    return cycles;
            //}

            //var successorsSortedByAngle = quiverInPlane.Vertices.Select(baseVertex =>
            //{
            //    var basePos = quiverInPlane.GetVertexPosition(baseVertex);

            //    var sortedSuccessors = quiverInPlane.AdjacencyLists[baseVertex].OrderBy(vertex => quiverInPlane.GetVertexPosition(vertex), new AngleBasedPointComparer(basePos));

            //    var sortedVertexList = new CircularList<TVertex>(sortedSuccessors);
            //    return new KeyValuePair<TVertex, CircularList<TVertex>>(baseVertex, sortedVertexList);
            //}).ToDictionary(p => p.Key, p => p.Value);

            //var arrows = new HashSet<Arrow<TVertex>>(quiverInPlane.GetArrows());

            ////TODO: Continue here
            //throw new NotImplementedException();



            //// Old idea
            //// Algorithm:
            //// Order the arrows to/from a vertex cyclically by the angle, say with a dictionary of cyclic lists of tuples:
            ////     vertex -> [(outgoing/incoming, target/source), ...]
            ////
            //// Because clockwise gets positive sign, it might be easier to order things cyclically by -angle
            ////
            //// Keep track of arrows "consumed" and their signs
            ////
            //// For every vertex:
            ////     Begin with the first outgoing arrow
            ////     Check if the next arrow is incoming
            ////     If not,
            ////     Try to "turn right" (take the previous arrow)
            ////

            ////var neighborsSortedByAngle = quiverInPlane.Vertices.Select(baseVertex =>
            ////{
            ////    var basePos = quiverInPlane.GetVertexPosition(baseVertex);
            ////    var outgoingArrowTargetVertices = quiverInPlane.AdjacencyLists[baseVertex];
            ////    var incomingArrowSourceVertices = quiverInPlane.Vertices.Where(sourceVertex => quiverInPlane.AdjacencyLists[sourceVertex].Contains(baseVertex));
            ////    var undirectedlyAdjacentVertices = incomingArrowSourceVertices.Concat(outgoingArrowTargetVertices);
            ////    var sortedVertices = undirectedlyAdjacentVertices.OrderBy(vertex => quiverInPlane.GetVertexPosition(vertex), new AngleBasedPointComparer(basePos));
            ////    var sortedVertexList = new CircularList<TVertex>(sortedVertices);
            ////    return new KeyValuePair<TVertex, CircularList<TVertex>>(baseVertex, sortedVertexList);
            ////}).ToDictionary(p => p.Key, p => p.Value);

            ////var arrows = new HashSet<Arrow<TVertex>>(quiverInPlane.GetArrows());

            ////TODO: Continue here
            ////throw new NotImplementedException();
        }
示例#19
0
 /// <summary>
 /// Analyzes a QP with the default computer of maximal nonzero equivalence class
 /// representatives.
 /// </summary>
 /// <typeparam name="TVertex">The type of the vertices of the quiver.</typeparam>
 /// <param name="qp">The quiver with potential.</param>
 /// <param name="settings">The settings for the analysis.</param>
 /// <returns>The results of the analysis.</returns>
 /// <exception cref="ArgumentNullException"><paramref name="qp"/> is
 /// <see langword="null"/>, or <paramref name="settings"/> is
 /// <see langword="null"/>.</exception>
 /// <exception cref="NotSupportedException">The potential of <paramref name="qp"/> has a
 /// cycle with coefficient not equal to either of -1 and +1,
 /// or some arrow occurs multiple times in a single cycle of the potential of
 /// <paramref name="qp"/>.</exception>
 /// <exception cref="ArgumentException">For some arrow in the potential of
 /// <paramref name="qp"/> and sign, the arrow is contained in more than one cycle of that
 /// sign.</exception>
 public IQPAnalysisResults <TVertex> Analyze <TVertex>(QuiverWithPotential <TVertex> qp, QPAnalysisSettings settings)
     where TVertex : IEquatable <TVertex>, IComparable <TVertex>
 {
     return(Analyze(qp, settings, defaultComputer));
 }
        /// <remarks>This method should be made obsolete (prefer converting the QP to a
        /// semimonomial unbound quiver, and analyzing that instead (or at least creating the
        /// transformation rule tree for that instead).</remarks>
        public TransformationRuleTreeNode <TVertex> CreateTransformationRuleTree <TVertex>(QuiverWithPotential <TVertex> qp)
            where TVertex : IEquatable <TVertex>, IComparable <TVertex>
        {
            if (qp is null)
            {
                throw new ArgumentNullException(nameof(qp));
            }

            var root = new TransformationRuleTreeNode <TVertex>(false, null, null);

            foreach (var arrow in qp.Quiver.Arrows)
            {
                var linComb = new LinearCombination <Path <TVertex> >();
                foreach (var(cycle, coefficient) in qp.Potential.LinearCombinationOfCycles.ElementToCoefficientDictionary)
                {
                    linComb = linComb.Add(cycle.DifferentiateCyclically(arrow).Scale(coefficient));
                }

                AddRulesFromSingleLinearCombination(linComb, root);
            }

            return(root);
        }
示例#21
0
        private void DoSetup(QuiverWithPotential <int> qp, out TransformationRuleTreeNode <int> ruleTree)
        {
            var creator = new TransformationRuleTreeCreator();

            ruleTree = creator.CreateTransformationRuleTree(qp);
        }
示例#22
0
 /// <summary>
 /// Executes the specified recipe.
 /// </summary>
 /// <param name="recipe">The recipe according to which to generate the potential of the QP.</param>
 /// <param name="initialCycleNumArrows">The number of arrows in the first cycle.</param>
 /// <param name="qp">Output parameter for the QP generated according to the recipe. If the
 /// recipe is not executed successfully, the output value is <see langword="null"/>.</param>
 /// <returns>A boolean value indicating whether the recipe was executed successfully.</returns>
 public bool TryExecuteRecipe(PotentialRecipe recipe, int initialCycleNumArrows, out QuiverWithPotential <int> qp)
 {
     return(InternalExecuteRecipe(recipe, initialCycleNumArrows, out qp, false));
 }