Ejemplo n.º 1
0
 public bool Equals(DifferenceOfPaths <TVertex> otherDifference)
 {
     if (otherDifference is null)
     {
         return(false);
     }
     return(Minuend.Equals(otherDifference.Minuend) && Subtrahend.Equals(otherDifference.Subtrahend));
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SemimonomialIdeal{TVertex}"/> class.
        /// </summary>
        /// <param name="paths">The monomial generators of the ideal.</param>
        /// <param name="differencesOfPaths">The non-monomial generators of the ideal.</param>
        /// <exception cref="ArgumentNullException"><paramref name="paths"/> is <see langword="null"/>,
        /// or <paramref name="differencesOfPaths"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentException"><paramref name="paths"/> contains a duplicate path,
        /// or <paramref name="differencesOfPaths"/> contains a redundant difference of paths (i.e.,
        /// a duplicate difference of paths up to the equivalence relation of negating differences
        /// of paths).</exception>
        public SemimonomialIdeal(IEnumerable <Path <TVertex> > paths, IEnumerable <DifferenceOfPaths <TVertex> > differencesOfPaths)
        {
            if (paths is null)
            {
                throw new ArgumentNullException(nameof(paths));
            }
            if (differencesOfPaths is null)
            {
                throw new ArgumentNullException(nameof(differencesOfPaths));
            }

            if (paths.TryGetDuplicate(out var duplicate))
            {
                throw new ArgumentException($"{nameof(paths)} contains a duplicate path {duplicate}.");
            }
            if (TryGetDuplicateDifference(differencesOfPaths, out var duplicateDifference))
            {
                throw new ArgumentException($"{nameof(differencesOfPaths)} contains a redundant generator {duplicate}.");
            }

            Paths = paths;
            DifferencesOfPaths = differencesOfPaths;

            bool TryGetDuplicateDifference(IEnumerable <DifferenceOfPaths <TVertex> > diffsOfPaths, out DifferenceOfPaths <TVertex> duplicateDiff)
            {
                var copy = new HashSet <DifferenceOfPaths <TVertex> >();

                foreach (var d in diffsOfPaths)
                {
                    if (copy.Contains(d) || copy.Contains(d.Negate()))
                    {
                        duplicateDiff = new DifferenceOfPaths <TVertex>(d.Minuend, d.Subtrahend);
                        return(true);
                    }
                }

                duplicateDiff = default;
                return(false);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Creates a new instance of the <see cref="SemimonomialIdeal{TVertex}"/> class that
        /// represents the Jacobian ideal of the given potential (in some unspecified quiver
        /// containing all the arrows in the potential).
        /// </summary>
        /// <param name="potential">The potential whose semimonomial Jacobian ideal to create.</param>
        /// <returns>The semimonomial Jacobian ideal of <paramref name="potential"/>.</returns>
        /// <exception cref="NotSupportedException"><paramref name="potential"/> has a cycle with
        /// coefficient not equal to either of -1 and +1,
        /// or some arrow occurs multiple times in a single cycle of <paramref name="potential"/>.</exception>
        /// <exception cref="ArgumentException">For some arrow in <paramref name="potential"/> and
        /// sign, the arrow is contained in more than one cycle of that sign.</exception>
        /// <remarks>
        /// <para>The preconditions on <paramref name="potential"/> as of this writing is that the
        /// the scalars are <c>-1</c> or <c>+1</c>, every arrow occurs in at most one cycle per
        /// sign, and every arrow occurs at most once per cycle.</para>
        /// <para>The reasoning behind the differentiation between <see cref="NotSupportedException"/>
        /// and <see cref="ArgumentException"/> is that <see cref="NotSupportedException"/> is
        /// thrown when things might work out in theory (e.g., all scalars could be -2 or +2
        /// instead of -1 or +1, or an arrow could appear more than once in a cycle if the cycle is
        /// a suitable power of some other cycle (and stars align if the arrow is also contained in
        /// a cycle of the opposite sign)), while <see cref="ArgumentException"/> is thrown when
        /// things do not work out even in theory (i.e., semimonomiality fails to hold). That is,
        /// <see cref="NotSupportedException"/> is thrown in cases that might be &quot;fixed&quot;
        /// in the future.</para>
        /// </remarks>
        public static SemimonomialIdeal <TVertex> CreateSemimonomialIdealFromPotential <TVertex>(Potential <TVertex> potential)
            where TVertex : IEquatable <TVertex>, IComparable <TVertex>
        {
            // Validation
            var cycleCoefficients = new HashSet <int>(potential.LinearCombinationOfCycles.ElementToCoefficientDictionary.Values);

            if (!cycleCoefficients.IsSubsetOf(new int[] { -1, +1 }))
            {
                throw new NotSupportedException("Only potentials with all coefficients equal to +1 or -1 are supported.");
            }

            if (potential.Cycles.Any(cycle => cycle.Arrows.HasDuplicate()))
            {
                throw new NotSupportedException("Potentials with an arrow occurring more than once in a cycle are not supported.");
            }

            var signedCycles = potential.LinearCombinationOfCycles.ElementToCoefficientDictionary;
            var signedArrows = signedCycles.SelectMany(pair =>
            {
                var cycle = pair.Key;
                var sign  = pair.Value;
                return(cycle.Arrows.Select(arrow => (arrow, sign)));
            });

            if (signedArrows.TryGetDuplicate(out var duplicate))
            {
                throw new ArgumentException($"The potential has a signed arrow {duplicate} occurring in more than one cycle.", nameof(potential));
            }

            var monomialGenerators    = new List <Path <TVertex> >();
            var nonMonomialGenerators = new List <DifferenceOfPaths <TVertex> >();

            var arrows = potential.Cycles.SelectMany(cycle => cycle.Arrows).WithoutDuplicates();

            foreach (var arrow in arrows)
            {
                // Guaranteed by the validation to have only terms with coefficients +1 or -1
                // Also guaranteed to have at most 2 terms
                var linCombOfPaths = potential.DifferentiateCyclically(arrow);

                var numTerms = linCombOfPaths.NumberOfTerms;
                if (numTerms == 1)
                {
                    monomialGenerators.Add(linCombOfPaths.Elements.Single());
                }
                else if (numTerms == 2)
                {
                    var paths             = linCombOfPaths.Elements.ToList();
                    var differenceOfPaths = new DifferenceOfPaths <TVertex>(paths[0], paths[1]);
                    nonMonomialGenerators.Add(differenceOfPaths);
                }
                else
                {
                    System.Diagnostics.Debug.Fail($"{numTerms} terms in the cyclic derivative with respect to {arrow}. Expected at most two terms.");
                }
            }

            var semimonomialIdeal = new SemimonomialIdeal <TVertex>(monomialGenerators, nonMonomialGenerators);

            return(semimonomialIdeal);
        }