Added point removal

main
František Špaček 1 year ago
parent 47358a6b9a
commit e3f056c40a

@ -137,12 +137,22 @@ app.get('/kNNQuery', (req, res) => {
const result = mtree.kNNQuery(parsedQueryPoint, kInt); const result = mtree.kNNQuery(parsedQueryPoint, kInt);
const mtreeKNNQueryTime = performance.now() - start; const mtreeKNNQueryTime = performance.now() - start;
const start2 = performance.now(); /*const start2 = performance.now();
let sequentialFunctionCalls = 0; let sequentialFunctionCalls = 0;
const sequentialResult = points.sort((a, b) => { const sequentialResult = points.sort((a, b) => {
sequentialFunctionCalls++; sequentialFunctionCalls++;
return mtree.distanceFunction(a, parsedQueryPoint) - mtree.distanceFunction(b, parsedQueryPoint); return mtree.distanceFunction(a, parsedQueryPoint) - mtree.distanceFunction(b, parsedQueryPoint);
}).slice(0, kInt); }).slice(0, kInt);*/
const start2 = performance.now();
let sequentialFunctionCalls = 0;
const distances = points.map(point => {
sequentialFunctionCalls++;
return { point, distance: mtree.distanceFunction(point, parsedQueryPoint) };
});
distances.sort((a, b) => a.distance - b.distance);
const sequentialResult = distances.slice(0, kInt).map(({ point }) => point);
const sequentialSearchTime = performance.now() - start2; const sequentialSearchTime = performance.now() - start2;
/*if (JSON.stringify(result.points.map(point => point.point)) !== JSON.stringify(sequentialResult)) { /*if (JSON.stringify(result.points.map(point => point.point)) !== JSON.stringify(sequentialResult)) {
@ -226,5 +236,16 @@ app.post('/loadTree', (req, res) => {
res.send('MTree loaded'); res.send('MTree loaded');
}); });
// Remove the given point from the MTree
app.post('/remove', (req, res) => {
const point = req.body.point;
if (!point)
return res.status(400).send('Missing point');
if (mtree.remove(point))
res.send('Point removed from MTree');
else
res.status(404).send('Point not found in MTree');
});
// Start the server // Start the server
app.listen(3000, () => { console.log('MTree API is running on port 3000'); }); app.listen(3000, () => { console.log('MTree API is running on port 3000'); });

@ -295,6 +295,32 @@ class MTree {
} }
} }
} }
/**
* Removes a point from the MTree.
* @param {number[]} point - The point to remove
* @param {Node} [currentNode] - The node to start searching from, defaults to the root node
* @returns {boolean} True if the point was removed, false otherwise
*/
remove(point, currentNode = this.root) {
for (let i = 0; i < currentNode.entries.length; i++) {
const entry = currentNode.entries[i];
const distance = this.distanceFunction(point, entry.point);
if (currentNode.isLeaf) {
if (distance === 0) {
currentNode.entries.splice(i, 1);
return true;
}
} else {
if (distance <= entry.radius) {
const deleted = this.remove(point, entry);
if (deleted) return true;
}
}
}
return false;
}
} }
module.exports = MTree; module.exports = MTree;

