Skip to content

Commit

Permalink
Merge 3b6d86a into 6a7c149
Browse files Browse the repository at this point in the history
  • Loading branch information
EdgarACarneiro committed Mar 7, 2021
2 parents 6a7c149 + 3b6d86a commit ca95661
Show file tree
Hide file tree
Showing 10 changed files with 6,032 additions and 173 deletions.
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,53 @@ For an in-depth analysis of both the parameter tuning (such as the tree's order

To suit the _I2BplusTree_ to your needs, implement a class that __extends the [FlatInterval](https://github.com/EdgarACarneiro/IBplusTree/blob/master/src/FlatInterval.ts)__ class, defining the information that will be stored on leaves there. One might also want to override the `equals` method, thus allowing the incorporation of the extra information stored in the Intervals in comparisons.

Example:
```TypeScript
import { IBplusTree, FlatInterval } from 'I2BplusTree';

// Create a class that inherits from the FlatInterval
class MyInterval extends FlatInterval {

// This is just an example property
// Like this there could be many more
private myProperty: any;

constructor(val1: number, val2: number, myPropertyValue: any) {
super(val1, val2);
this.myProperty = myPropertyValue;
}

// This is just an example method
public exampleMethod(): void {
// Do stuff
}

// Overriding equals method to take into account the new property
equals(int: MyInterval): boolean {
return this.upperBound == int.getUpperBound() &&
this.lowerBound == int.getLowerBound() &&
this.myProperty == int.getProperty();
}
}

// Now we create our I2BplusTree object and insert a `MyInterval` object
const threshold = 30;
const alpha = 0.2;
const tree: IBplusTree<MyInterval> = new IBplusTree<MyInterval>(threshold, alpha);
// Introduce an object
tree.insert(new MyInterval(0, 2, "example-property"));

/**
And do many other operations such as:
- Delete an interval from the tree
- Delete all intervals contained in a range
- Verify if a interval exists in the tree
- Search all intervals with equal bounds to the ones provided
- Find the first interval that intersects the given bounds
- Find all intervals intersecting the given range
- Find all intervals contained in the given range
*/
```

# Acknowledgements

Expand Down
105 changes: 50 additions & 55 deletions benchmarks/src/Deletion.benchmark.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { IBplusTree, Interval, FlatInterval } from '../../src';
import { addBenchmarkLogsAndRun } from "./Helpers";
import { getOrders, getAlphas } from './Settings';
import { Suite } from "benchmark";
import { Benchmark, Test } from 'kruonis';


let iterator: number = 0;
let tree: IBplusTree<FlatInterval>;
let delInts: Array<Interval<FlatInterval>>;


const createTree = (intervals: Array<Interval<FlatInterval>>, order: number, alpha: number):
[IBplusTree<FlatInterval>, Array<Interval<FlatInterval>>] => {
const newTree = new IBplusTree(order, alpha);
Expand All @@ -25,71 +22,69 @@ const createTree = (intervals: Array<Interval<FlatInterval>>, order: number, alp
return [newTree, newDelInts];
};

/**
* Create the test suite for a generic test
*
* @param dataset The dataset used in the suite
* @returns the created suite
*/
const createSuite = (dataset: Array<Interval<FlatInterval>>, alpha: number): Suite => {
return (new Suite).on('start cycle', function (event) {
if (getOrders()[iterator]) {
[tree, delInts] = createTree(dataset, getOrders()[iterator], alpha);
iterator += 1;
}
});
}

const deletionTest = (dataset: Array<Interval<FlatInterval>>, alpha: number) => {
iterator = 0;
let suite = createSuite(dataset, alpha);

for (const order of getOrders())
suite = suite.add(`D_o${order}_a${alpha}#test`, () => {
for (let int of delInts)
tree.delete(int);

for (let int of delInts)
tree.insert(int);
});
let benchmark = new Benchmark();

for (const order of getOrders()) {
benchmark.add(
new Test(`D_o${order}_a${alpha}#test`, () => {
for (let int of delInts)
tree.delete(int);
}).on('onBegin', () => {
[tree, delInts] = createTree(dataset, order, alpha);
}).on('onCycleEnd', () => {
for (let int of delInts)
tree.insert(int)
})
);
}

addBenchmarkLogsAndRun(suite);
addBenchmarkLogsAndRun(benchmark);
}

const rangeDeletionTest = (dataset: Array<Interval<FlatInterval>>, alpha: number) => {
iterator = 0;
let suite = createSuite(dataset, alpha);
let rangedIntervals = delInts.map(int => tree.containedRangeSearch(int.getLowerBound(), int.getUpperBound()));

for (const order of getOrders())
suite = suite.add(`RD_o${order}_a${alpha}#test`, () => {
for (let int of delInts)
tree.rangeDelete(int.getLowerBound(), int.getUpperBound());

for (let intervals of rangedIntervals)
for (let it = intervals.values(), int = null; int = it.next().value;)
tree.insert(int);
});
let benchmark = new Benchmark();
let rangedIntervals;

for (const order of getOrders()) {
benchmark.add(
new Test(`RD_o${order}_a${alpha}#test`, () => {
for (let int of delInts)
tree.rangeDelete(int.getLowerBound(), int.getUpperBound());
}).on('onBegin', () => {
[tree, delInts] = createTree(dataset, order, alpha);
rangedIntervals = delInts.map(int => tree.containedRangeSearch(int.getLowerBound(), int.getUpperBound()));
}).on('onCycleEnd', () => {
for (let intervals of rangedIntervals)
for (let it = intervals.values(), int = null; int = it.next().value;)
tree.insert(int);
})
);
}

addBenchmarkLogsAndRun(suite);
addBenchmarkLogsAndRun(benchmark);
}

const deleteHalfTree = (dataset: Array<Interval<FlatInterval>>, alpha: number) => {
iterator = 0;
let suite = createSuite(dataset, alpha);
let benchmark = new Benchmark();
const ub = dataset.map(int => int.getUpperBound()).reduce((max, el) => max > el ? max : el, 0);
const lb = dataset.map(int => int.getLowerBound()).reduce((max, el) => max > el ? max : el, 0) / 2;
let rangedIntervals = tree.containedRangeSearch(lb, ub);

for (const order of getOrders())
suite = suite.add(`DH_o${order}_a${alpha}#test`, () => {
tree.rangeDelete(lb, ub);

for (let it = rangedIntervals.values(), int = null; int = it.next().value;)
tree.insert(int);
});
for (const order of getOrders()) {
benchmark.add(
new Test(`DH_o${order}_a${alpha}#test`, () => {
tree.rangeDelete(lb, ub);
}).on('onBegin', () => {
[tree, delInts] = createTree(dataset, order, alpha);
}).on('onCycleEnd', () => {
for (let it = rangedIntervals.values(), int = null; int = it.next().value;)
tree.insert(int);
})
);
}

addBenchmarkLogsAndRun(suite);
addBenchmarkLogsAndRun(benchmark);
}

export const run = (dataset: Array<Interval<FlatInterval>>) => {
Expand Down
34 changes: 14 additions & 20 deletions benchmarks/src/Helpers.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
import { appendFileSync } from "fs";
import { Suite } from "benchmark";
import { getOutputPath } from './Settings'
import { getOutputPath } from './Settings';
import { Benchmark, Test } from 'kruonis';


const secToMilisec: number = 1000;

const prettyStats = (result: Suite) => {
console.log(`${String(result)}:\n` +
` * Mean: ${result.stats.mean * secToMilisec}ms\n` +
` * Standard Deviation: ${result.stats.deviation * secToMilisec}ms\n`);
const prettyStats = (test: Test) => {
console.log(`${test.name} (${test.getStats().count} cycles):\n` +
` * Mean: ${test.getStats().mean}ms\n` +
` * Standard Deviation: ${test.getStats().std}ms\n`);
}

const logToFile = (result: Suite) => {
const logToFile = (test: Test) => {
appendFileSync(getOutputPath(),
`${result.name} ${result.stats.mean * secToMilisec}\n`);
`${test.name} ${test.getStats().mean}\n`);
}

export const addBenchmarkLogsAndRun = (benchmark: Suite) => {
export const addBenchmarkLogsAndRun = (benchmark: Benchmark) => {
// add listeners
benchmark.on('cycle', function (event) {
prettyStats(event.target);
logToFile(event.target);
})
.on('complete', function () {
console.log('Fastest is ' + this.filter('fastest').map('name') + '\n\n');
})
.run({ 'async': false });
benchmark
.on('onTestEnd', (benchmark: Benchmark, result: Test) => {
prettyStats(result);
logToFile(result);
}).run();
}
32 changes: 17 additions & 15 deletions benchmarks/src/Insertion.benchmark.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { IBplusTree, Interval, FlatInterval } from '../../src';
import { addBenchmarkLogsAndRun } from "./Helpers";
import { getOrders, getAlphas } from './Settings';
import { Suite } from "benchmark";


let iterator: number = 0;
import { Benchmark, Test } from 'kruonis';

const createTree = (intervals: Array<Interval<FlatInterval>>, order: number, alpha: number):
[IBplusTree<FlatInterval>, Array<Interval<FlatInterval>>] => {
Expand All @@ -26,18 +23,23 @@ const insertionTest = (dataset: Array<Interval<FlatInterval>>, alpha: number) =>
let tree: IBplusTree<FlatInterval>;
let insInts: Array<Interval<FlatInterval>>;

let suite = (new Suite).on('start cycle', function (event) {
[tree, insInts] = createTree(dataset, getOrders()[iterator], alpha);
iterator += 1;
});

for (const order of getOrders())
suite = suite.add(`I_o${order}_a${alpha}#test`, () => {
for (let int of insInts)
tree.insert(int);
});
let benchmark = new Benchmark();

for (const order of getOrders()) {
benchmark.add(
new Test(`I_o${order}_a${alpha}#test`, () => {
for (let int of insInts)
tree.insert(int);
}).on('onBegin', () => {
[tree, insInts] = createTree(dataset, order, alpha);
}).on('onCycleEnd', () => {
for (let int of insInts)
tree.delete(int);
})
);
}

addBenchmarkLogsAndRun(suite);
addBenchmarkLogsAndRun(benchmark);
};

export const run = (dataset: Array<Interval<FlatInterval>>) => {
Expand Down
76 changes: 34 additions & 42 deletions benchmarks/src/Search.benchmark.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { IBplusTree, Interval, FlatInterval } from '../../src';
import { addBenchmarkLogsAndRun } from "./Helpers";
import { getOrders, getAlphas } from './Settings';
import { Suite } from "benchmark";
import { Benchmark, Test } from "kruonis";


let iterator: number = 0;
let tree: IBplusTree<FlatInterval>;
let searchInts: Array<Interval<FlatInterval>>;

Expand All @@ -22,58 +20,52 @@ const createTree = (intervals: Array<Interval<FlatInterval>>, order: number, alp
return [newTree, newSearchInts];
};

/**
* Create the test suite for a generic test
*
* @param dataset The dataset used in the suite
* @returns the created suite
*/
const createSuite = (dataset: Array<Interval<FlatInterval>>, alpha: number): Suite => {
return (new Suite).on('start cycle', function (event) {
if (getOrders()[iterator]) {
[tree, searchInts] = createTree(dataset, getOrders()[iterator], alpha);
iterator += 1;
}
});
}

const existTest = (dataset: Array<Interval<FlatInterval>>, alpha: number) => {
iterator = 0;
let suite = createSuite(dataset, alpha);
const benchmark = new Benchmark();

for (const order of getOrders())
suite = suite.add(`E_o${order}_a${alpha}#test`, () => {
for (let int of searchInts)
tree.exists(int);
});

addBenchmarkLogsAndRun(suite);
benchmark.add(
new Test(`E_o${order}_a${alpha}#test`, () => {
for (let int of searchInts)
tree.exists(int);
}).on('onBegin', () => {
[tree, searchInts] = createTree(dataset, order, alpha);
})
);

addBenchmarkLogsAndRun(benchmark);
}

const rangeSearchTest = (dataset: Array<Interval<FlatInterval>>, alpha: number) => {
iterator = 0;
let suite = createSuite(dataset, alpha);
const benchmark = new Benchmark();

for (const order of getOrders())
suite = suite.add(`RS_o${order}_a${alpha}#test`, () => {
for (let int of searchInts)
tree.allRangeSearch(int.getLowerBound(), int.getUpperBound());
});

addBenchmarkLogsAndRun(suite);
benchmark.add(
new Test(`RS_o${order}_a${alpha}#test`, () => {
for (let int of searchInts)
tree.allRangeSearch(int.getLowerBound(), int.getUpperBound());
}).on('onBegin', () => {
[tree, searchInts] = createTree(dataset, order, alpha);
})
);

addBenchmarkLogsAndRun(benchmark);
}

const containedRangeSearchTest = (dataset: Array<Interval<FlatInterval>>, alpha: number) => {
iterator = 0;
let suite = createSuite(dataset, alpha);
const benchmark = new Benchmark();

for (const order of getOrders())
suite = suite.add(`CRS_o${order}_a${alpha}#test`, () => {
for (let int of searchInts)
tree.containedRangeSearch(int.getLowerBound(), int.getUpperBound());
});

addBenchmarkLogsAndRun(suite);
benchmark.add(
new Test(`CRS_o${order}_a${alpha}#test`, () => {
for (let int of searchInts)
tree.containedRangeSearch(int.getLowerBound(), int.getUpperBound());
}).on('onBegin', () => {
[tree, searchInts] = createTree(dataset, order, alpha);
})
);

addBenchmarkLogsAndRun(benchmark);
}

export const run = (dataset: Array<Interval<FlatInterval>>) => {
Expand Down

0 comments on commit ca95661

Please sign in to comment.