Added inclusive / exclusive functionality

This commit is contained in:
Daniel Gil 2018-05-29 16:08:17 +02:00
parent 6fdaa341ff
commit 6702d50231
12 changed files with 345 additions and 67 deletions

2
.gitignore vendored
View File

@ -4,4 +4,4 @@
debug.test debug.test
example/debug example/debug
example/out.png example/*.png

View File

@ -6,4 +6,5 @@
20,30 20,30
25,28 25,28
30,32 30,32
0,1
10,12 10,12

View File

@ -21,6 +21,26 @@ const (
MaxX = 40 MaxX = 40
) )
type PlotType int
const (
PlotTypeIntervals PlotType = iota
PlotTypeGaps
PlotTypeOverlapped
PlotTypeMerged
)
var (
openBracket = "["
closeBracket = "]"
openParenthesis = "("
closeParenthesis = ")"
intervalOpening = openBracket
intervalClosing = closeBracket
lowInclusive bool
highInclusive bool
)
func main() { func main() {
filename := "data.txt" filename := "data.txt"
xys, err := readData(filename) xys, err := readData(filename)
@ -47,12 +67,17 @@ func readData(path string) ([]xy, error) {
// read line by line using a scanner (because we don't know if the file will be huge) // read line by line using a scanner (because we don't know if the file will be huge)
s := bufio.NewScanner(f) s := bufio.NewScanner(f)
for s.Scan() { for s.Scan() {
var x, y int var low, high int
_, err := fmt.Sscanf(s.Text(), "%d,%d", &x, &y) _, err := fmt.Sscanf(s.Text(), "%d,%d", &low, &high)
if err != nil { if err != nil {
log.Printf("discarding bad data point %v: %v", s.Text(), err) log.Printf("discarding bad data point %v: %v", s.Text(), err)
continue
} }
xys = append(xys, xy{x, y}) if low > high {
log.Printf("discarding bad data point (low, high)=(%v): low can not be greater than high", s.Text())
continue
}
xys = append(xys, xy{low, high})
} }
if err := s.Err(); err != nil { if err := s.Err(); err != nil {
return nil, fmt.Errorf("could not scan: %v", err) return nil, fmt.Errorf("could not scan: %v", err)
@ -61,7 +86,24 @@ func readData(path string) ([]xy, error) {
} }
func initIntervals(xys []xy) interval.Intervals { func initIntervals(xys []xy) interval.Intervals {
intervals := interval.NewIntervals(MinX, MaxX) intervals := interval.NewIntervals(MinX, MaxX, true, true)
if intervals.IsLowInclusive() {
intervalOpening = "["
lowInclusive = true
} else {
intervalOpening = "("
lowInclusive = false
}
if intervals.IsHighInclusive() {
intervalClosing = "]"
highInclusive = true
} else {
intervalClosing = ")"
highInclusive = false
}
for _, xy := range xys { for _, xy := range xys {
intervals.Add(&interval.Interval{Low: xy.x, High: xy.y}) intervals.Add(&interval.Interval{Low: xy.x, High: xy.y})
} }
@ -93,7 +135,7 @@ func alignPlots(plotItems []*plot.Plot) *vgimg.Canvas {
} }
} }
img := vgimg.New(vg.Points(512), vg.Points(float64(128*rows))) img := vgimg.New(vg.Points(512), vg.Points(float64(200*rows)))
dc := draw.New(img) dc := draw.New(img)
t := draw.Tiles{ t := draw.Tiles{
@ -129,7 +171,7 @@ func createFileFromCanvas(path string, img *vgimg.Canvas) error {
return nil return nil
} }
func createPlot(title string, xys plotter.XYs) (*plot.Plot, error) { func createPlot(title string, xys plotter.XYs, plotType PlotType) (*plot.Plot, error) {
p, err := plot.New() p, err := plot.New()
if err != nil { if err != nil {
return nil, fmt.Errorf("could not create plot: %v", err) return nil, fmt.Errorf("could not create plot: %v", err)
@ -142,7 +184,7 @@ func createPlot(title string, xys plotter.XYs) (*plot.Plot, error) {
// p.X.Label.Text = "values" // p.X.Label.Text = "values"
p.X.Padding = vg.Length(5) p.X.Padding = vg.Length(5)
p.Y.Padding = vg.Length(20) p.Y.Padding = vg.Length(20)
plotIntervals(p, xys) plotIntervals(p, plotType, xys)
return p, nil return p, nil
} }
@ -151,7 +193,7 @@ func plotData(path string, intervals interval.Intervals) error {
// create Intervals plot // create Intervals plot
xysIntervals := convertToPlotterXYs(intervals.Get()) xysIntervals := convertToPlotterXYs(intervals.Get())
p1, err := createPlot("Intervals", xysIntervals) p1, err := createPlot("Intervals", xysIntervals, PlotTypeIntervals)
if err != nil { if err != nil {
return fmt.Errorf("could not create plot: %v", err) return fmt.Errorf("could not create plot: %v", err)
} }
@ -159,7 +201,7 @@ func plotData(path string, intervals interval.Intervals) error {
// create Gaps plot // create Gaps plot
xysGaps := convertToPlotterXYs(intervals.Gaps()) xysGaps := convertToPlotterXYs(intervals.Gaps())
p2, err := createPlot("Gaps", xysGaps) p2, err := createPlot("Gaps", xysGaps, PlotTypeGaps)
if err != nil { if err != nil {
return fmt.Errorf("could not create plot: %v", err) return fmt.Errorf("could not create plot: %v", err)
} }
@ -167,7 +209,7 @@ func plotData(path string, intervals interval.Intervals) error {
// create Overlapped `plot // create Overlapped `plot
xysOverlapped := convertToPlotterXYs(intervals.Overlapped()) xysOverlapped := convertToPlotterXYs(intervals.Overlapped())
p3, err := createPlot("Overlapped", xysOverlapped) p3, err := createPlot("Overlapped", xysOverlapped, PlotTypeOverlapped)
if err != nil { if err != nil {
return fmt.Errorf("could not create plot: %v", err) return fmt.Errorf("could not create plot: %v", err)
} }
@ -175,7 +217,7 @@ func plotData(path string, intervals interval.Intervals) error {
// create Merged plot // create Merged plot
xysMerged := convertToPlotterXYs(intervals.Merge()) xysMerged := convertToPlotterXYs(intervals.Merge())
p4, err := createPlot("Merged", xysMerged) p4, err := createPlot("Merged", xysMerged, PlotTypeMerged)
if err != nil { if err != nil {
return fmt.Errorf("could not create plot: %v", err) return fmt.Errorf("could not create plot: %v", err)
} }
@ -190,16 +232,71 @@ func plotData(path string, intervals interval.Intervals) error {
return nil return nil
} }
func plotIntervals(p *plot.Plot, xys plotter.XYs) error { func plotIntervals(p *plot.Plot, plotType PlotType, xys plotter.XYs) error {
var ps []plot.Plotter var ps []plot.Plotter
colors := getColors() colors := getColors()
numColors := len(colors) numColors := len(colors)
crossShape := draw.CrossGlyph{}
ringShape := draw.RingGlyph{}
legendWithCrossShape := false
legendWithRingShape := false
for i, xy := range xys { for i, xy := range xys {
label := fmt.Sprintf("(%v,%v)", xy.X, xy.Y) pXYLow := struct{ X, Y float64 }{xy.X, float64(i)}
pXYs := plotter.XYs{{xy.X, float64(i)}, {xy.Y, float64(i)}} pXYHigh := struct{ X, Y float64 }{xy.Y, float64(i)}
pXYs := plotter.XYs{pXYLow, pXYHigh}
color := colors[i%numColors] color := colors[i%numColors]
s, err := plotter.NewScatter(pXYs) var s1, s2 *plotter.Scatter
var err error
label := ""
if plotType == PlotTypeIntervals {
label = fmt.Sprintf("%s%v,%v%s", intervalOpening, xy.X, xy.Y, intervalClosing)
s1, err = plotter.NewScatter(plotter.XYs{pXYLow})
if err != nil {
return fmt.Errorf("unable to create new scatter: %v", err)
}
if !lowInclusive {
s1.GlyphStyle.Shape = crossShape
if !legendWithCrossShape {
p.Legend.Add("Exclusive", s1)
legendWithCrossShape = true
}
} else {
s1.GlyphStyle.Shape = ringShape
if !legendWithRingShape {
p.Legend.Add("Inclusive", s1)
legendWithRingShape = true
}
}
s2, err = plotter.NewScatter(plotter.XYs{pXYHigh})
if err != nil {
return fmt.Errorf("unable to create new scatter: %v", err)
}
if !highInclusive {
s2.GlyphStyle.Shape = crossShape
if !legendWithCrossShape {
p.Legend.Add("Exclusive", s2)
legendWithCrossShape = true
}
} else {
s2.GlyphStyle.Shape = ringShape
if !legendWithRingShape {
p.Legend.Add("Inclusive", s2)
legendWithRingShape = true
}
}
} else {
label = fmt.Sprintf("%s%v,%v%s", openBracket, xy.X, xy.Y, closeBracket)
s1, err = plotter.NewScatter(pXYs)
if err != nil {
return fmt.Errorf("unable to create new scatter: %v", err)
}
if !lowInclusive && !highInclusive {
s1.GlyphStyle.Shape = crossShape
}
}
if xy.X != xy.Y { if xy.X != xy.Y {
l, err := plotter.NewLine(pXYs) l, err := plotter.NewLine(pXYs)
@ -211,15 +308,20 @@ func plotIntervals(p *plot.Plot, xys plotter.XYs) error {
ps = append(ps, l) ps = append(ps, l)
p.Legend.Add(label, l) p.Legend.Add(label, l)
} else { } else {
s.Color = color s1.Color = color
p.Legend.Add(label, s) if s2 != nil {
s2.Color = color
}
p.Legend.Add(label, s1)
} }
if err != nil { if err != nil {
return fmt.Errorf("could not create a new scatter: %v", err) return fmt.Errorf("could not create a new scatter: %v", err)
} }
ps = append(ps, s) ps = append(ps, s1)
if s2 != nil {
ps = append(ps, s2)
}
} }
p.Legend.Left = false p.Legend.Left = false
p.Add(ps...) p.Add(ps...)

12
find.go
View File

@ -1,14 +1,20 @@
package interval package interval
func (intvls *intervals) FindIntervalsForValue(value int) []*Interval { func (intvls *intervals) FindIntervalsForValue(value int) []*Interval {
// sort intervals (if necessary)
intvls.Sort() intvls.Sort()
var matches []*Interval var matches []*Interval
for _, intvl := range intvls.Intervals { for _, intvl := range intvls.Intervals {
if intvl.Low > value { // convert if necessary exclusive low/high values into inclusive ones
// due to the intervals are sorted, we can confirm that we will not find more matches low, high := intvls.getInclusives(intvl.Low, intvl.High)
// check if we have to stop searching
if low > value {
// due to the intervals are sorted byLow, we can confirm that we will not find more matches
break break
} }
if inBetweenInclusive(value, intvl.Low, intvl.High) { if inBetweenInclusive(value, low, high) {
matches = append(matches, intvl) matches = append(matches, intvl)
} }
} }

32
gaps.go
View File

@ -16,19 +16,33 @@ func (intvls *intervals) Gaps() []*Interval {
} }
func (intvls *intervals) calculateGaps() []*Interval { func (intvls *intervals) calculateGaps() []*Interval {
list := []*Interval{}
if len(intvls.Intervals) == 0 {
return list
}
// sort intervals (if necessary)
intvls.Sort() intvls.Sort()
gaps := []*Interval{}
lastMaxHigh := intvls.MinLow gapThreshold := intvls.MinLow
for _, intvl := range intvls.Intervals { for _, intvl := range intvls.Intervals {
if intvl.Low > lastMaxHigh { // convert if necessary exclusive low/high values into inclusive ones
gaps = append(gaps, &Interval{Low: lastMaxHigh, High: intvl.Low - 1}) low, high := intvls.getInclusives(intvl.Low, intvl.High)
// if the current Low is higher than the last maximal High, means that there is a gap so we add this gap to the list
if low > gapThreshold {
list = append(list, &Interval{Low: gapThreshold, High: low - 1})
} }
if intvl.High >= lastMaxHigh {
lastMaxHigh = intvl.High + 1 // update if necessary the threshold for the next gap
if high >= gapThreshold {
gapThreshold = high + 1
} }
} }
if lastMaxHigh < intvls.MaxHigh {
gaps = append(gaps, &Interval{Low: lastMaxHigh, High: intvls.MaxHigh}) // if intvls.Intervals haven't covered all the range until the end, we need to fill the rest until the end as a gap
if gapThreshold < intvls.MaxHigh {
list = append(list, &Interval{Low: gapThreshold, High: intvls.MaxHigh})
} }
return gaps return list
} }

3
get.go
View File

@ -1,6 +1,9 @@
package interval package interval
func (intvls *intervals) Get() []*Interval { func (intvls *intervals) Get() []*Interval {
// sort intervals (if necessary)
intvls.Sort() intvls.Sort()
// return the intervals sorted
return intvls.Intervals return intvls.Intervals
} }

37
inclusives.go Normal file
View File

@ -0,0 +1,37 @@
package interval
func (intvls *intervals) getInclusives(intervalLow, intervalHigh int) (int, int) {
low := intvls.getInclusiveLow(intervalLow)
high := intvls.getInclusiveHigh(intervalHigh)
if high < low {
high = low
}
if low > high {
low = high
}
return low, high
}
func (intvls *intervals) getInclusiveLow(value int) int {
if intvls.LowInclusive {
return value
}
// here the low is exclusive, we have to take the next value
newLow := value + 1
if newLow > intvls.MaxHigh {
return intvls.MaxHigh
}
return newLow
}
func (intvls *intervals) getInclusiveHigh(value int) int {
if intvls.HighInclusive {
return value
}
// here the high is exclusive, we have to take the previous value
newHigh := value - 1
if newHigh < intvls.MinLow {
return intvls.MinLow
}
return newHigh
}

View File

@ -5,8 +5,10 @@ import (
) )
const ( const (
defaultMinLow = 0 defaultMinLow = 0
defaultMaxHigh = math.MaxInt64 defaultMaxHigh = math.MaxInt64
defaultLowInclusive = true
defaultHighInclusive = true
) )
// Intervals is an interface to handle Interval structures discovering the existence of gaps or overlays // Intervals is an interface to handle Interval structures discovering the existence of gaps or overlays
@ -39,6 +41,12 @@ type Intervals interface {
// Report first sorts (if necessary) and then creates a report of the interval sequence // Report first sorts (if necessary) and then creates a report of the interval sequence
Report() string Report() string
// IsLowInclusive indicates if the Low part of the interval is included, e. g. (3,5) --> the 3 is included as part of the interval
IsLowInclusive() bool
// IsHighInclusive indicates if the High part of the interval is included, e. g. (3,5) --> the 5 is included as part of the interval
IsHighInclusive() bool
} }
// intervals implements Intervals interface // intervals implements Intervals interface
@ -50,19 +58,31 @@ type intervals struct {
MinLow int MinLow int
MaxHigh int MaxHigh int
Sorted bool Sorted bool
LowInclusive bool
HighInclusive bool
} }
// NewIntervalsDefault is a constructor that returns an instance of the Intervals interface with default values // NewIntervalsDefault is a constructor that returns an instance of the Intervals interface with default values
func NewIntervalsDefault() Intervals { func NewIntervalsDefault() Intervals {
return NewIntervals(defaultMinLow, defaultMaxHigh) return NewIntervals(defaultMinLow, defaultMaxHigh, defaultLowInclusive, defaultHighInclusive)
} }
// NewIntervals is a constructor that returns an instance of the Intervals interface // NewIntervals is a constructor that returns an instance of the Intervals interface
func NewIntervals(minLow int, maxHigh int) Intervals { func NewIntervals(minLow int, maxHigh int, lowInclusive bool, highInclusive bool) Intervals {
return &intervals{ return &intervals{
MinLow: minLow, MinLow: minLow,
MaxHigh: maxHigh, MaxHigh: maxHigh,
Intervals: []*Interval{}, Intervals: []*Interval{},
Sorted: false, Sorted: false,
LowInclusive: lowInclusive,
HighInclusive: highInclusive,
} }
} }
func (intvls *intervals) IsLowInclusive() bool {
return intvls.LowInclusive
}
func (intvls *intervals) IsHighInclusive() bool {
return intvls.HighInclusive
}

View File

@ -8,33 +8,66 @@ func (intvls *intervals) Merge() []*Interval {
} }
func (intvls *intervals) calculateMerged() []*Interval { func (intvls *intervals) calculateMerged() []*Interval {
intvls.Sort()
list := []*Interval{} list := []*Interval{}
if len(intvls.Intervals) == 0 { if len(intvls.Intervals) == 0 {
return list return list
} }
var lastLow int // sort intervals (if necessary)
var lastHigh int intvls.Sort()
var currentMinLow int
var currentMaxHigh int
for i, intvl := range intvls.Intervals { for i, intvl := range intvls.Intervals {
// convert if necessary exclusive low/high values into inclusive ones
low, high := intvls.getInclusives(intvl.Low, intvl.High)
// in the first iteration it's for sure that don't exists merge, we just initialize variables
if i == 0 { if i == 0 {
lastLow = intvl.Low currentMinLow = low
lastHigh = intvl.High currentMaxHigh = high
continue continue
} }
if isLowInBetween(intvl.Low, intvl.High, lastLow, lastHigh) || isHighInBetween(intvl.Low, intvl.High, lastLow, lastHigh) {
if intvl.Low < lastLow { // in case the current interval is overlapped or consecutive to the previous one, we need to update variables
lastLow = intvl.Low // and keep going and process the next interval
if areSegmentsConsecutivesOrOverlapped(low, high, currentMinLow, currentMaxHigh) {
// update control variables if necessary
if low < currentMinLow {
currentMinLow = low
} }
if intvl.High > lastHigh { if high > currentMaxHigh {
lastHigh = intvl.High currentMaxHigh = high
} }
continue continue
} }
list = append(list, &Interval{Low: lastLow, High: lastHigh})
lastLow = intvl.Low // here the segments are not consecutive or overlapped so we close this merged segment (add to the list)
lastHigh = intvl.High list = append(list, &Interval{Low: currentMinLow, High: currentMaxHigh})
// update control variables
currentMinLow = low
currentMaxHigh = high
} }
list = append(list, &Interval{Low: lastLow, High: lastHigh}) // the last segment is pending to be added to the list
list = append(list, &Interval{Low: currentMinLow, High: currentMaxHigh})
return list return list
} }
func areSegmentsOverlapped(low, high, lastLow, lastHigh int) bool {
if isLowInBetweenInclusive(low, high, lastLow, lastHigh) {
return true
}
if isHighInBetweenInclusive(low, high, lastLow, lastHigh) {
return true
}
return false
}
func areSegmentsConsecutives(low, high, lastLow, lastHigh int) bool {
return ((lastHigh + 1) == low) || ((high + 1) == lastLow)
}
func areSegmentsConsecutivesOrOverlapped(low, high, lastLow, lastHigh int) bool {
return areSegmentsOverlapped(low, high, lastLow, lastHigh) || areSegmentsConsecutives(low, high, lastLow, lastHigh)
}

View File

@ -18,25 +18,38 @@ func (intvls *intervals) Overlapped() []*Interval {
} }
func (intvls *intervals) calculateOverlapped() []*Interval { func (intvls *intervals) calculateOverlapped() []*Interval {
intvls.Sort()
list := []*Interval{} list := []*Interval{}
if len(intvls.Intervals) == 0 {
return list
}
// sort intervals (if necessary)
intvls.Sort()
lastMinLow := math.MaxInt64 lastMinLow := math.MaxInt64
lastMaxHigh := math.MinInt64 lastMaxHigh := math.MinInt64
for i, intvl := range intvls.Intervals { for i, intvl := range intvls.Intervals {
// convert if necessary exclusive low/high values into inclusive ones
low, high := intvls.getInclusives(intvl.Low, intvl.High)
// for the first iteration make no sense those operations
if i > 0 { if i > 0 {
lowInBetween := isLowInBetween(lastMinLow, lastMaxHigh, intvl.Low, intvl.High) // check if the front or back side of the current segment overlaps with the previous one
highInBetween := isHighInBetween(lastMinLow, lastMaxHigh, intvl.Low, intvl.High) lowInBetween := isLowInBetweenInclusive(lastMinLow, lastMaxHigh, low, high)
highInBetween := isHighInBetweenInclusive(lastMinLow, lastMaxHigh, low, high)
if lowInBetween || highInBetween { if lowInBetween || highInBetween {
greaterLow := max(intvl.Low, lastMinLow) // extract which part is overlapped, create a new interval and add it to the list
lowerHigh := min(intvl.High, lastMaxHigh) biggestLow := max(low, lastMinLow)
list = append(list, &Interval{Low: greaterLow, High: lowerHigh}) smallestHigh := min(high, lastMaxHigh)
list = append(list, &Interval{Low: biggestLow, High: smallestHigh})
} }
} }
if intvl.Low < lastMinLow { // update control variables (if necessary)
lastMinLow = intvl.Low if low < lastMinLow {
lastMinLow = low
} }
if intvl.High > lastMaxHigh { if high > lastMaxHigh {
lastMaxHigh = intvl.High lastMaxHigh = high
} }
} }
return list return list
@ -44,7 +57,7 @@ func (intvls *intervals) calculateOverlapped() []*Interval {
func (intvls *intervals) valueIsOverlapping(value int, overlapped []*Interval) bool { func (intvls *intervals) valueIsOverlapping(value int, overlapped []*Interval) bool {
for _, ovrlp := range overlapped { for _, ovrlp := range overlapped {
if inBetweenInclusive(value, ovrlp.Low, ovrlp.High) { if inBetween(value, ovrlp.Low, ovrlp.High, intvls.LowInclusive, intvls.HighInclusive) {
return true return true
} }
} }

View File

@ -3,6 +3,7 @@ package interval
import "sort" import "sort"
func (intvls *intervals) Sort() { func (intvls *intervals) Sort() {
// sort the intervals slice just if necessary
if !intvls.Sorted { if !intvls.Sorted {
sort.Sort(ByLow(intvls.Intervals)) sort.Sort(ByLow(intvls.Intervals))
} }

View File

@ -13,6 +13,23 @@ func max(a, b int) int {
return b return b
} }
func inBetween(i, min, max int, lowInclusive, highInclusive bool) bool {
if lowInclusive && highInclusive {
return inBetweenInclusive(i, min, max)
}
if !lowInclusive && !highInclusive {
return inBetweenExclusive(i, min, max)
}
if lowInclusive && !highInclusive {
return inBetweenLowInclusive(i, min, max)
}
if !lowInclusive && highInclusive {
return inBetweenHighInclusive(i, min, max)
}
return false
}
// both inclusive
func inBetweenInclusive(i, min, max int) bool { func inBetweenInclusive(i, min, max int) bool {
if (i >= min) && (i <= max) { if (i >= min) && (i <= max) {
return true return true
@ -20,6 +37,23 @@ func inBetweenInclusive(i, min, max int) bool {
return false return false
} }
// only low is inclusive
func inBetweenLowInclusive(i, min, max int) bool {
if (i >= min) && (i < max) {
return true
}
return false
}
// only high is inclusive
func inBetweenHighInclusive(i, min, max int) bool {
if (i > min) && (i <= max) {
return true
}
return false
}
// both exclusive
func inBetweenExclusive(i, min, max int) bool { func inBetweenExclusive(i, min, max int) bool {
if (i > min) && (i < max) { if (i > min) && (i < max) {
return true return true
@ -27,14 +61,28 @@ func inBetweenExclusive(i, min, max int) bool {
return false return false
} }
func isLowInBetween(low1, high1, low2, high2 int) bool { func isLowInBetween(low1, high1, low2, high2 int, lowInclusive, highInclusive bool) bool {
if inBetween(low1, low2, high2, lowInclusive, highInclusive) || inBetween(low2, low1, high1, lowInclusive, highInclusive) {
return true
}
return false
}
func isLowInBetweenInclusive(low1, high1, low2, high2 int) bool {
if inBetweenInclusive(low1, low2, high2) || inBetweenInclusive(low2, low1, high1) { if inBetweenInclusive(low1, low2, high2) || inBetweenInclusive(low2, low1, high1) {
return true return true
} }
return false return false
} }
func isHighInBetween(low1, high1, low2, high2 int) bool { func isHighInBetween(low1, high1, low2, high2 int, lowInclusive, highInclusive bool) bool {
if inBetween(high1, low2, high2, lowInclusive, highInclusive) || inBetween(high2, low1, high1, lowInclusive, highInclusive) {
return true
}
return false
}
func isHighInBetweenInclusive(low1, high1, low2, high2 int) bool {
if inBetweenInclusive(high1, low2, high2) || inBetweenInclusive(high2, low1, high1) { if inBetweenInclusive(high1, low2, high2) || inBetweenInclusive(high2, low1, high1) {
return true return true
} }