@ -83,15 +83,18 @@ class Node {
* @returns {GroundEntry[]} An array of ground entries found within the node. * @returns {GroundEntry[]} An array of ground entries found within the node.
*/ */
static findGroundEntries(node) { static findGroundEntries(node) {
const stack = [node];
const result = [];
while (stack.length > 0) {
const node = stack.pop();
if (node.isLeaf) { if (node.isLeaf) {
return node.entries.filter(entry => entry instanceof GroundEntry); result.push(...node.entries.filter(entry => entry instanceof GroundEntry));
} else { } else {
const result = []; stack.push(...node.entries);
for (const entry of node.entries) {
result.push(...Node.findGroundEntries(entry));
} }
return result;
} }
return result;
}; };
findGroundEntries() { findGroundEntries() {

@ -24,6 +24,7 @@
<input type="text" id="point" /> <input type="text" id="point" />
</div> </div>
<button id="insertButton" disabled>Insert Point</button> <button id="insertButton" disabled>Insert Point</button>
<button id="removeButton" disabled>Remove Point</button>
<div class="form-group"> <div class="form-group">
<label for="dimensions">Dimensions:</label> <label for="dimensions">Dimensions:</label>
<input type="number" id="dimensions" value="3" placeholder="e.g. 3" min="0" /> <input type="number" id="dimensions" value="3" placeholder="e.g. 3" min="0" />

@ -176,7 +176,7 @@
sequentialSearch: 0 sequentialSearch: 0
} }
}; };
for (let j = 0; j < 5; j++) { for (let j = 0; j < 2; j++) {
const response = await fetch('/recreate', { const response = await fetch('/recreate', {
method: 'POST', method: 'POST',
@ -186,7 +186,8 @@
pointCount: datasetSize, pointCount: datasetSize,
capacity: mTreeNodeSize, capacity: mTreeNodeSize,
distanceFunction: 'euclidean' distanceFunction: 'euclidean'
}) }),
timeout: 6000000
}); });
if (!response.ok) { if (!response.ok) {
throw new Error(`error recreating tree: ${await response.text()}`); throw new Error(`error recreating tree: ${await response.text()}`);
@ -195,9 +196,9 @@
const { treeCreationTime } = await response.json(); const { treeCreationTime } = await response.json();
timingResults.treeCreationTime += treeCreationTime; timingResults.treeCreationTime += treeCreationTime;
for (let i = 0; i < 5; i++) { for (let i = 0; i < 4; i++) {
const queryPoint = Array(dimension).fill(i / 5); const queryPoint = Array(dimension).fill(i / 4);
const knnResponse = await fetch(`/kNNQuery?queryPoint=${encodeURIComponent(JSON.stringify(queryPoint))}&k=${encodeURIComponent((i + 1)*3)}`); const knnResponse = await fetch(`/kNNQuery?queryPoint=${encodeURIComponent(JSON.stringify(queryPoint))}&k=${encodeURIComponent((i + 1)*3)}`);
if (!knnResponse.ok) { if (!knnResponse.ok) {
@ -229,20 +230,19 @@
} }
} }
timingResults.treeCreationTime /= 5; timingResults.treeCreationTime /= 2;
timingResults.rangeQueryTime.mtreeRangeQuery /= 25; timingResults.rangeQueryTime.mtreeRangeQuery /= 8;
functionCallCounts.rangeQuery.mtreeRangeQuery /= 25; functionCallCounts.rangeQuery.mtreeRangeQuery /= 8;
timingResults.rangeQueryTime.sequentialSearch /= 25; timingResults.rangeQueryTime.sequentialSearch /= 8;
functionCallCounts.rangeQuery.sequentialSearch /= 25; functionCallCounts.rangeQuery.sequentialSearch /= 8;
timingResults.knnQueryTime.mtreeKNNQuery /= 25; timingResults.knnQueryTime.mtreeKNNQuery /= 8;
functionCallCounts.knnQuery.mtreeKNNQuery /= 25; functionCallCounts.knnQuery.mtreeKNNQuery /= 8;
timingResults.knnQueryTime.sequentialSearch /= 25; timingResults.knnQueryTime.sequentialSearch /= 8;
functionCallCounts.knnQuery.sequentialSearch /= 25; functionCallCounts.knnQuery.sequentialSearch /= 8;
return { timingResults, functionCallCounts };
const endTime = performance.now(); const endTime = performance.now();
console.log(`finished at ${endTime} after ${endTime - startTime}ms`); console.log(`finished at ${endTime} after ${endTime - startTime}ms`);
return { timingResults, functionCallCounts };
} catch (error) { } catch (error) {
console.error('error running tests:', error); console.error('error running tests:', error);
return {}; return {};

@ -20,6 +20,7 @@ function toggleButtons(enable) {
document.getElementById('rangeQueryButton').disabled = !enable; document.getElementById('rangeQueryButton').disabled = !enable;
document.getElementById('knnQueryButton').disabled = !enable; document.getElementById('knnQueryButton').disabled = !enable;
document.getElementById('insertButton').disabled = !enable; document.getElementById('insertButton').disabled = !enable;
document.getElementById('removeButton').disabled = !enable;
document.getElementById('saveTreeButton').disabled = !enable; document.getElementById('saveTreeButton').disabled = !enable;
} }
@ -208,6 +209,23 @@ async function loadTree() {
reader.readAsText(file); reader.readAsText(file);
} }
/**
* Removes the point with the given coordinates from the MTree.
* After removing the point, updates the status element with a success or failure message.
*/
async function removePoint() {
const pointString = document.getElementById('point').value;
const point = JSON.parse(pointString);
const response = await fetch('/remove', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ point })
});
setStatus(response.ok);
document.getElementById('status').innerText = response.ok ? 'Point removed' : `Error: ${await response.text()}`;
}
/** /**
* Sets the status element to display a success or failure message. * Sets the status element to display a success or failure message.
* @param {boolean} success - Whether the operation was successful. * @param {boolean} success - Whether the operation was successful.
@ -223,6 +241,7 @@ document.addEventListener('DOMContentLoaded', () => {
document.getElementById('rangeQueryButton').addEventListener('click', performRangeQuery); document.getElementById('rangeQueryButton').addEventListener('click', performRangeQuery);
document.getElementById('knnQueryButton').addEventListener('click', performKNNQuery); document.getElementById('knnQueryButton').addEventListener('click', performKNNQuery);
document.getElementById('insertButton').addEventListener('click', insertPoint); document.getElementById('insertButton').addEventListener('click', insertPoint);
document.getElementById('removeButton').addEventListener('click', removePoint);
document.getElementById('recreateTreeButton').addEventListener('click', recreateTree); document.getElementById('recreateTreeButton').addEventListener('click', recreateTree);
document.getElementById('saveTreeButton').addEventListener('click', saveTree); document.getElementById('saveTreeButton').addEventListener('click', saveTree);
@ -243,3 +262,4 @@ document.addEventListener('DOMContentLoaded', () => {
}); });
}); });
}); });

Loading…
Cancel
Save

Powered by TurnKey Linux.