Skip to content

Commit b982cdf

Browse files
committed
losing my mind, 5 hrs wasted over this algorithm for trying to achieve a O(log n) time over a dummy project. Hey atleast i figured it... ig?
1 parent 31dbb2d commit b982cdf

File tree

9 files changed

+232
-20
lines changed

9 files changed

+232
-20
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
basically a binary tree but partitions its childs through their geographic planes
2+
well since we have latitude and longitude, we can use Rtree
3+
https://en.wikipedia.org/wiki/R-tree
4+
just what we want
5+
or we can also use https://en.wikipedia.org/wiki/K-d_tree and use x,y coordinates, which is the same thing whatever
6+
then perform range search
7+
8+
i am not sure whether we need optimization since we dont need nearest neighbour search. Edit: Well we do dumbass
9+
10+
11+
search algo:
12+
13+
go recursively deep as a normal insert precudere, check if dist lower than 1km or whatever, add to all nodes, then from parent look at the other branch and from current dim (x or y) calculate if curr dim is bigger than 1km already, if not go check

lib/main.dart

+2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import 'package:flutter/material.dart';
2+
import 'package:harmony/services/kdtree_service.dart';
23

34
import 'starting_page.dart';
45

56
void main() {
7+
KDTreeService.initTree();
68
runApp(const MyApp());
79
}
810

lib/services/firestore.dart

+30-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,41 @@
11
import 'package:cloud_firestore/cloud_firestore.dart';
2+
import 'package:harmony/utilites/kdtree_implementation/kdtree.dart';
3+
import 'package:harmony/utilites/kdtree_implementation/kdtree.dart';
4+
import 'package:harmony/models/place.dart';
25

36
class FireStoreService{
4-
FirebaseFirestore _firestore = FirebaseFirestore.instance;
7+
static FirebaseFirestore _firestore = FirebaseFirestore.instance;
58

6-
CollectionReference users = FirebaseFirestore.instance.collection('users');
7-
CollectionReference places = FirebaseFirestore.instance.collection('places');
8-
CollectionReference reviews = FirebaseFirestore.instance.collection('reviews');
9+
static CollectionReference users = FirebaseFirestore.instance.collection('users');
10+
static CollectionReference places = FirebaseFirestore.instance.collection('places');
11+
static CollectionReference reviews = FirebaseFirestore.instance.collection('reviews');
12+
static CollectionReference place_kdtree = FirebaseFirestore.instance.collection("place-kdtree");
13+
14+
Future<KDTree> initKDTree() async{
15+
return await place_kdtree.
16+
doc("TREE").
17+
get().
18+
then(
19+
(value) => KDTree.fromJson(value.data()! as Map<String, dynamic>)
20+
);
21+
}
922

1023
Stream<QuerySnapshot> getPlacesStream(){
1124
return places.snapshots();
1225
}
1326

1427

28+
29+
30+
31+
void addPlace(){
32+
//IMPLEMENTATION AND SO WHAT
33+
//Add to place kd tree for optimization
34+
///addToPlaceKDTree();
35+
}
36+
37+
void addToPlaceKDTree(Place place){
38+
//TODO
39+
}
40+
1541
}

