private static IEnumerable <BigIntRange> EnumerateIncludedRanges(IEnumerable <BigIntRangeBound> sortedBounds) { BigInteger?prevBound = null; //only non-null when the previous bound is incomplete and needs the next bound before anything can be returned foreach (var bound in sortedBounds) { if (bound.Direction == Direction.Nowhere) { if (prevBound != null) { throw new InvalidOperationException("Underlying sorted set of range bounds is corrupt - previous bound (at value " + prevBound.Value + ") expected a matching closing bound next but current bound (at value " + bound.Bound + ") represents a single point."); } yield return(BigIntRange.Single(bound.Bound)); } else if (bound.Direction == Direction.Up) { if (prevBound != null) { throw new InvalidOperationException("Underlying sorted set of range bounds is corrupt - previous bound (at value " + prevBound.Value + ") expected a matching closing bound next but current bound (at value " + bound.Bound + ") represents the start of a new range."); } prevBound = bound.Bound; } else { if (prevBound == null) { throw new InvalidOperationException("Underlying sorted set of range bounds is corrupt - current bound (at value " + bound.Bound + ") represents the end of a range, but the previous bound was a complete range or there was no previous bound"); } yield return(BigIntRange.CreateStartEnd(prevBound.Value, bound.Bound)); prevBound = null; } } }
public IEnumerable <BigInteger> EnumerateIncludedValues(bool reverse = false) { if (_sortedSet.Count == 0) { return(Enumerable.Empty <BigInteger>()); } else { return(EnumerateIncludedValues(BigIntRange.CreateStartEnd(this.Min.Value, this.Max.Value), reverse)); } }
public void RemoveRange(BigIntRange range) { SortedSet <BigIntRangeBound> nearbyBounds = GetOverlappingOrAdjacentBounds(range.Start, range.End); if (nearbyBounds.Count == 0) { //There's no bounds nearby, but there might still be some larger range //that includes the range to be removed. To check for this, check if //some value in the new range is already included in the RangeSet. if (this.Includes(range.Start)) { AddBound(range.Start - 1, Direction.Down); AddBound(range.End + 1, Direction.Up); } } else { var minNearby = nearbyBounds.Min; var maxNearby = nearbyBounds.Max; RemoveSubset(nearbyBounds); if (minNearby.Direction == Direction.Down) { //If lowest existing pointed down (ie. joins onto a lower range), //then add a new bound outside the removed range, pointing down AddBound(range.Start - 1, Direction.Down); } else if (minNearby.Bound == range.Start - 1) { //If the lowest existing bound is exactly one below the removed range (and doesn't point down), //then removing the range cuts its range down to a single point, so add that point AddBound(range.Start - 1, Direction.Nowhere); } //Vice versa for maximum if (maxNearby.Direction == Direction.Up) { AddBound(range.End + 1, Direction.Up); } else if (maxNearby.Bound == range.End + 1) { AddBound(range.End + 1, Direction.Nowhere); } } }
public IEnumerable <BigInteger> EnumerateExcludedValues(BigIntRange searchRange, bool reverse = false) { if (reverse) { //If reverse is true, reverse the order of the provided bounds. However, they are expected to be in //ascending order, so to make this true, multiply them by negative 1 (and reverse their directions, //as well as taking the negative of the search range's limits). Then, take the negative of the results, //to get the correct output, still in reverse order. return(RangeSet.EnumerateExcludedValues( sortedBounds: _sortedSet.Reverse().Select(x => x.GetNegative()), searchRange: searchRange.GetNegative() ).Select(x => - x)); } else { return(RangeSet.EnumerateExcludedValues( sortedBounds: _sortedSet, searchRange: searchRange )); } }
public bool TryGetSurroundingIncludedRange(BigInteger x, out BigIntRange range) { bool rangeIsIncluded; if (TryGetSurroundingRange(x, out range, out rangeIsIncluded)) { if (rangeIsIncluded) { return(true); } else { range = default(BigIntRange); return(false); } } else { range = default(BigIntRange); return(false); } }
public bool TryGetSurroundingGap(BigInteger x, out BigIntRange gap) { bool rangeIsIncluded; if (TryGetSurroundingRange(x, out gap, out rangeIsIncluded)) { if (rangeIsIncluded) { gap = default(BigIntRange); return(false); } else { return(true); } } else { gap = default(BigIntRange); return(false); } }
public void AddRange(BigIntRange range) { // Console.WriteLine("51: " + range); SortedSet <BigIntRangeBound> nearbyBounds = GetOverlappingOrAdjacentBounds(range.Start, range.End); if (nearbyBounds.Count == 0) { //No existing ranges are adjacent or *partially* overlapping, however there could //be an existing range that entirely includes the new range. To check for that, //check if some value in the new range is already included in the RangeSet. if (this.Includes(range.Start)) { //Don't need to do anything - the new range is already included. } else { //Need to add the range, and there's no bounds nearby to affect doing this, so its easy if (range.Start == range.End) { AddBound(range.Start, Direction.Nowhere); } else { AddBound(range.Start, Direction.Up); AddBound(range.End, Direction.Down); } } } else { var minNearby = nearbyBounds.Min; var maxNearby = nearbyBounds.Max; RemoveSubset(nearbyBounds); //All contents & ends are unneeded (both ends are to be either deleted or modified/re-added) bool resultingRangeIsPoint = ( //If the new min and max are different, the resulting range will include at least 2 points range.Start == range.End //If there's more than one existing bound, they have to point either be at different points, //or point different ways, so the resulting range won't be a single point && nearbyBounds.Count == 1 //If the new point and the existing bound are different, the resulting range will include at least 2 points && range.Start == minNearby.Bound //If the existing bound points up or down, the resulting range will be more than a single point && minNearby.Direction == Direction.Nowhere ); if (resultingRangeIsPoint) { AddBound(range.Start, Direction.Nowhere); //minimum == maximum == minInExpandedRange == maxInExpandedRange } else { //If the minimum existing bound doesn't point down (ie. join onto a lower range), provide a new lower bound if (minNearby.Direction != Direction.Down) { AddBound(BigInteger.Min(minNearby.Bound, range.Start), Direction.Up); } //If the maximum existing bound doesn't point up (ie. join onto a higher range), provide a new upper bound if (maxNearby.Direction != Direction.Up) { AddBound(BigInteger.Max(maxNearby.Bound, range.End), Direction.Down); } } } }
public bool TryGetSurroundingRange(BigInteger x, out BigIntRange range, out bool rangeIsIncluded) { BigIntRangeBound below; BigIntRangeBound above; if (TryGetSurroundingBounds(x, out below, out above)) { switch (below.Direction) { case Direction.Nowhere: range = BigIntRange.Single(below.Bound); //below == above rangeIsIncluded = true; return(true); case Direction.Down: switch (above.Direction) { case Direction.Down: throw new InvalidOperationException( "Underlying sorted set of range bounds is corrupt - the bound below or equal to " + nameof(x) + "=" + x + " " + "(at value " + below.Bound + ") represents the end of a range, but the bound above or equal " + "to " + nameof(x) + "=" + x + " (at value " + above.Bound + ") also represents the end of a range, meaning " + "this second range would have no starting value." ); case Direction.Nowhere: //Same behaviour as for Direction.Up case Direction.Up: if (BigInteger.Abs(below.Bound - above.Bound) >= 2) //If there is a gap between the bounds { range = BigIntRange.CreateStartEnd(below.Bound + 1, above.Bound - 1); rangeIsIncluded = false; return(true); } else { range = default(BigIntRange); rangeIsIncluded = default(bool); return(false); } default: break; } break; case Direction.Up: switch (above.Direction) { case Direction.Nowhere: throw new InvalidOperationException( "Underlying sorted set of range bounds is corrupt - the bound below or equal to " + nameof(x) + "=" + x + " " + "(at value " + below.Bound + ") represents the start of a range, so and end to this range is expected next, " + "but the bound above or equal to " + nameof(x) + "=" + x + " (at value " + above.Bound + ") represents a range " + "containing only single value." ); case Direction.Up: throw new InvalidOperationException( "Underlying sorted set of range bounds is corrupt - the bound below or equal to " + nameof(x) + "=" + x + " " + "(at value " + below.Bound + ") represents the end of a range, so and end to this range is expected next, " + "but the bound above or equal to " + nameof(x) + "=" + x + " (at value " + above.Bound + ") represents " + "the start of another range." ); case Direction.Down: range = BigIntRange.CreateStartEnd(below.Bound, above.Bound); rangeIsIncluded = true; return(true); default: break; } break; default: break; } } range = default(BigIntRange); rangeIsIncluded = default(bool); return(false); }
public bool InclduesInEntirety(BigIntRange range) { BigIntRange foundRange; return(TryGetSurroundingIncludedRange(range.Start, out foundRange) && foundRange.Start <= range.Start && range.End <= foundRange.End); }
public bool OverlapsWith(BigIntRange other) => other.Start <= this.End && other.End >= this.Start;
/// <summary>Gets a range from (-End) to (-Start)</summary> public BigIntRange GetNegative() => BigIntRange.CreateStartEnd(start: -this.End, end: -this.Start);
//Not a clear name & difficult to define (it's not a union - what is it) // public static BigIntRange Combine(BigIntRange a, BigIntRange b) => BigIntRange.CreateStartEnd( // start: BigInteger.Min(a.Start, b.Start), // end: BigInteger.Max(a.End , b.End ) // ); //Instead do: public BigIntRange ExpandToInclude(BigIntRange other) => BigIntRange.CreateStartEnd( start: BigInteger.Min(this.Start, other.Start), end: BigInteger.Max(this.End, other.End) );
public BigIntRange ExpandToInclude(BigInteger x) => BigIntRange.CreateStartEnd( start: BigInteger.Min(this.Start, x), end: BigInteger.Max(this.End, x) );
public BigIntRange Expand(BigInteger downBy, BigInteger upBy) => BigIntRange.CreateStartEnd(this.Start - downBy, this.End + upBy);
public bool IncludesInEntirety(BigIntRange other) => this.Start <= other.Start && other.End <= this.End;
public bool IsAdjacentOrOverlaps(BigIntRange other) => other.Start <= this.End + 1 && other.End >= this.Start - 1;
private static IEnumerable <BigInteger> EnumerateIncludedValues(IEnumerable <BigIntRangeBound> sortedBounds, BigIntRange searchRange) { BigInteger i = searchRange.Start; foreach (var bound in sortedBounds) { while (i <= searchRange.End) { if (bound.Direction == Direction.Up) { //Move i to the start of the range, but only if that means moving forwards, //and then continue to the next bound i = BigInteger.Max(i, bound.Bound); break; } else if (bound.Direction == Direction.Down) { //Keep returning sequential values until i passes the bound (or the end of the search range) if (i > bound.Bound) { break; } yield return(i); i++; } else { if (searchRange.Includes(bound.Bound)) { yield return(bound.Bound); i = bound.Bound + 1; } break; } } } }
private static IEnumerable <BigInteger> EnumerateExcludedValues(IEnumerable <BigIntRangeBound> sortedBounds, BigIntRange searchRange) { // Console.WriteLine("40.0"); var includedValues = EnumerateIncludedValues(sortedBounds, searchRange); BigInteger prev = searchRange.Start - 1; foreach (BigInteger included in includedValues) { // Console.WriteLine("40.1: " + included + ", " + prev); //If there's been a jump of at least 2 (ie 1 number in gap), //loop until all numbers in the gap have been yielded while (prev + 1 < included) { prev++; yield return(prev); } prev = included; } // Console.WriteLine("40.2: searchRange.End: " + searchRange.End + ", prev: " + prev); //Yield all final values (that are in a gap) until the search range is exited while (prev < searchRange.End) { prev++; yield return(prev); } }
public static IEnumerable <BigInteger> IterateNonTrivialZeros(BigInteger maxZ, Action <ExpansionTerm> currentPathStartingPointPrinter = null) { var termOptions = new TermOptionsMatrix(maxZ); // var sortedEliminatedRanges = new List<BigIntRange>(); var eliminatedRanges = new RangeSet(); BigInteger prevStartingPointEval = BigInteger.Zero; //Starts lower than any evaluated starting point foreach (ExpansionTerm pathStartingPoint in EnumerateSortedTermOptions()) { currentPathStartingPointPrinter?.Invoke(pathStartingPoint); // Console.WriteLine("#25 current starting point: " + pathStartingPoint); // //Debugging: // eliminatedRanges.DebugBounds(); // foreach (var range in eliminatedRanges.IncludedRanges) { // Console.WriteLine("#40: " + range.Start + " to " + range.End); // } // Console.WriteLine("#41: " + eliminatedRanges.Count); BigInteger startingPointEval = pathStartingPoint.Evaluate(); if (startingPointEval > maxZ) { //If gone past end of requested range, return all remaining stored values //up to end of requested range, then stop enumerating. var gaps = eliminatedRanges.EnumerateExcludedValues( searchRange: BigIntRange.CreateStartEnd( start: prevStartingPointEval + 1, end: maxZ ) ); foreach (BigInteger gap in gaps) { yield return(gap); } // foreach (var range in eliminatedRanges.IncludedRanges) { // Console.WriteLine("#42: " + range.Start + " to " + range.End); // } // Console.WriteLine("#43: " + eliminatedRanges.Count); yield break; } foreach (BigInteger summedPath in termOptions.EnumerateSummedExpansionPaths(pathStartingPoint, capToMaximum: true)) { // Console.WriteLine("#44: " + summedPath + ", " + expansionPath.ToString(includeSpaces: false)); BigInteger newRangeMax = summedPath; BigInteger newRangeMin = summedPath; // Console.WriteLine("#44.1: " + newRangeMin + ", " + newRangeMax); //Exclude adjacent trivial zeros (multiples of 3) as well if ((newRangeMax + 1) % 3 == 0) { newRangeMax += 1; } if ((newRangeMin - 1) % 3 == 0) { newRangeMin -= 1; } // Console.WriteLine("#44.2: " + newRangeMin + ", " + newRangeMax); // Console.WriteLine("#45: " + eliminatedRanges.Count); eliminatedRanges.AddRange(BigIntRange.CreateStartEnd(newRangeMin, newRangeMax)); // Console.WriteLine("#46: " + eliminatedRanges.Count); } { // Console.WriteLine("#47: " + eliminatedRanges.Count); var gaps = eliminatedRanges.EnumerateExcludedValues( searchRange: BigIntRange.CreateStartEnd( start: prevStartingPointEval + 1, end: startingPointEval ) ); foreach (BigInteger gap in gaps) { yield return(gap); } // Console.WriteLine("#48"); } prevStartingPointEval = startingPointEval; } }
public static bool Equals(BigIntRange a, BigIntRange b) => a.Start == b.Start && a.End == b.End;