Guest User

Julia precision issues

a guest
Jan 28th, 2022
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Julia 5.09 KB | None | 0 0
  1. using Statistics
  2.  
  3. # Run in command line as
  4. # > julia icp_precision.jl n precision
  5. # Example:
  6. # > julia icp_precision.jl 9 3000
  7.  
  8. struct Region
  9.     A::Vector{BigFloat} # point set A
  10.     B::Vector{BigFloat} # point set B
  11.     width::BigFloat     # largest (a, b) distance
  12.  
  13.     function Region(A::Vector{BigFloat}, B::Vector{BigFloat})
  14.         width::BigFloat = maximum([abs(a-b) for a ∈ A, b ∈ B])
  15.         return new(sort(A), sort(B), width)
  16.     end
  17. end
  18.  
  19. struct ICPConstruction
  20.     regions::Vector{Region}
  21.     A::Vector{BigFloat} # point set A
  22.     B::Vector{BigFloat} # point set B
  23.     δ::BigFloat         # largest (a, b) distance within any region
  24.    
  25.     "Assembles full ICP construction with A and B point sets (vectors)."
  26.     function ICPConstruction(regions::Vector{Region})
  27.         # extract, concatenate, and sort overall A and B from regions
  28.         A = reduce(vcat, map(r -> r.A, regions)) |> sort
  29.         B = reduce(vcat, map(r -> r.B, regions)) |> sort
  30.         δ = reduce(vcat, map(r -> r.width, regions)) |> maximum
  31.         return new(regions, A, B, δ)
  32.     end
  33. end
  34.  
  35. function add_region(c::ICPConstruction, new::Region)::ICPConstruction
  36.     δ::BigFloat = maximum([c.δ, new.width])
  37.     min_old::BigFloat = minimum(vcat(c.A, c.B))
  38.     max_new::BigFloat = maximum(vcat(new.A, new.B))
  39.     shift::BigFloat = abs(min_old - max_new) + 3δ + 1
  40.    
  41.     A′ = new.A .- shift
  42.     B′ = new.B .- shift
  43.     regions = vcat(c.regions, Region(A′, B′))
  44.     return ICPConstruction(regions)
  45. end
  46.  
  47. function AugmentedLinearShifter(n::BigInt)::ICPConstruction
  48.     # width of augmented linear shifter is (2n + 1)ℓ - 1 / k^n
  49.     k::BigInt = 3n + 2
  50.     ℓ::BigFloat = sum([1 / k^j for j ∈ 0:n])
  51.  
  52.     # Define A
  53.     A::Vector{BigFloat} = [-2i *for i ∈ 0:n]
  54.  
  55.     # Define B
  56.     b₀::BigFloat = 0.0
  57.     b(i) = sum([1 / k^j for j ∈ 0:i-1])
  58.     bᵢ::Vector{BigFloat} = [b(i) for i ∈ 1:n]
  59.     B::Vector{BigFloat} = vcat(b₀, bᵢ)
  60.  
  61.     # Define Linear Shifter
  62.     linear_shifter = Region(A, B)
  63.     return ICPConstruction([linear_shifter])
  64. end
  65.  
  66. struct Redirector
  67.     regions::Tuple{Region, Region}
  68.     A::Vector{BigFloat} # A₁ ∪ A₂
  69.     B::Vector{BigFloat} # B₁ ∪ B₂
  70.     v::BigFloat
  71.     y::BigFloat
  72.  
  73.     function Redirector(v::BigFloat, y::BigFloat, k::BigInt)
  74.         # Region 1
  75.         a::BigFloat = 0.5k * v - y # a is y to the left of the (b₁ b₂) midpoint
  76.         b₁::BigFloat = 0.0
  77.         b₂::BigFloat = k * v
  78.         A₁ = [a]
  79.         B₁ = [b₁, b₂]
  80.         R₁ = Region(A₁, B₁)
  81.  
  82.         # Region 2
  83.         a′::BigFloat = 0.0
  84.         A₂ = [a′]
  85.         B₂ = [a′ + 0.5]
  86.         R₂ = Region(A₂, B₂)
  87.  
  88.         regions = (R₁, R₂)
  89.         A = reduce(vcat, map(r -> r.A, regions)) |> sort
  90.         B = reduce(vcat, map(r -> r.B, regions)) |> sort
  91.         return new((R₁, R₂), A, B, v, y)
  92.     end
  93. end
  94.  
  95. function icp1d(construction::ICPConstruction; k = big"0")
  96.     A::Vector{BigFloat} = copy(construction.A)
  97.     B::Vector{BigFloat} = copy(construction.B)
  98.  
  99.     t::BigFloat = 0.0
  100.     correspondences::Vector{Int64} = []
  101.     for a ∈ A
  102.         neighbor = argmin(abs.(B .- a))
  103.         push!(correspondences, neighbor)
  104.     end
  105.  
  106.     # Remember transformations for visualization
  107.     ts::Vector{BigFloat} = []
  108.     cs::Vector{Vector{Int64}} = []
  109.    
  110.     while true
  111.         # remember iteration state for visualization
  112.         push!(ts, t)
  113.         push!(cs, copy(correspondences))
  114.        
  115.         # find nearest neighbours
  116.         BNeighbours = @view B[correspondences]
  117.  
  118.         # calculate mean for each point cloud
  119.         a0::BigFloat = k == 0 ? mean(A) : sum(A) / k
  120.         b0::BigFloat = k == 0 ? mean(BNeighbours) : sum(BNeighbours) / k
  121.  
  122.         # compute transformations
  123.         t = b0 - a0
  124.         A .+= t
  125.  
  126.         # compute new correspondences
  127.         correspondences = []
  128.         for a ∈ A
  129.             neighbor = argmin(abs.(B .- a))
  130.             push!(correspondences, neighbor)
  131.         end
  132.        
  133.         # terminate if nearest neighbours don't change
  134.         if correspondences == cs[end]
  135.             push!(ts, t)
  136.             break
  137.         end
  138.     end
  139.    
  140.     return ts, cs
  141. end
  142.  
  143. function run_full_construction(n::BigInt)
  144.     k::BigInt = 3n + 2
  145.     ℓ::BigFloat = sum([1 / k^j for j ∈ 0:n])
  146.  
  147.     construction = AugmentedLinearShifter(n);
  148.     redirectors = [Redirector(ℓ + 1, (2i + 1)ℓ, k) for i ∈ 0:n-1]
  149.     redirector_regions = map(r -> collect(r.regions), redirectors) |> Iterators.flatten |> collect
  150.  
  151.     for region ∈ redirector_regions
  152.         construction = add_region(construction, region)
  153.     end
  154.  
  155.     # determine kickoff translation
  156.     x₁::BigFloat = icp1d(construction, k=k)[1][2]
  157.  
  158.     a′::BigFloat = big"0.0"
  159.     b′::BigFloat = a′ + (1.0 - x₁)k
  160.     kicker_region = Region([a′], [b′])
  161.  
  162.     # complete construction with kicker region
  163.     construction = add_region(construction, kicker_region)
  164.     @assert length(construction.A) == k "k must equal |A|"
  165.    
  166.     # run ICP on fill construction
  167.     translations, correspondences = icp1d(construction)
  168.     return construction, translations, correspondences
  169. end
  170.  
  171. if length(ARGS) == 2
  172.     n = parse(BigInt, ARGS[1])
  173.     setprecision(parse(Int, ARGS[2]))
  174. else
  175.     n = big"8"
  176.     setprecision(2000)
  177. end
  178.  
  179. println("\n🌟 Running one-dimensional ICP for n = $n with precision $(precision(BigFloat))...")
  180.  
  181. construction, t, c = run_full_construction(n)
  182. iterations_expected = (n+1)^2 + 1
  183.  
  184. println("🌟 ICP took $(length(t)) iterations. $iterations_expected were expected. $(length(t) == iterations_expected ? "" : "")\n")
Advertisement
Add Comment
Please, Sign In to add comment