/// <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); }
/// <summary> /// Analyzes a <see cref="QuiverInPlane{TVertex}"/>. /// </summary> /// <typeparam name="TVertex">The type of the vertices in the quiver.</typeparam> /// <param name="quiverInPlane">The quiver in plane to analyze.</param> /// <returns>The analysis results.</returns> /// <remarks> /// <para>If the analysis is unsuccessful, the value of the <c>MainResult</c> property /// of the returned analysis results does not have the /// <see cref="QuiverInPlaneAnalysisMainResults.Success"/> or the /// <see cref="QuiverInPlaneAnalysisMainResults.QPIsSelfInjective"/> flags set and has at least /// one of the other flags (each of which indicates some sort of failure) set. However, in /// the case of multiple causes for failure (e.g., the quiver has loops and anti-parallel /// arrows), all the corresponding flags are not necessarily set (e.g., /// <see cref="QuiverInPlaneAnalysisMainResults.QuiverHasLoops"/> is set but /// <see cref="QuiverInPlaneAnalysisMainResults.QuiverHasAntiParallelArrows"/> is not set, /// or <see cref="QuiverInPlaneAnalysisMainResults.QuiverHasAntiParallelArrows"/> is set but /// <see cref="QuiverInPlaneAnalysisMainResults.QuiverHasLoops"/> is not set).</para> /// <para>This method does not throw any exceptions (unless I've forgotten something).</para> /// </remarks> public IQuiverInPlaneAnalysisResults <TVertex> Analyze <TVertex>( QuiverInPlane <TVertex> quiverInPlane, QuiverInPlaneAnalysisSettings settings) where TVertex : IEquatable <TVertex>, IComparable <TVertex> { if (quiverInPlane is null) { throw new ArgumentNullException(nameof(quiverInPlane)); } var qpExtractor = new QPExtractor(); var extractionResult = qpExtractor.TryExtractQP(quiverInPlane, out var qp); if (extractionResult != QPExtractionResult.Success) { return(AnalysisResultsFactory.CreateQuiverInPlaneAnalysisResults <TVertex>(extractionResult)); } var analyzer = new QPAnalyzer(); var qpAnalyzerSettings = AnalysisSettingsFactory.CreateQPAnalysisSettings(settings); var qpAnalysisResults = analyzer.Analyze(qp, qpAnalyzerSettings); var analysisResults = AnalysisResultsFactory.CreateQuiverInPlaneAnalysisResults(qpAnalysisResults); return(analysisResults); }
/// <summary> /// Analyzes a semimonomial unbound quiver with a default computer of maximal nonzero /// equivalence class representatives. /// </summary> /// <typeparam name="TVertex">The type of the vertices of the quiver.</typeparam> /// <param name="unboundQuiver">The unbound quiver.</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="unboundQuiver"/> 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 semimonomial ideal of /// <paramref name="unboundQuiver"/> has two distinct non-monomial generators /// <c>p1 - q1</c> and <c>p2 - q2</c> where <c>p1, q1, p2, q2</c> are not all distinct.</exception> /// <exception cref="ArgumentException">The semimonomial ideal of /// <paramref name="unboundQuiver"/> has a non-monomial generator <c>p - q</c> where the /// paths <c>p</c> and <c>q</c> do not have the same endpoints.</exception> public ISemimonomialUnboundQuiverAnalysisResults <TVertex> Analyze <TVertex>( SemimonomialUnboundQuiver <TVertex> unboundQuiver, SemimonomialUnboundQuiverAnalysisSettings settings, IMaximalNonzeroEquivalenceClassRepresentativeComputer computer) where TVertex : IEquatable <TVertex>, IComparable <TVertex> { if (unboundQuiver is null) { throw new ArgumentNullException(nameof(unboundQuiver)); } if (settings is null) { throw new ArgumentNullException(nameof(settings)); } if (computer is null) { throw new ArgumentNullException(nameof(computer)); } var computationSettings = AnalysisSettingsFactory.CreateMaximalNonzeroEquivalenceClassRepresentativeComputationSettings(settings); var transformationRuleTreeCreator = new TransformationRuleTreeCreator(); var transformationRuleTree = transformationRuleTreeCreator.CreateTransformationRuleTree(unboundQuiver); var maximalPathRepresentatives = new Dictionary <TVertex, IEnumerable <Path <TVertex> > >(); var nakayamaPermutationDict = new Dictionary <TVertex, TVertex>(); var mainResults = SemimonomialUnboundQuiverAnalysisMainResults.None; Path <TVertex> longestPath = null; foreach (var startingVertex in unboundQuiver.Quiver.Vertices) { var representativesResult = computer.ComputeMaximalNonzeroEquivalenceClassRepresentativesStartingAt(unboundQuiver.Quiver, startingVertex, transformationRuleTree, computationSettings); if (longestPath is null || representativesResult.LongestPathEncountered.Length > longestPath.Length) { longestPath = representativesResult.LongestPathEncountered; } if (representativesResult.WeakCancellativityFailureDetected) { mainResults |= SemimonomialUnboundQuiverAnalysisMainResults.NotWeaklyCancellative; } if (representativesResult.CancellativityFailureDetected) { mainResults |= SemimonomialUnboundQuiverAnalysisMainResults.NotCancellative; } if (representativesResult.TooLongPathEncountered) { mainResults |= SemimonomialUnboundQuiverAnalysisMainResults.Aborted; } if ((representativesResult.WeakCancellativityFailureDetected && settings.TerminateEarlyIfWeakCancellativityFails) || (representativesResult.CancellativityFailureDetected && settings.TerminateEarlyIfCancellativityFails) || (representativesResult.TooLongPathEncountered)) { return(new SemimonomialUnboundQuiverAnalysisResults <TVertex>(mainResults, null, null, longestPath)); } var maximalNonzeroEquivalenceClassRepresentatives = representativesResult.MaximalNonzeroEquivalenceClassRepresentatives; maximalPathRepresentatives[startingVertex] = maximalNonzeroEquivalenceClassRepresentatives; int numMaximalNonzeroPathClasses = maximalNonzeroEquivalenceClassRepresentatives.Count(); Debug.Assert(numMaximalNonzeroPathClasses > 0, "Analysis with starting vertex found 0 maximal nonzero classes."); if (numMaximalNonzeroPathClasses > 1) { mainResults |= SemimonomialUnboundQuiverAnalysisMainResults.MultipleMaximalNonzeroClasses; if (settings.TerminateEarlyOnMultiDimensionalSocle) { return(new SemimonomialUnboundQuiverAnalysisResults <TVertex>(mainResults, null, null, longestPath)); } } else { var endingPoint = maximalNonzeroEquivalenceClassRepresentatives.Single().EndingPoint; // Check if the tentative Nakayama permutation fails to be injective. if (nakayamaPermutationDict.ContainsValue(endingPoint)) { mainResults |= SemimonomialUnboundQuiverAnalysisMainResults.NonInjectiveTentativeNakayamaPermutation; if (settings.TerminateEarlyIfNakayamaPermutationFails) { return(new SemimonomialUnboundQuiverAnalysisResults <TVertex>(mainResults, null, null, longestPath)); } } else { nakayamaPermutationDict[startingVertex] = endingPoint; } } } mainResults |= SemimonomialUnboundQuiverAnalysisMainResults.Success; NakayamaPermutation <TVertex> nakayamaPermutation = null; if (mainResults.IndicatesSelfInjectivity()) { nakayamaPermutation = new NakayamaPermutation <TVertex>(nakayamaPermutationDict); } return(new SemimonomialUnboundQuiverAnalysisResults <TVertex>(mainResults, maximalPathRepresentatives, nakayamaPermutation, longestPath)); }
/// <summary> /// Analyzes a semimonomial unbound quiver in a way that utilizes the /// "periodicity" of the unbound quiver and concurrently. /// The analysis is done using a specified computer of maximal nonzero /// equivalence class representatives. /// </summary> /// <typeparam name="TVertex">The type of the vertices of the quiver.</typeparam> /// <param name="unboundQuiver">The unbound quiver.</param> /// <param name="periods">A collection of consecutive non-empty periods of the unbound /// quiver that are jointly exhaustive and mutually exclusive.</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="unboundQuiver"/> is /// <see langword="null"/>, /// or <paramref name="periods"/> 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 semimonomial ideal of /// <paramref name="unboundQuiver"/> has two distinct non-monomial generators /// <c>p1 - q1</c> and <c>p2 - q2</c> where <c>p1, q1, p2, q2</c> are not all distinct.</exception> /// <exception cref="ArgumentException">The semimonomial ideal of /// <paramref name="unboundQuiver"/> has a non-monomial generator <c>p - q</c> where the /// paths <c>p</c> and <c>q</c> do not have the same endpoints, /// 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 /// "periods" of the unbound quiver.</para> /// </remarks> public ISemimonomialUnboundQuiverAnalysisResults <TVertex> AnalyzeUtilizingPeriodicityConcurrently <TVertex>( SemimonomialUnboundQuiver <TVertex> unboundQuiver, IEnumerable <IEnumerable <TVertex> > periods, SemimonomialUnboundQuiverAnalysisSettings settings, IMaximalNonzeroEquivalenceClassRepresentativeComputer computer) where TVertex : IEquatable <TVertex>, IComparable <TVertex> { if (unboundQuiver is null) { throw new ArgumentNullException(nameof(unboundQuiver)); } if (periods is null) { throw new ArgumentNullException(nameof(periods)); } if (settings is null) { throw new ArgumentNullException(nameof(settings)); } if (computer is null) { throw new ArgumentNullException(nameof(computer)); } var computationSettings = AnalysisSettingsFactory.CreateMaximalNonzeroEquivalenceClassRepresentativeComputationSettings(settings); var transformationRuleTreeCreator = new TransformationRuleTreeCreator(); var transformationRuleTree = transformationRuleTreeCreator.CreateTransformationRuleTree(unboundQuiver); // Remark: We cannot terminate before the CreateTransformationRuleTree method is called, // because it is responsible for throwing an ArgumentException. var verticesInPeriods = new HashSet <TVertex>(); foreach (var period in periods) { if (period.Any(vertex => verticesInPeriods.Contains(vertex))) { throw new ArgumentException("The periods overlap."); } verticesInPeriods.UnionWith(period); } var quiver = unboundQuiver.Quiver; if (!quiver.Vertices.SetEquals(verticesInPeriods)) { throw new ArgumentException("The union of the periods is not the collection of all vertices in the quiver."); } var maximalPathRepresentativesDict = new ConcurrentDictionary <TVertex, IEnumerable <Path <TVertex> > >(); var nakayamaPermutationDict = new ConcurrentDictionary <TVertex, TVertex>(); if (!periods.Any()) { return(ExtendResultForPeriodToEntireQuiver( periods, maximalPathRepresentativesDict, nakayamaPermutationDict, null, false, false, false, false, false)); } // The period of the vertices whose socles to investigate. var firstPeriod = periods.First(); // The period into which all the analyzed vertices are mapped by the tentative Nakayama permutation. ISet <TVertex> targetPeriod = null; // These aren't used, are they? var cts = new CancellationTokenSource(); var options = new ParallelOptions() { CancellationToken = cts.Token }; // Variable into which to put the output of the execution that doesn't go into the // some other variable (maximalPathRepresentatives and nakayamaPermutationDict). // Called globalState because it aggregates all the local states. var globalState = ( longestPath : (Path <TVertex>)null, nonCancellativityDetected : false, tooLongPathEncountered : false, multiDimensionalSocleEncountered : false, permutationFails : false, cancelledEarly : false); var globalStateLock = new object(); Parallel.ForEach( // The enumerable to iterate over. firstPeriod, // Options for the parallel execution, used to pass a cancellation token. options, // localInit delegate used to get the initial value of localState for each task/"thread". () => ( longestPath: (Path <TVertex>)null, nonCancellativityDetected: false, tooLongPathEncountered: false, multiDimensionalSocleEncountered: false, permutationFails: false, cancelledEarly: false), // body delegate that contains the loop body. (startingVertex, loopState, localState) => { if (loopState.ShouldExitCurrentIteration) { return(localState); } var representativesResult = computer.ComputeMaximalNonzeroEquivalenceClassRepresentativesStartingAt(unboundQuiver.Quiver, startingVertex, transformationRuleTree, computationSettings); if (localState.longestPath is null || representativesResult.LongestPathEncountered.Length > localState.longestPath.Length) { localState.longestPath = representativesResult.LongestPathEncountered; } if (representativesResult.CancellativityFailureDetected) { localState.nonCancellativityDetected = true; if (settings.TerminateEarlyIfCancellativityFails) { localState.cancelledEarly = true; loopState.Stop(); } } if (representativesResult.TooLongPathEncountered) { localState.tooLongPathEncountered = true; localState.cancelledEarly = true; loopState.Stop(); } if (loopState.ShouldExitCurrentIteration) { return(localState); } var maximalNonzeroEquivalenceClassRepresentatives = representativesResult.MaximalNonzeroEquivalenceClassRepresentatives; maximalPathRepresentativesDict[startingVertex] = maximalNonzeroEquivalenceClassRepresentatives; int numMaximalNonzeroPathClasses = maximalNonzeroEquivalenceClassRepresentatives.Count(); if (numMaximalNonzeroPathClasses > 1) { localState.multiDimensionalSocleEncountered = true; if (settings.TerminateEarlyOnMultiDimensionalSocle) { localState.cancelledEarly = true; loopState.Stop(); return(localState); } } var endingPoint = maximalNonzeroEquivalenceClassRepresentatives.Single().EndingPoint; lock (nakayamaPermutationDict) { // If this was the first vertex analyzed, set the target period. if (targetPeriod is null) { targetPeriod = periods.First(period => period.Contains(endingPoint)).ToSet(); } // Else check that the current vertex is mapped into the same period as the first vertex. // If not, there cannot be a Nakayama permutation. else if (!targetPeriod.Contains(endingPoint)) { localState.permutationFails = true; if (settings.TerminateEarlyIfNakayamaPermutationFails) { localState.cancelledEarly = true; loopState.Stop(); return(localState); } } // If the current vertex maps to a vertex to which some other vertex have // already been mapped. // If not, there cannot be a Nakayama permutation. if (nakayamaPermutationDict.Values.Contains(endingPoint)) { localState.permutationFails = true; if (settings.TerminateEarlyIfNakayamaPermutationFails) { localState.cancelledEarly = true; loopState.Stop(); return(localState); } } nakayamaPermutationDict[startingVertex] = endingPoint; return(localState); } }, // localFinally delegate used to output the local states to the outside. localState => { lock (globalStateLock) { if (globalState.longestPath is null || (localState.longestPath != null && localState.longestPath.Length > globalState.longestPath.Length)) { globalState.longestPath = localState.longestPath; } if (localState.tooLongPathEncountered) { globalState.tooLongPathEncountered = true; } if (localState.nonCancellativityDetected) { globalState.nonCancellativityDetected = true; } if (localState.multiDimensionalSocleEncountered) { globalState.multiDimensionalSocleEncountered = true; } if (localState.permutationFails) { localState.permutationFails = true; } if (localState.cancelledEarly) { globalState.cancelledEarly = true; } } }); return(ExtendResultForPeriodToEntireQuiver( periods, maximalPathRepresentativesDict, nakayamaPermutationDict, globalState.longestPath, globalState.tooLongPathEncountered, globalState.nonCancellativityDetected, globalState.multiDimensionalSocleEncountered, globalState.permutationFails, globalState.cancelledEarly)); }