# there must be an relation edges # and a file Speeds2 if not(isDBObject("Speeds2")) then restore Speeds2 from Speeds2 endif query meminit(20000) query memclear() # in a first step, we sssign speeds to the edges of the relation if not(isDBObject("EdgesB")) then let EdgesB = Speeds2 feed {s} Edges feed filter[isdefined(.Curve)] itHashJoin[RoadType_s, RoadType] extend[Cost: size(.Curve,[const geoid value WGS1984]) / (.Speed_s / 3.6), Middle: 0, NEdges: 1.0] project[Source, Target, SourcePos, TargetPos, Cost, Middle, NEdges] filter[isdefined(.Cost)] consume endif # store the EdgesB relation into an ordered relation to be able to create a graph from it if not(isDBObject("EdgesB2")) then let EdgesB2 = EdgesB feed sortbyh[Source, Target] oconsume[Source, Target] endif # store the largest connected component into relation EdgesC if not(isDBObject("EdgesC")) then { query memglet("EdgesB", EdgesB2) | let maxcompno = "EdgesB" mgconnectedcomponents sortbyh[CompNo] groupby[CompNo; Cnt: group count] kbiggest[1; Cnt] extract[CompNo] | let EdgesC = "EdgesB" mgconnectedcomponents filter[.CompNo = maxcompno] remove[CompNo] consume | query memdelete("EdgesB") | delete maxcompno } endif # release memory used by the graph "EdgesB" query memclear() # We renumber the nodes from 0 .. nodecount -1 # using an mgraph2 if not(isDBObject("EdgesD")) then { query EdgesC feed createmgraph2[Source,Target,.Cost,"EdgesD", TRUE] count | let EdgesD = "EdgesD" mg2feed projectextend[; Source : .MG_Source, SourcePos : .SourcePos, Cost : .MG_Cost, Middle : .Middle, NEdges : .NEdges, Target : .MG_Target, TargetPos : .TargetPos] consume | if isDBObject("NodeCount") then delete NodeCount endif | let NodeCount = mg2numvertices("EdgesD") } endif # release old memory objects query memclear() # create an mgraph3 from the EdgesD relation query EdgesD feed createmgraph3[Source, Target, Cost, NodeCount, "EdgesX"] count # store the nodes into a relation NodesA if not(isDBObject("NodesA")) then let NodesA = "EdgesX" mg3feed project[Source, SourcePos] renameattr[NodeIdNew: Source, Pos: SourcePos] "EdgesX" mg3feed project[Target, TargetPos] renameattr[NodeIdNew: Target, Pos: TargetPos] concat sorth rdup consume endif # create an empty relation for the contraction edges query "EdgesX" mg3feed head[0] letmconsume["ContractionX"] # create a priority queue from the nodes query NodesA feed projectextend[; Node: .NodeIdNew, Pos: .Pos, Prio: 0.0] mcreatepqueue[Prio, "NodesX"] count # create an empty relation for the deleted nodes query NodesA feed projectextend[; Node: .NodeIdNew, Pos: .Pos, Prio: 0.0, In: 0, Out: 0, CEdges: 0, Deleted: 0] head[0] letmconsume["DeletedNodes"]; # define a function for contraction # basic idea # for all nodes in the queue # if the product of in and out edges is higher than the periority => reinsert the node with adopted prio # else # if contraction of the edge reduces the number of edges or # the exact priority is better than the guessed one # then contract the node # else reinsert the node # # if the current priority overcomes the threshold maxprio # and at least minBlockSize nodes has been contracted since the # last reorganisation of the priority queue # then set all priorities within the queue to 0.0 # if isDBObject("contract") then delete contract endif let contract = fun(maxprio: int, minBlockSize : int, maxHops : int, progress : int) "NodesX" mfeedpq extend[ In : pwrap("EdgesX") mg3numpredecessors[.Node], Out: pwrap("EdgesX") mg3numsuccessors[.Node] ] extend[CEdges: fun(t: TUPLE) ifthenelse( (attr(t, In) * attr(t, Out)) <= attr(t, Prio), pwrap("EdgesX") mg3predecessors[attr(t,Node)] sortbyh[Source, Cost] krdup[Source] {i} pwrap("EdgesX") mg3successors[attr(t,Node)] sortbyh[Target, Cost] krdup[Target] {o} product filter[.Source_i # .Target_o] filter[ ( fun(node: int) pwrap("EdgesX") mg3successors[node] ) minPathCost1[Target, .Source_i, .Target_o, Cost, maxHops] >= (.Cost_i + .Cost_o) ] groupby[; Added: fun(g: GROUP) ifthenelse( (((attr(t, In) * attr(t, Out)) + ((g count) - (attr(t, In) + attr(t, Out)))) <= attr(t, Prio)) or ( (g count) <= attr(t,In) + attr(t,Out)), g feed projectextend[; Source: .Source_i, SourcePos: .SourcePos_i, Cost: .Cost_i + .Cost_o, Middle: attr(t, Node), NEdges: .NEdges_i + .NEdges_o, Target: .Target_o, TargetPos: .TargetPos_o ] mg3insert[pwrap("EdgesX")] minsert[pwrap("ContractionX")] count, bool2int(pwrap("NodesX") minserttuplepqprojectU[t, ((attr(t, In) * attr(t, Out)) + ((g count) - (attr(t, In) + attr(t, Out)))) * 1.0, Prio; Node, Pos, Prio]) - 10 )] extractDef[Added, 0] , bool2int(pwrap("NodesX") minserttuplepqprojectU[t, (attr(t, In) * attr(t, Out)) * 1.0, Prio; Node, Pos, Prio]) - 10 ) ] filter[.CEdges >= 0] addModCounter[Num,1, (.Prio > maxprio) and (.. > minBlockSize), 0] extend[ Dummy : ifthenelse(.Num = 0,pwrap("NodesX") mpqreorderupdate[ 0.0, Prio ],0)] remove[Num,Dummy] addcounter[Progress,1] filter[ ifthenelse((.Progress mod progress)=0, TRUE echo[num2string(.Progress)], TRUE)] remove[Progress] extend[Deleted: bool2int(pwrap("EdgesX") mg3disconnect[.Node]) ] minsert[pwrap("DeletedNodes")] count ##################### multitarget version of this function if isDBObject("mtcreationEdges") then delete mtcreationEdges endif let mtcreationEdges = fun(node10 : int, maxHops : int) pwrap("EdgesX") mg3predecessors[node10] sortbyh[Source,Cost] krdup[Source] {i} loopjoin[ fun(t10 : TUPLE) (fun(node11: int) pwrap("EdgesX") mg3successors[node11]) pwrap("EdgesX") mg3successors[node10] sortbyh[Target,Cost] krdup[Target] {o} mtMinPathCosts1[Target,attr(t10,Source_i), Target_o, Cost, maxHops] filter[attr(t10,Source_i) # .Target_o] extend[Cost : attr(t10,Cost_i) + .Cost_o] filter[.MinPC >= .Cost] remove[MinPC] ] if isDBObject("mtcontract") then delete mtcontract endif let mtcontract = fun(maxprio: int, minBlockSize : int, maxHops : int, progress : int) "NodesX" mfeedpq extend[ In : pwrap("EdgesX") mg3numpredecessors[.Node], Out: pwrap("EdgesX") mg3numsuccessors[.Node] ] extend[CEdges: fun(t: TUPLE) ifthenelse( (attr(t, In) * attr(t, Out)) <= attr(t, Prio), mtcreationEdges(attr(t,Node), maxHops) groupby[; Added: fun(g: GROUP) ifthenelse( (((attr(t, In) * attr(t, Out)) + ((g count) - (attr(t, In) + attr(t, Out)))) <= attr(t, Prio)) or ( (g count) <= attr(t,In) + attr(t,Out)), g feed projectextend[; Source: .Source_i, SourcePos: .SourcePos_i, Cost: .Cost_i + .Cost_o, Middle: attr(t, Node), NEdges: .NEdges_i + .NEdges_o, Target: .Target_o, TargetPos: .TargetPos_o ] mg3insert[pwrap("EdgesX")] minsert[pwrap("ContractionX")] count, bool2int(pwrap("NodesX") minserttuplepqprojectU[t, ((attr(t, In) * attr(t, Out)) + ((g count) - (attr(t, In) + attr(t, Out)))) * 1.0, Prio; Node, Pos, Prio]) - 10 )] extractDef[Added, 0] , bool2int(pwrap("NodesX") minserttuplepqprojectU[t, (attr(t, In) * attr(t, Out)) * 1.0, Prio; Node, Pos, Prio]) - 10 ) ] filter[.CEdges >= 0] addModCounter[Num,1, (.Prio > maxprio) and (.. > minBlockSize), 0] extend[ Dummy : ifthenelse(.Num = 0,pwrap("NodesX") mpqreorderupdate[ 0.0, Prio ],0)] remove[Num,Dummy] addcounter[Progress,1] filter[ ifthenelse((.Progress mod progress)=0, TRUE echo[num2string(.Progress)], TRUE)] remove[Progress] extend[Deleted: bool2int(pwrap("EdgesX") mg3disconnect[.Node]) ] minsert[pwrap("DeletedNodes")] count ########## the actual Contraction, play with arguments query mtcontract(30,300,8, NodeCount div 100) ####### make result persistent if isDBObject("EdgesX") then delete EdgesX endif let EdgesX = "EdgesX" mg3feed consume if isDBObject("NodesX") then delete NodesX endif let NodesX = "NodesX" mfeedpq consume {query memdelete("NodesX") | query NodesX feed mcreatepqueue[Prio, "NodesX"] count} if isDBObject("ContractionX") then delete ContractionX endif let ContractionX = "ContractionX" mfeed consume if isDBObject("NodeOrder") then delete NodeOrder endif let NodeOrder = "DeletedNodes" mfeed addcounter[NewId, 1] consume