github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/sqle/setalgebra/intersection.go (about) 1 // Copyright 2020 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package setalgebra 16 17 import ( 18 "github.com/dolthub/dolt/go/store/hash" 19 "github.com/dolthub/dolt/go/store/types" 20 ) 21 22 // finiteSetIntersection returns the set of points that are in both fs1 and fs2 23 func finiteSetIntersection(fs1, fs2 FiniteSet) (Set, error) { 24 hashToVal := make(map[hash.Hash]types.Value) 25 for h, v := range fs1.HashToVal { 26 if _, ok := fs2.HashToVal[h]; ok { 27 hashToVal[h] = v 28 } 29 } 30 31 if len(hashToVal) == 0 { 32 return EmptySet{}, nil 33 } else { 34 return FiniteSet{HashToVal: hashToVal}, nil 35 } 36 } 37 38 // finiteSetInterval will return the set of points that are in the interval, or an EmptySet instance 39 func finiteSetIntervalIntersection(fs FiniteSet, in Interval) (Set, error) { 40 hashToVal := make(map[hash.Hash]types.Value) 41 for h, v := range fs.HashToVal { 42 inRange, err := in.Contains(v) 43 44 if err != nil { 45 return nil, err 46 } 47 48 if inRange { 49 hashToVal[h] = v 50 } 51 } 52 53 if len(hashToVal) == 0 { 54 return EmptySet{}, nil 55 } else { 56 return FiniteSet{HashToVal: hashToVal}, nil 57 } 58 } 59 60 // finiteSetInterval will return the set of points that are in the composite set, or an EmptySet instance 61 func finiteSetCompositeSetIntersection(fs FiniteSet, composite CompositeSet) (Set, error) { 62 hashToVal := make(map[hash.Hash]types.Value) 63 for h, v := range fs.HashToVal { 64 if _, ok := composite.Set.HashToVal[h]; ok { 65 hashToVal[h] = v 66 } 67 } 68 69 for _, r := range composite.Intervals { 70 for h, v := range fs.HashToVal { 71 inRange, err := r.Contains(v) 72 73 if err != nil { 74 return nil, err 75 } 76 77 if inRange { 78 hashToVal[h] = v 79 } 80 } 81 } 82 83 if len(hashToVal) == 0 { 84 return EmptySet{}, nil 85 } else { 86 return FiniteSet{HashToVal: hashToVal}, nil 87 } 88 } 89 90 // intervalIntersection will return the intersection of two intervals. This will either be the interval where they 91 // overlap, or an EmptySet instance. 92 func intervalIntersection(in1, in2 Interval) (Set, error) { 93 intComparison, err := compareIntervals(in1, in2) 94 95 if err != nil { 96 return nil, err 97 } 98 99 var resIntervToReduce Interval 100 if intComparison == noOverlapLess || intComparison == noOverlapGreater { 101 // No overlap 102 return EmptySet{}, nil 103 } else if intComparison[start1start2] <= 0 { 104 if intComparison[end1end2] >= 0 { 105 // in2 fully contained in in1 106 return in2, nil 107 } else { 108 // in1 starts first and in2 ends last. take the inside points for the intersection 109 resIntervToReduce = Interval{in1.nbf, in2.Start, in1.End} 110 } 111 } else { 112 if intComparison[end1end2] <= 0 { 113 // in1 fully contained in in2 114 return in1, nil 115 } else { 116 // in2 starts first and in1 ends last. take the inside points for the intersection 117 resIntervToReduce = Interval{in1.nbf, in1.Start, in2.End} 118 } 119 } 120 121 return simplifyInterval(resIntervToReduce) 122 } 123 124 // intervalCompositeSetIntersection will intersect the interval with all sets in the composite and return the resulting 125 // set of points and intervals that are in the interval and the CompositeSet 126 func intervalCompositeSetIntersection(in Interval, cs CompositeSet) (Set, error) { 127 hashToVal := make(map[hash.Hash]types.Value) 128 129 // check the existing finite set and eliminate values not in the new interval 130 for h, v := range cs.Set.HashToVal { 131 contained, err := in.Contains(v) 132 133 if err != nil { 134 return nil, err 135 } 136 137 if contained { 138 hashToVal[h] = v 139 } 140 } 141 142 // intersect the new interval with all the existing intervals 143 intervals, err := intersectIntervalWithMultipleIntervals(in, cs.Intervals, hashToVal) 144 if err != nil { 145 return nil, err 146 } 147 148 if len(hashToVal) == 0 && len(intervals) == 1 { 149 // could possibly be universal set 150 return simplifyInterval(intervals[0]) 151 } else if len(hashToVal) > 0 && len(intervals) == 0 { 152 return FiniteSet{hashToVal}, nil 153 } else if len(hashToVal) > 0 && len(intervals) > 0 { 154 return CompositeSet{FiniteSet{hashToVal}, intervals}, nil 155 } else { 156 return EmptySet{}, nil 157 } 158 } 159 160 // intersectIntervalWithMultipleIntervals returns a slice of Interval objects containing all intersections between the 161 // input interval and the slice of multiple intervals. 162 func intersectIntervalWithMultipleIntervals(in Interval, multipleIntervals []Interval, hashToVal map[hash.Hash]types.Value) ([]Interval, error) { 163 intervals := make([]Interval, 0, len(multipleIntervals)) 164 for _, curr := range multipleIntervals { 165 intersection, err := intervalIntersection(in, curr) 166 167 if err != nil { 168 return nil, err 169 } 170 171 switch typedSet := intersection.(type) { 172 case EmptySet: 173 continue 174 case FiniteSet: 175 for h, v := range typedSet.HashToVal { 176 hashToVal[h] = v 177 } 178 case Interval: 179 intervals = append(intervals, typedSet) 180 default: 181 panic("unexpected set type") 182 } 183 } 184 return intervals, nil 185 } 186 187 // compositeIntersection finds the intersection of two composite sets 188 func compositeIntersection(cs1, cs2 CompositeSet) (Set, error) { 189 // intersect cs1.Set with cs2 and cs2.Set with cs1 to get the discreet values in the resulting intersection. 190 temp1, err := finiteSetCompositeSetIntersection(cs1.Set, cs2) 191 192 if err != nil { 193 return nil, err 194 } 195 196 temp2, err := finiteSetCompositeSetIntersection(cs2.Set, cs1) 197 198 if err != nil { 199 return nil, err 200 } 201 202 resSet, err := temp1.Union(temp2) 203 204 if err != nil { 205 return nil, err 206 } 207 208 var hashToVal map[hash.Hash]types.Value 209 switch typedResSet := resSet.(type) { 210 case EmptySet: 211 hashToVal = make(map[hash.Hash]types.Value) 212 case FiniteSet: 213 hashToVal = typedResSet.HashToVal 214 default: 215 panic("unexpected set type") 216 } 217 218 // intersect the intervals 219 var intervals []Interval 220 for _, curr := range cs1.Intervals { 221 newIntervals, err := intersectIntervalWithMultipleIntervals(curr, cs2.Intervals, hashToVal) 222 223 if err != nil { 224 return nil, err 225 } 226 227 intervals = append(intervals, newIntervals...) 228 } 229 230 // combine the intervals and the discreet values into a result 231 if len(hashToVal) == 0 && len(intervals) == 1 { 232 return simplifyInterval(intervals[0]) 233 } else if len(hashToVal) > 0 && len(intervals) == 0 { 234 return FiniteSet{hashToVal}, nil 235 } else if len(hashToVal) > 0 && len(intervals) > 0 { 236 return CompositeSet{FiniteSet{hashToVal}, intervals}, nil 237 } else { 238 return EmptySet{}, nil 239 } 240 }