Esempio n. 1
0
        public void Do()
        {
            var importer = new QuiverInPlaneFromMutationAppImporter();
            var quiverInPlaneAfterAction = importer.ImportQuiverInPlane(path);

            // Copying the quiver is important, because actions done on this very object might be
            // undone on an equal but not reference-equal object. Consider the following example:

            /*
             * 1. Import (the action as a quiverInPlaneAfterAction)
             * 2. Actions
             * 3. Load/import (which stores a copy of quiverInPlane as quiverInPlaneBeforeAction)
             * 4. Undo load/import (line 3)
             *                  quiverInPlane is now not reference-equal to quiverInPlaneAfterAction on line 1; it is reference-equal to the copy made on line 3
             * 5. Undo actions (line 2)
             *                  This step did not modify quiverInPlaneAfterAction on line 1 but rather the copy made on line 3
             * 6. Undo import
             * 7. Redo import
             *                  This loads quiverInPlaneAfterAction, which is supposed to be equal to the quiver after line 1 but is equal to the quiver after line 2 !
             * 8. Redo actions
             *                  This fails (e.g., if the action on line 2 was adding a vertex, then the vertex would already exist)
             */
            this.quiverInPlaneAfterAction = quiverInPlaneAfterAction.Copy();

            model.JustLoadQuiver(quiverInPlaneAfterAction);
        }
Esempio n. 2
0
        public void TryExtractQP_DoesNotThrow_WhenEncounteringFaceMoreThanOnce()
        {
            var vertices = new int[] { 1, 2, 3, 4, 5 };
            var arrows   = new Arrow <int>[]
            {
                new Arrow <int>(1, 2),
                new Arrow <int>(2, 3),
                new Arrow <int>(3, 1),
                new Arrow <int>(1, 4),
                new Arrow <int>(4, 5),
                new Arrow <int>(5, 1),
                new Arrow <int>(2, 5)
            };

            var vertexPositions = new Dictionary <int, Point>
            {
                { 1, new Point(0, 0) },
                { 2, new Point(1, -1) },
                { 3, new Point(-1, -1) },
                { 4, new Point(-1, 1) },
                { 5, new Point(1, 1) },
            };

            var quiverInPlane = new QuiverInPlane <int>(vertices, arrows, vertexPositions);
            var extractor     = CreateQPExtractor();

            Assert.That(() => extractor.TryExtractQP(quiverInPlane, out _), Throws.Nothing);
        }
        public void Analyze_WorksOnClockwiseCycle(int cycleLength)
        {
            const double Radius          = 1000;
            var          vertices        = Enumerable.Range(0, cycleLength).ToList();
            var          arrows          = vertices.Select(k => new Arrow <int>(k, (k + 1).Modulo(cycleLength)));
            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(analyzer, settings) = CreateAnalyzerWithSettings();

            var results = analyzer.Analyze(quiverInPlane, settings);

            Assert.That(results.MainResults, Is.EqualTo(QuiverInPlaneAnalysisMainResults.Success));
            Assert.That(results.MainResults.IndicatesSelfInjectivity());
            var expectedMaximalPathRepresentatives = vertices.ToDictionary(
                k => k,
                k => new Path <int>[] { new Path <int>(Enumerable.Range(k, vertices.Count - 1).Select(l => l.Modulo(vertices.Count))) });

            Assert.That(results.MaximalPathRepresentatives.ToList(), Is.EqualTo(expectedMaximalPathRepresentatives));

            var expectedNakayamaPermutation = vertices.ToDictionary(k => k, k => (k - 2).Modulo(vertices.Count));

            Assert.That(results.NakayamaPermutation.UnderlyingDictionary, Is.EqualTo(expectedNakayamaPermutation));
        }
Esempio n. 4
0
        /// <summary>
        /// Exports the specified quiver to the file with the specified path.
        /// </summary>
        /// <param name="path">The path of the file to which to export the quiver.</param>
        /// <param name="quiverInPlane">The quiver to export.</param>
        /// <remarks>
        /// <para>The labels of the vertices are not stored explicitly in the Mutation App file
        /// format, so the labels are in general not preserved.</para>
        /// </remarks>
        /// <exception cref="ExporterException">The file was not exported successfully.</exception>
        public void ExportQuiverInPlane(string path, QuiverInPlane <int> quiverInPlane)
        {
            if (path is null)
            {
                throw new ArgumentNullException(nameof(path));
            }
            if (quiverInPlane is null)
            {
                throw new ArgumentNullException(nameof(quiverInPlane));
            }

            string data = GetMutationAppStringForQuiverInPlane(quiverInPlane);

            string errorMessage = "Failed to export quiver to file.";

            try
            {
                File.WriteAllText(path, data);
            }
            catch (ArgumentNullException ex) { throw new ExporterException(errorMessage, ex); }
            catch (ArgumentException ex) { throw new ExporterException(errorMessage, ex); }
            catch (PathTooLongException ex) { throw new ExporterException(errorMessage, ex); }
            catch (DirectoryNotFoundException ex) { throw new ExporterException(errorMessage, ex); }
            catch (IOException ex) { throw new ExporterException(errorMessage, ex); }
            catch (UnauthorizedAccessException ex) { throw new ExporterException(errorMessage, ex); }
            catch (NotSupportedException ex) { throw new ExporterException(errorMessage, ex); }
            catch (System.Security.SecurityException ex) { throw new ExporterException(errorMessage, ex); }
        }
