1/* 2 * Copyright (c) 2024-2025 Huawei Device Co., Ltd. 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 16import { SparseBitVector } from '../../utils/SparseBitVector'; 17 18type Idx = number; 19export interface IPtsCollection<T extends Idx> { 20 contains(elem: T): boolean; 21 insert(elem: T): boolean; 22 remove(elem: T): boolean; 23 clone(): this; 24 union(other: this): boolean; 25 subtract(other: this): boolean; 26 clear(): void; 27 count(): number; 28 isEmpty(): boolean; 29 superset(other: this): boolean; 30 intersect(other: this): boolean; 31 getProtoPtsSet(): any; 32 [Symbol.iterator](): IterableIterator<T>; 33} 34 35/* 36 * Return PtsSet or PtsBV 's constructor by input type 37 */ 38export function createPtsCollectionCtor<T extends Idx>(type: PtsCollectionType): new () => IPtsCollection<T> { 39 if (type === PtsCollectionType.Set) { 40 return PtsSet<T>; 41 } else if (type === PtsCollectionType.BitVector) { 42 return PtsBV<T>; 43 } 44 throw new Error(`Unsupported pts collection type: ${type}`); 45} 46 47/* 48 * A simple set to store pts data 49 */ 50export class PtsSet<T extends Idx> implements IPtsCollection<T> { 51 pts: Set<T>; 52 53 constructor() { 54 this.pts = new Set(); 55 } 56 57 contains(elem: T): boolean { 58 return this.pts.has(elem); 59 } 60 61 insert(elem: T): boolean { 62 if (this.pts.has(elem)) { 63 return false; 64 } 65 this.pts.add(elem); 66 return true; 67 } 68 69 remove(elem: T): boolean { 70 if (!this.pts.has(elem)) { 71 return false; 72 } 73 this.pts.delete(elem); 74 return true; 75 } 76 77 clone(): this { 78 let clonedSet = new PtsSet<T>(); 79 clonedSet.pts = new Set<T>(this.pts); 80 // TODO: need validate 81 return clonedSet as this; 82 } 83 84 union(other: this): boolean { 85 let changed = false; 86 for (const elem of other.pts) { 87 changed = this.insert(elem) || changed; 88 } 89 return changed; 90 } 91 92 subtract(other: this): boolean { 93 let changed = false; 94 for (const elem of other.pts) { 95 changed = this.remove(elem) || changed; 96 } 97 98 return changed; 99 } 100 101 clear(): void { 102 this.pts.clear(); 103 } 104 105 count(): number { 106 return this.pts.size; 107 } 108 109 isEmpty(): boolean { 110 return this.pts.size === 0; 111 } 112 113 // If current collection is a super set of other 114 superset(other: this): boolean { 115 for (const elem of other.pts) { 116 if (!this.pts.has(elem)) { 117 return false; 118 } 119 } 120 return true; 121 } 122 123 // If current collection is intersect with other 124 intersect(other: this): boolean { 125 for (const elem of other.pts) { 126 if (this.pts.has(elem)) { 127 return true; 128 } 129 } 130 return false; 131 } 132 133 getProtoPtsSet(): Set<T> { 134 return this.pts; 135 } 136 137 [Symbol.iterator](): IterableIterator<T> { 138 return this.pts[Symbol.iterator](); 139 } 140} 141 142export class PtsBV<T extends Idx> implements IPtsCollection<T> { 143 pts: SparseBitVector; 144 145 constructor() { 146 this.pts = new SparseBitVector(); 147 } 148 149 contains(elem: T): boolean { 150 return this.pts.test(elem); 151 } 152 153 insert(elem: T): boolean { 154 this.pts.set(elem); 155 return true; 156 } 157 158 remove(elem: T): boolean { 159 this.pts.reset(elem); 160 return true; 161 } 162 163 clone(): this { 164 let cloned = new PtsBV<T>(); 165 cloned.pts = this.pts.clone(); 166 return cloned as this; 167 } 168 169 union(other: this): boolean { 170 return this.pts.unionWith(other.pts); 171 } 172 173 subtract(other: this): boolean { 174 return this.pts.subtractWith(other.pts); 175 } 176 177 clear(): void { 178 this.pts.clear(); 179 } 180 181 count(): number { 182 return this.pts.count(); 183 } 184 185 isEmpty(): boolean { 186 return this.pts.isEmpty(); 187 } 188 189 // If current collection is a super set of other 190 superset(other: this): boolean { 191 for (const elem of other.pts) { 192 if (!this.pts.test(elem)) { 193 return false; 194 } 195 } 196 return true; 197 } 198 199 // If current collection is intersect with other 200 intersect(other: this): boolean { 201 for (const elem of other.pts) { 202 if (this.pts.test(elem)) { 203 return true; 204 } 205 } 206 return false; 207 } 208 209 getProtoPtsSet(): SparseBitVector { 210 return this.pts; 211 } 212 213 [Symbol.iterator](): IterableIterator<T> { 214 return this.pts[Symbol.iterator]() as IterableIterator<T>; 215 } 216} 217 218export enum PtsCollectionType { 219 Set, 220 BitVector, 221} 222export class DiffPTData<K, D extends Idx, DS extends IPtsCollection<D>> { 223 private diffPtsMap: Map<K, DS>; 224 private propaPtsMap: Map<K, DS>; 225 226 constructor(private DSCreator: new () => DS) { 227 this.diffPtsMap = new Map(); 228 this.propaPtsMap = new Map(); 229 } 230 231 clear(): void { 232 this.diffPtsMap.clear(); 233 this.propaPtsMap.clear(); 234 } 235 236 addPts(v: K, elem: D): boolean { 237 let propa = this.propaPtsMap.get(v); 238 if (propa && propa.contains(elem)) { 239 return false; 240 } 241 let diff = this.diffPtsMap.get(v) || new this.DSCreator(); 242 this.diffPtsMap.set(v, diff); 243 return diff.insert(elem); 244 } 245 246 resetElem(v: K): boolean { 247 let propa = this.propaPtsMap.get(v); 248 if (propa) { 249 this.diffPtsMap.set(v, propa.clone()); 250 return true; 251 } 252 return false; 253 } 254 255 unionDiffPts(dstv: K, srcv: K): boolean { 256 if (dstv === srcv) { 257 return false; 258 } 259 let changed = false; 260 let diff = this.diffPtsMap.get(srcv); 261 if (diff) { 262 let srcDs = diff.clone(); 263 changed = this.unionPtsTo(dstv, srcDs); 264 } 265 return changed; 266 } 267 268 unionPts(dstv: K, srcv: K): boolean { 269 if (dstv === srcv) { 270 return false; 271 } 272 let changed = false; 273 let diff = this.diffPtsMap.get(srcv); 274 if (diff) { 275 let srcDs = diff.clone(); 276 changed = this.unionPtsTo(dstv, srcDs); 277 } 278 let propa = this.propaPtsMap.get(srcv); 279 if (propa) { 280 let srcDs = propa.clone(); 281 changed = this.unionPtsTo(dstv, srcDs) || changed; 282 } 283 return changed; 284 } 285 286 unionPtsTo(dstv: K, srcDs: DS): boolean { 287 let diff = this.diffPtsMap.get(dstv) || new this.DSCreator(); 288 let propa = this.propaPtsMap.get(dstv) || new this.DSCreator(); 289 let newSet = srcDs.clone(); 290 newSet.subtract(propa); 291 let changed = diff.union(newSet); 292 this.diffPtsMap.set(dstv, diff); 293 return changed; 294 } 295 296 removePtsElem(v: K, elem: D): boolean { 297 let removedFromDiff = this.diffPtsMap.get(v)?.remove(elem) ?? false; 298 let removedFromPropa = this.propaPtsMap.get(v)?.remove(elem) ?? false; 299 return removedFromDiff || removedFromPropa; 300 } 301 302 getDiffPts(v: K): DS | undefined { 303 return this.diffPtsMap.get(v); 304 } 305 306 getMutDiffPts(v: K): DS | undefined { 307 if (!this.diffPtsMap.has(v)) { 308 this.diffPtsMap.set(v, new this.DSCreator()); 309 } 310 return this.diffPtsMap.get(v); 311 } 312 313 getPropaPts(v: K): DS | undefined { 314 return this.propaPtsMap.get(v); 315 } 316 317 getAllPropaPts(): Map<K, DS> { 318 return this.propaPtsMap; 319 } 320 321 getPropaPtsMut(v: K): DS { 322 if (!this.propaPtsMap.has(v)) { 323 this.propaPtsMap.set(v, new this.DSCreator()); 324 } 325 return this.propaPtsMap.get(v)!; 326 } 327 328 flush(v: K): void { 329 if (!this.diffPtsMap.has(v)) { 330 return; 331 } 332 let diff = this.diffPtsMap.get(v)!; 333 let propa = this.getPropaPtsMut(v); 334 // do not clear origin propa, only copy the pt and add it to diff 335 propa.union(diff); 336 diff.clear(); 337 } 338 339 clearPts(v: K): void { 340 let diff = this.diffPtsMap.get(v); 341 if (diff) { 342 diff.clear(); 343 } 344 let propa = this.propaPtsMap.get(v); 345 if (propa) { 346 propa.clear(); 347 } 348 } 349 350 clearDiffPts(v: K): void { 351 let diff = this.diffPtsMap.get(v); 352 if (diff) { 353 diff.clear(); 354 } 355 } 356 357 clearPropaPts(v: K): void { 358 let propa = this.propaPtsMap.get(v); 359 if (propa) { 360 propa.clear(); 361 } 362 } 363 364 calculateDiff(src: K, dst: K): DS { 365 let srcDiff = this.diffPtsMap.get(src)!; 366 let dstPropa = this.propaPtsMap.get(dst); 367 if (!dstPropa) { 368 return srcDiff.clone(); 369 } 370 371 let result = srcDiff.clone(); 372 373 result.subtract(dstPropa); 374 return result; 375 } 376} 377