-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdbscan.lua
More file actions
121 lines (108 loc) · 4.37 KB
/
dbscan.lua
File metadata and controls
121 lines (108 loc) · 4.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
module( ..., package.seeall )
require( "sql_help" )
local function InitDBScan( db )
--ResetDBScan( db )
db:execute( "CREATE TABLE IF NOT EXISTS dbScanClusterData (clusterID INTEGER, id INTEGER, type INTEGER );" )
db:execute( "CREATE TABLE IF NOT EXISTS dbScanClusterIds (clusterID INTEGER PRIMARY KEY AUTOINCREMENT, first INTEGER );" )
db:execute( "CREATE INDEX IF NOT EXISTS idx_dbScanCluster_id ON dbScanClusterData (id );" );
db:execute( "CREATE INDEX IF NOT EXISTS idx_dbScanCluster_clid ON dbScanClusterData ( clusterid );" );
--db:execute( "DROP TABLE IF EXISTS dbScanScan;" );
db:execute( "CREATE TABLE IF NOT EXISTS dbScanScan (id INTEGER PRIMARY KEY);" )
db:execute( "CREATE INDEX IF NOT EXISTS idx_dbScanScan_id ON dbScanScan (id );" )
end
function ResetDBScan( db )
db:execute( "DROP TABLE IF EXISTS dbScanClusterData;" )
db:execute( "DROP TABLE IF EXISTS dbScanClusterIds;" )
db:execute( "DROP TABLE IF EXISTS dbScanScan;" )
end
function AddToCluster( db, P, type, C )
type = type or 0 -- 0 = centre, 1 = edge
if C == nil then
SqlHelper( { db = db, sql = "INSERT INTO dbScanClusterIds (first ) VALUES ( ?);", param = { P } } )
C = db:last_insert_rowid();
end
SqlHelper( { db = db, sql = "INSERT INTO dbScanClusterData (clusterId, id, type ) VALUES( ?,?, ? );", param = { C, P, type} } )
SqlHelper( {db = db, sql = "INSERT OR IGNORE INTO dbScanScan (id ) VALUES ( ? );", param = { P } } )
return C
end
function DBSCAN( db, RegionQuery, tbl, eps, minPts )
InitDBScan( db )
local sql = "SELECT MIN(id) as nxt FROM $(table) WHERE ID NOT IN (SELECT id FROM dbScanScan);"
sql = SubField( sql, { table = tbl } )
local P
repeat
P = SqlHelper( { db = db, sql = sql, param = {} , result = "nxt" } )
if P ~= nil then
print( "id " .. tostring(P) .. " " .. os.date() .." " )
-- mark P as visited
-- if P == 6 then
-- print( "." )
-- end
local neighbours = RegionQuery( P, eps )
if #neighbours < minPts then
SqlHelper( {db = db, sql = "INSERT OR IGNORE INTO dbScanScan (id ) VALUES ( ? );", param = { P } } )
else
db:execute( "BEGIN;" );
C = AddToCluster( db, P )
expandCluster(db, P, neighbours, C, eps, minPts, RegionQuery )
db:execute( "COMMIT;" );
end
end
until P == nil
end
function IsClustered( db, id )
local i = SqlHelper( { db = db, sql = "SELECT id FROM dbScanClusterData WHERE id = ?;", param = { id } , result = "id" } )
if i then return true end
return false
end
function RemoveEntry( tb, id )
for i,j in ipairs( tb ) do
if j.id == id then
table.remove( tb, i )
return
end
end
end
function expandCluster( db, P, neigh, C, eps, minPts, RegionQuery )
local neighbours = {}
local visited = {}
for i,j in ipairs( neigh ) do
if j.dist == 0 and P ~= j.id then
AddToCluster( db, j.id, 0, C )
visited[ j.id ] = true
else
neighbours[ #neighbours + 1] = j
end
end
for i,j in ipairs( neighbours ) do
visited[ j.id ] = true
end
while #neighbours > 1 do
io.write( "neighbours " .. tostring( #neighbours ) .. " " .. os.date() .." \r" )
local item = neighbours[ #neighbours ]
table.remove( neighbours )
local type = 1
local newneighbours = {}
if item.dist == 0 then
type = 0 -- only type zero added to the list
else
newneighbours = RegionQuery( item.id, eps )
end
if #newneighbours >= minPts then
type = 0
for i,j in ipairs( newneighbours ) do
if visited[ j.id ] ~= true and j.dist > 0 then
neighbours[ #neighbours + 1] = j
visited[ j.id ] = true
end
if j.dist == 0 then
RemoveEntry( neighbours, j.id )
SqlHelper( {db = db, sql = "INSERT OR IGNORE INTO dbScanScan (id ) VALUES ( ? );", param = { j.id } } )
end
end
end
if not IsClustered( db, item.id ) then
AddToCluster( db, item.id, type, C )
end
end
end