lib/services/kdtree_service.dart

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import 'dart:ffi';
2+
import 'dart:math';
3+
4+
import 'package:cloud_firestore/cloud_firestore.dart';
5+
import 'package:harmony/utilites/custom_exception.dart';
6+
import 'package:harmony/utilites/kdtree_implementation/kdtree.dart';
7+
import 'package:harmony/services/firestore.dart';
8+
import 'package:harmony/utilites/kdtree_implementation/node.dart';
9+
//https://www.cs.cmu.edu/~ckingsf/bioinfo-lectures/kdtrees.pdf
10+
class KDTreeService{
11+
12+
static KDTree? tree; //I am actually not sure how to not make this nullable, find a solution if you can
13+
14+
15+
static void initTree() async{
16+
tree = await FireStoreService().initKDTree();
17+
18+
KDTreeService().insertPosition([1,1,3]);
19+
}
20+
21+
void insertPosition(List<double> cartesianCoordinate){
22+
///Requires a Cartesian Coordinate, an x,y coordinate
23+
///May be time expensive, wait for it
24+
if(cartesianCoordinate.length != 2){
25+
throw new CustomException("Cartesian Coordinate list must include 2 vars, x,y");
26+
}
27+
try{
28+
tree!.rootNode = _insert(cartesianCoordinate, tree!.rootNode);
29+
} catch(e){
30+
print(e.toString());
31+
}
32+
}
33+
34+
void deletePosition(List<double> cartesianCoordinate){
35+
///Requires a Cartesian Coordinate, an x,y coordinate
36+
///May be time expensive, wait for it
37+
if(cartesianCoordinate.length != 2){
38+
throw new CustomException("Cartesian Coordinate list must include 2 vars, x,y");
39+
}
40+
try{
41+
tree!.rootNode = _delete(cartesianCoordinate, tree!.rootNode, 2);
42+
} catch(e){
43+
print(e.toString());
44+
}
45+
}
46+
47+
48+
49+
50+
Node _insert(List<double> point, Node? node, {int cd : 0}){
51+
int k = point.length;
52+
if (node == null) {
53+
node = Node(point: point);
54+
}
55+
else if(point == node.point){
56+
return throw new CustomException("Duplicate Node!");
57+
}
58+
else if(point[cd] < node.point[cd]) {
59+
node.leftChild = _insert(point, node.leftChild, cd : (cd+1) % k);
60+
}
61+
else {
62+
node.rightChild = _insert(point, node.rightChild, cd : (cd+1) % k);
63+
}
64+
return node;
65+
}
66+
67+
List<double> _findmin(Node? T, int dim, int cd){
68+
if (T == null) return throw new CustomException("Empty tree!"); //empty tree
69+
70+
// T splits on the dimension we’re searching
71+
// => only visit left subtree
72+
if (cd == dim){
73+
if (T.leftChild == null) return T.point; //Smallest in this subtree
74+
else return _findmin(T.leftChild, dim, (cd+1) % dim);
75+
}
76+
77+
// T splits on a different dimension
78+
// => have to search both subtrees
79+
else {
80+
List<List<double>> list = [
81+
_findmin(T.leftChild, dim, (cd+1) % dim),
82+
_findmin(T.leftChild, dim, (cd+1) % dim),
83+
T.point
84+
];
85+
list.sort((a,b) => a[dim].compareTo(b[dim])); //find min of dimension
86+
return list[0];
87+
}
88+
}
89+
90+
Node? _delete(List<double> x, Node? T,int dim, {int cd : 0}){
91+
if (T == null) return throw new CustomException("Empty tree!");
92+
int next_cd = (cd+1) % dim;
93+
94+
// This is the point to delete:
95+
if(x == T.point){
96+
// use min(cd) from right subtree:
97+
if(T.rightChild != null){
98+
//Basically switch
99+
T.point = _findmin(T.rightChild, dim, next_cd);
100+
T.rightChild = _delete(T.point, T.rightChild, dim, cd: next_cd);
101+
}
102+
else if(T.leftChild != null){ // swap subtrees and use min(cd) from new right:
103+
T.point = _findmin(T.leftChild, dim, next_cd);
104+
T.leftChild = _delete(T.point, T.leftChild, dim , cd: next_cd);
105+
}
106+
else{
107+
T = null; // we’re a leaf: just remove
108+
}
109+
}
110+
// this is not the point, so search for it:
111+
else if(x[cd] < T.point[cd]){
112+
T.leftChild = _delete(x, T.leftChild, dim , cd: next_cd);
113+
}
114+
else {
115+
T.rightChild = _delete(x, T.rightChild, dim , cd: next_cd);
116+
}
117+
return T;
118+
}
119+
120+
Node balanceTree(){
121+
122+
}
123+
124+
}

lib/utilites/custom_exception.dart

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class CustomException implements Exception {
2+
String cause;
3+
CustomException(this.cause);
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import 'package:harmony/utilites/kdtree_implementation/node.dart';
2+
3+
class KDTree{
4+
Node? rootNode;
5+
6+
KDTree({this.rootNode});
7+
8+
9+
10+
11+
factory KDTree.fromJson(Map<String, dynamic> treeData){
12+
if (treeData.isEmpty){
13+
return KDTree();
14+
}
15+
return KDTree(
16+
rootNode: createNode(treeData['root_node'])
17+
);
18+
}
19+
20+
static Node createNode(Map<String, dynamic> nodeData){
21+
Node node = Node(
22+
point: nodeData['coordinate'] as List<double>
23+
);
24+
25+
if (nodeData['left_child'] != null){
26+
Node leftChild = createNode(nodeData['left_child']);
27+
node.leftChild = leftChild;
28+
}
29+
if(nodeData["right_child"] != null){
30+
Node rightChild = createNode(nodeData["right_child"]);
31+
node.rightChild = rightChild;
32+
}
33+
34+
return node;
35+
}
36+
37+
38+
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class Node{
2+
3+
Node? leftChild;
4+
Node? rightChild;
5+
6+
List<double> point;
7+
8+
Node({required this.point, this.leftChild, this.rightChild});
9+
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import 'package:cloud_firestore/cloud_firestore.dart';
2+
3+
class DiscoverPageViewModel{
4+
5+
6+
7+
8+
}

lib/views/discover/place_builder.dart

+2-16
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,10 @@ class _PlaceBuilderState extends State<PlaceBuilder> {
1818
}
1919
@override
2020
Widget build(BuildContext context) {
21-
return StreamBuilder<QuerySnapshot>(
22-
stream: FireStoreService().getPlacesStream(),
23-
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) { //
24-
if (snapshot.hasError) {
25-
return Text('Something went wrong');
26-
}
2721

28-
if (snapshot.connectionState == ConnectionState.waiting) {
29-
return CircularProgressIndicator();
30-
}
22+
return ListView.builder(
23+
itemBuilder: (BuildContext context, int index){
3124

32-
return ListView.builder(
33-
itemBuilder: (BuildContext context, int index) {
34-
return Text("h");
35-
},
36-
37-
38-
);
3925
},
4026
);
4127
}

0 commit comments

Comments
 (0)