Esempio n. 5
0
        /// <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);
        }
Esempio n. 6
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;
 }
Esempio n. 7
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));
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="LoadPredefinedQuiverAction"/> class.
 /// </summary>
 /// <param name="model">The quiver-editor model.</param>
 /// <param name="predefinedQuiver">The type of predefined quiver to load.</param>
 /// <param name="quiverParameter">The parameter for the predefined quiver to load.</param>
 /// <param name="quiverInPlaneBeforeAction">The quiver in plane before the action.</param>
 /// <remarks>
 /// <para>This constructor takes care of copying
 /// <paramref name="quiverInPlaneBeforeAction"/> to ensure that the quiver in plane before
 /// the action that is stored in this <see cref="LoadPredefinedQuiverAction"/> is not
 /// modified.</para>
 /// </remarks>
 public LoadPredefinedQuiverAction(QuiverEditorModel model, PredefinedQuiver predefinedQuiver, dynamic quiverParameter, QuiverInPlane <int> quiverInPlaneBeforeAction)
 {
     this.model = model ?? throw new ArgumentNullException(nameof(model));
     if (!predefinedQuiver.IsInEnum())
     {
         throw new ArgumentOutOfRangeException(nameof(predefinedQuiver));
     }
     this.predefinedQuiver          = predefinedQuiver;
     this.quiverParameter           = quiverParameter;
     this.quiverInPlaneBeforeAction = quiverInPlaneBeforeAction?.Copy() ?? throw new ArgumentNullException(nameof(quiverInPlaneBeforeAction));
 }
Esempio n. 9
0
        public void TryExtractQP_ReturnsQuiverHasFaceWithInconsistentOrientation_For4CycleWithMiddleArrow()
        {
            var vertices = new int[] { 1, 2, 3, 4 };
            var arrows   = vertices.Select(k => new Arrow <int>(k, (k % 4) + 1));

            arrows = arrows.AppendElement(new Arrow <int>(2, 4));
            var vertexPositions = vertices.ToDictionary(k => k, k => new Point(
                                                            (int)(1000 * Math.Cos(k * 2 * Math.PI / vertices.Count())),
                                                            (int)(1000 * Math.Sin(k * 2 * Math.PI / vertices.Count()))));
            var quiverInPlane = new QuiverInPlane <int>(vertices, arrows, vertexPositions);
            var extractor     = CreateQPExtractor();

            Assert.That(extractor.TryExtractQP(quiverInPlane, out _), Is.EqualTo(QPExtractionResult.QuiverHasFaceWithInconsistentOrientation));
        }
        private QuiverInPlane <int> GetQuiverInPlaneFromParsedData(int numVertices, bool[,] adjacencyMatrix, Point[] vertexPositions)
        {
            const int FirstVertex = 1;
            var       vertices    = Enumerable.Range(FirstVertex, numVertices);

            var arrows = adjacencyMatrix.Select((val, indices) => val ? new Arrow <int>(indices.Item1 + FirstVertex, indices.Item2 + FirstVertex) : null)
                         .Where(val => val != null);

            var vertexPositionDict = vertexPositions.Select((point, i) => new KeyValuePair <int, Point>(i + FirstVertex, point))
                                     .ToDictionary(p => p.Key, p => p.Value);

            var quiverInPlane = new QuiverInPlane <int>(vertices, arrows, vertexPositionDict);

            return(quiverInPlane);
        }
Esempio n. 11
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));
        }
Esempio n. 12
0
        public IEnumerable <InteractiveLayeredQuiverGeneratorOutput> GenerateFromBaseForFixedLayerType(
            QuiverInPlane <int> quiverInPlane,
            Potential <int> potential,
            IEnumerable <int> boundaryLayer,
            LayerType layerType,
            ICompositionGenerator compositionGenerator,
            int nextVertex)
        {
            if (quiverInPlane is null)
            {
                throw new ArgumentNullException(nameof(quiverInPlane));
            }
            if (potential is null)
            {
                throw new ArgumentNullException(nameof(potential));
            }
            if (boundaryLayer is null)
            {
                throw new ArgumentNullException(nameof(boundaryLayer));
            }
            if (layerType is null)
            {
                throw new ArgumentNullException(nameof(layerType));
            }
            if (compositionGenerator is null)
            {
                throw new ArgumentNullException(nameof(compositionGenerator));
            }

            var interactiveGenerator = new InteractiveLayeredQuiverGenerator();

            if (!interactiveGenerator.TryStartGenerationFromBase(quiverInPlane, potential, boundaryLayer, layerType, nextVertex, out var nextCompositionParameters))
            {
                return(new InteractiveLayeredQuiverGeneratorOutput[0]);
            }

            return(DoWork(interactiveGenerator, nextCompositionParameters, compositionGenerator));
        }
