2011-11-09 10 views
8

Olası Çoğalt:
Is there any documented free R-Tree implementation for .NET?
F # (veya C#) içindeki herhangi bir R-Tree uygulaması?

F # herhangi R-ağacı uygulamaları var mıdır? Varsayımlar şunlardır: ekleme veya silme işlemine gerek yoktur, sabitlenmiş Geo-Fences kümesi (bölgeler). İhtiyaçlar şunlardır: çok hızlı arama süresi.

Eğer

+0

Bu iyi bir kaynaktır: http://www.itu.dk/research/c5/ Hiçbir R-ağacı uygulaması AFAIK ama sen adapte olabilecek başka bir şey bulamazlarsa/uzatmak ağaç koleksiyonlarından biri. –

+0

@Daniel Thanks. Bunu zaten buldum, ama bundan memnun değildim. Bu yüzden, Google’da görünmeyen seçenekleri görmek için buraya geldim. –

cevap

7

İşte F # için this one in OCaml hızlı bir çeviri ederiz.

namespace RTree 

open System 

module Envelope = 

    type t = float * float * float * float 

    let ranges_intersect a b a' b' = a' <= b && a <= b' 

    let intersects (x0, x1, y0, y1) (x0', x1', y0', y1') = 
    (* For two envelopes to intersect, both of their ranges do. *) 
    ranges_intersect x0 x1 x0' x1' && ranges_intersect y0 y1 y0' y1' 

    let add (x0, x1, y0, y1) (x0', x1', y0', y1') = 
    min x0 x0', max x1 x1', min y0 y0', max y1 y1' 

    let rec add_many = function 
    | e :: [] -> e 
    | e :: es -> add e (add_many es) 
    | [] -> raise (ArgumentException "can't zero envelopes") 

    let area (x0, x1, y0, y1) = 
    (x1 - x0) * (y1 - y0) 

    let within (x0, x1, y0, y1) (x0', x1', y0', y1') = 
    x0 <= x0' && x1 >= x1' && y0 <= y0' && y1 >= y1' 

    let empty = 0., 0., 0., 0. 

module rtree = 

    type 'a t = 
     Node of (Envelope.t * 'a t) list 
    | Leaf of (Envelope.t * 'a) list 
    | Empty 

    let max_node_load = 8 

    let empty = Empty 
    let empty_node = (Envelope.empty, Empty) 

    let enlargement_needed e e' = 
    Envelope.area (Envelope.add e e') - Envelope.area e 

    let rec partition_by_min_enlargement e = function 
    | (e', _) as n :: [] -> 
     n, [], enlargement_needed e e' 
    | (e', _) as n :: ns -> 
     let enlargement = enlargement_needed e e' 
     let min, maxs, enlargement' = partition_by_min_enlargement e ns 
     if enlargement < enlargement' then 
      n, min :: maxs, enlargement 
     else 
      min, n :: maxs, enlargement' 
    | [] -> 
     raise (ArgumentException "cannot partition an empty node") 

    let pairs_of_list xs = (* (cross product) *) 
    List.concat (List.map (fun x -> List.map (fun y -> (x, y)) xs) xs) 

    (* This is Guttman's quadradic splitting algorithm. *) 
    let split_pick_seeds ns = 
    let pairs = pairs_of_list ns 
    let cost (e0, _) (e1, _) = 
     (Envelope.area (Envelope.add e0 e1)) - 
     (Envelope.area e0) - (Envelope.area e1) 
    let rec max_cost = function 
     | (n, n') :: [] -> cost n n', (n, n') 
     | (n, n') as pair :: ns -> 
      let max_cost', pair' = max_cost ns 
      let cost = cost n n' 
      if cost > max_cost' then 
      cost, pair 
      else 
      max_cost', pair' 
     | [] -> raise (ArgumentException "can't compute split on empty list") 
    let (_, groups) = max_cost pairs in groups 

    let split_pick_next e0 e1 ns = 
    let diff (e, _) = 
     abs ((enlargement_needed e0 e) - (enlargement_needed e1 e)) 
    let rec max_difference = function 
     | n :: [] -> diff n, n 
     | n :: ns -> 
      let diff', n' = max_difference ns 
      let diff = diff n 
      if diff > diff' then 
      diff, n 
      else 
      diff', n' 
     | [] -> raise (ArgumentException "can't compute max diff on empty list") 
    let (_, n) = max_difference ns in n 

    let split_nodes ns = 
    let rec partition xs xs_envelope ys ys_envelope = function 
     | [] -> (xs, xs_envelope), (ys, ys_envelope) 
     | rest -> 
      let (e, _) as n = split_pick_next xs_envelope ys_envelope rest 
      let rest' = List.filter ((<>) n) rest 
      let enlargement_x = enlargement_needed e xs_envelope 
      let enlargement_y = enlargement_needed e ys_envelope 
      if enlargement_x < enlargement_y then 
      partition (n :: xs) (Envelope.add xs_envelope e) ys ys_envelope rest' 
      else 
      partition xs xs_envelope (n :: ys) (Envelope.add ys_envelope e) rest' 
    let (((e0, _) as n0), ((e1, _) as n1)) = split_pick_seeds ns 
    partition [n0] e0 [n1] e1 (List.filter (fun n -> n <> n0 && n <> n1) ns) 

    let envelope_of_nodes ns = Envelope.add_many (List.map (fun (e, _) -> e) ns) 

    let rec insert' elem e = function 
    | Node ns -> 
     let (_, min), maxs, _ = partition_by_min_enlargement e ns 
     match insert' elem e min with 
      | min', (_, Empty) -> 
       let ns' = min' :: maxs 
       let e' = envelope_of_nodes ns' 
       (e', Node ns'), empty_node 
      | min', min'' when (List.length maxs + 2) < max_node_load -> 
       let ns' = min' :: min'' :: maxs 
       let e' = envelope_of_nodes ns' 
       (e', Node ns'), empty_node 
      | min', min'' -> 
       let (a, envelope_a), (b, envelope_b) = 
       split_nodes (min' :: min'' :: maxs) 
       (envelope_a, Node a), (envelope_b, Node b) 
    | Leaf es -> 
     let es' = (e, elem) :: es 
     if List.length es' > max_node_load then 
      let (a, envelope_a), (b, envelope_b) = split_nodes es' 
      (envelope_a, Leaf a), (envelope_b, Leaf b) 
     else 
      (envelope_of_nodes es', Leaf es'), empty_node 
    | Empty -> 
     (e, Leaf [e, elem]), empty_node 

    let insert t elem e = 
    match insert' elem e t with 
     | (_, a), (_, Empty) -> a 
     | a, b -> Node [a; b] (* root split *) 

    let filter_intersecting e = 
    List.filter (fun (e', _) -> Envelope.intersects e e') 

    let rec find t e = 
    match t with 
     | Node ns -> 
      let intersecting = filter_intersecting e ns 
      let found = List.map (fun (_, n) -> find n e) intersecting 
      List.concat found 
     | Leaf es -> List.map snd (filter_intersecting e es) 
     | Empty -> [] 

    let rec size = function 
    | Node ns -> 
     let sub_sizes = List.map (fun (_, n) -> size n) ns 
     List.fold (+) 0 sub_sizes 
    | Leaf es -> 
     List.length es 
    | Empty -> 
     0