Esempio n. 13
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ImportQuiverFromMutationAppFileAction"/>
 /// class.
 /// </summary>
 /// <param name="model">The quiver-editor model.</param>
 /// <param name="path">The path of the file from which to import the quiver.</param>
 /// <param name="quiverInPlaneBeforeAction">The quiver in plane before the action.</param>
 /// <para>This constructor takes care of copying
 /// <paramref name="quiverInPlaneBeforeAction"/> to ensure that the quiver in plane before
 /// the action that is stored in this <see cref="ImportQuiverFromMutationAppFileAction"/>
 /// is not modified.</para>
 public ImportQuiverFromMutationAppFileAction(QuiverEditorModel model, string path, QuiverInPlane <int> quiverInPlaneBeforeAction)
 {
     this.model = model ?? throw new ArgumentNullException(nameof(model));
     this.path  = path ?? throw new ArgumentNullException(nameof(path));
     this.quiverInPlaneBeforeAction = quiverInPlaneBeforeAction?.Copy() ?? throw new ArgumentNullException(nameof(quiverInPlaneBeforeAction));
 }
Esempio n. 14
0
        /// <summary>
        /// Gets the string contents of a Mutation App file corresponding to the specified quiver
        /// in plane.
        /// </summary>
        /// <param name="quiverInPlane"></param>
        /// <returns></returns>
        private string GetMutationAppStringForQuiverInPlane(QuiverInPlane <int> quiverInPlane)
        {
            var builder  = new StringBuilder();
            var vertices = quiverInPlane.Vertices.Sorted().ToList();

            builder.AppendLine("//Number of points");
            builder.AppendLine($"{vertices.Count}");

            builder.AppendLine("//Vertex radius");
            const int VertexRadius = 9;

            builder.AppendLine($"{VertexRadius}");

            builder.AppendLine("//Labels shown");
            const bool LabelsShown = true;

            builder.AppendLine($"{(LabelsShown ? 1 : 0)}");

            builder.AppendLine("//Matrix");
            builder.AppendLine($"{vertices.Count} {vertices.Count}");
            foreach (var sourceVertex in vertices.Sorted())
            {
                var adjacencyValues       = vertices.Sorted().Select(targetVertex => GetAdjacencyValue(sourceVertex, targetVertex));
                var adjacencyValuesString = String.Join(" ", adjacencyValues);
                builder.AppendLine(adjacencyValuesString);
            }

            int GetAdjacencyValue(int source, int target)
            {
                if (quiverInPlane.AdjacencyLists[source].Contains(target))
                {
                    return(1);
                }
                else if (quiverInPlane.AdjacencyLists[target].Contains(source))
                {
                    return(-1);
                }
                else
                {
                    return(0);
                }
            }

            builder.AppendLine("//Growth factor");
            const double GrowthFactor = 0.2;

            builder.AppendLine(Invariant($"{GrowthFactor}"));

            builder.AppendLine("//Arrow label size");
            const double ArrowLabelSize = 12.0;

            builder.AppendLine(Invariant($"{ArrowLabelSize:F1}"));

            builder.AppendLine("//Traffic lights");
            const bool TrafficLights = false;

            builder.AppendLine($"{(TrafficLights ? 1 : 0)}");

            builder.AppendLine("//Points");
            foreach (var vertex in vertices.Sorted())
            {
                const int  ThisVertexRadius = 9;
                double     x      = quiverInPlane.GetVertexPosition(vertex).X;
                double     y      = quiverInPlane.GetVertexPosition(vertex).Y;
                const bool Frozen = false;

                builder.AppendLine(Invariant($"{ThisVertexRadius} {x:F1} {y:F1} {(Frozen ? 1 : 0)}"));
            }

            builder.AppendLine("//Historycounter");
            const int HistoryCounter = -1;

            builder.AppendLine($"{HistoryCounter}");

            builder.AppendLine("//History");
            var history       = new int[] { };
            var historyString = String.Join(" ", history);

            builder.AppendLine(historyString);

            builder.AppendLine("//Cluster is null");

            return(builder.ToString());
        }
 public QuiverLoadedEventArgs(QuiverInPlane <int> quiverInPlane)
 {
     QuiverInPlane = quiverInPlane ?? throw new ArgumentNullException(nameof(quiverInPlane));
 }