Skip to content

Commit 675af4a

Browse files
reverting
1 parent 2f2e826 commit 675af4a

File tree

2 files changed

+78
-23
lines changed

2 files changed

+78
-23
lines changed

src/sfdp.jl

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,29 +24,78 @@ the nodes.
2424
positions will be truncated or filled up with random values between [-1,1] in every coordinate.
2525
2626
- `seed=1`: Seed for random initial positions.
27-
- `fixed = false` : Anchors initial positions.
27+
- `pin::Union{Nothing, Vector{Point{Dim,Bool}}}=nothing` : Anchors positions of nodes to initial position
2828
"""
2929
@addcall struct SFDP{Dim,Ptype,T<:AbstractFloat} <: IterativeLayout{Dim,Ptype}
3030
tol::T
3131
C::T
3232
K::T
3333
iterations::Int
34-
initialpos::Vector{Point{Dim,Ptype}}
34+
initialpos::Dict{Int, Point{Dim,Ptype}}
3535
seed::UInt
36-
fixed::Bool
36+
pin::Vector{Point{Dim,Bool}}
37+
function SFDP(tol, C, K, iterations, initialpos, seed, pin)
38+
for (ix, p) in enumerate(pin)
39+
for (id, c) in enumerate(p)
40+
c && !haskey(initialpos, ix) && error("Please provide coordinate for every pinned position")
41+
end
42+
end
43+
dim = get_pt_dim(initialpos)
44+
ptype = get_pt_ptype(initialpos)
45+
new{dim, ptype, typeof(tol)}(tol, C, K, iterations, initialpos, seed, pin)
46+
end
3747
end
3848

3949
# TODO: check SFDP default parameters
40-
function SFDP(; dim=2, Ptype=Float64, tol=1.0, C=0.2, K=1.0, iterations=100, initialpos=Point{dim,Ptype}[],
41-
seed=1, fixed = false)
42-
if !isempty(initialpos)
43-
initialpos = Point.(initialpos)
44-
Ptype = eltype(eltype(initialpos))
45-
# TODO fix initial pos if list has points of multiple types
46-
Ptype == Any && error("Please provide list of Point{N,T} with same T")
47-
dim = length(eltype(initialpos))
50+
function SFDP(; dim=2, Ptype=Float64, tol=1.0, C=0.2, K=1.0, iterations=100, initialpos=Dict{Int, Point{dim,Ptype}}(),
51+
seed::UInt=UInt(1), pin = Vector{Bool}())
52+
@show initialpos
53+
return SFDP(tol, C, K, iterations, initialpos, seed, pin)
54+
end
55+
56+
function SFDP(tol::T, C::T, K::T, iterations::Int, initialpos::Vector, seed::UInt, pin) where T<:AbstractFloat
57+
@info "sfdp with ip vec"
58+
dim = get_pt_dim(initialpos)
59+
initialpos = Dict(zip(1:length(initialpos), Point.(initialpos)))
60+
Ptype = get_pt_ptype(initialpos)
61+
# TODO fix initial pos if list has points of multiple types
62+
return SFDP(tol, C, K, iterations, initialpos, seed, pin)
63+
end
64+
65+
function SFDP(tol::T, C::T, K::T, iterations::Int, initialpos::Dict{Int, <:Point}, seed::UInt, pin::Dict{Int, <:Point}) where {T<:AbstractFloat}
66+
@info "sfdp with ip dict and pin dict"
67+
fixed = falses(maximum(keys(pin)))
68+
for (i, p) in pin
69+
haskey(initialpos, i) && @warn "overwriting initial position of node $i with pin position"
70+
initialpos[i] = p
71+
fixed[i] = true
4872
end
49-
return SFDP{dim,Ptype,typeof(tol)}(tol, C, K, iterations, initialpos, seed, fixed)
73+
dim = get_pt_dim(initialpos)
74+
Ptype = get_pt_ptype(initialpos)
75+
return SFDP(tol, C, K, iterations, initialpos, seed, Point{dim,Bool}.(fixed))
76+
end
77+
78+
function SFDP(tol::T, C::T, K::T, iterations::Int, initialpos::Dict{Int, <:Point}, seed::UInt, pin::Vector{Bool}) where T<:AbstractFloat
79+
@info "sfdp with ip dict and pin vec"
80+
dim = get_pt_dim(initialpos)
81+
Ptype = get_pt_ptype(initialpos)
82+
return SFDP(tol, C, K, iterations, initialpos, seed, Point{dim, Bool}.(pin))
83+
end
84+
85+
function get_pt_ptype(ip::Dict{Int, <:Point})
86+
ptype = eltype(eltype(values(ip)))
87+
ptype == Any && error("Please provide list of Point{N,T} with same T")
88+
return ptype
89+
end
90+
91+
function get_pt_dim(ip::Vector)
92+
dims = length.(ip)
93+
length(unique(dims)) != 1 && error("Please provide list of Point{N,T} with same N")
94+
return first(dims)
95+
end
96+
97+
function get_pt_dim(ip::Dict{Int, <:Point})
98+
return typeof(ip).parameters[2].parameters[1] #based on type of point
5099
end
51100

52101
function Base.iterate(iter::LayoutIterator{SFDP{Dim,Ptype,T}}) where {Dim,Ptype,T}
@@ -55,22 +104,23 @@ function Base.iterate(iter::LayoutIterator{SFDP{Dim,Ptype,T}}) where {Dim,Ptype,
55104
M = length(algo.initialpos)
56105
rng = MersenneTwister(algo.seed)
57106
startpos = Vector{Point{Dim,Ptype}}(undef, N)
58-
startposbounds = (min = zero(Point{Dim, Ptype}), max = zero((Point{Dim, Ptype})) .+ one(Ptype))
59107
# take the first
60-
for i in 1:min(N, M)
61-
startpos[i] = algo.initialpos[i]
108+
for (i, p) in algo.initialpos
109+
startpos[i] = p
62110
end
63111

64112
# create bounds for random initial positions
65-
if M > 0
113+
if isempty(algo.initialpos)
114+
startposbounds = (min = zero(Point{Dim, Ptype}), max = zero((Point{Dim, Ptype})) .+ one(Ptype))
115+
else
66116
startposbounds = (
67-
min = Point{Dim, Ptype}([minimum((p[d] for p in startpos[1:min(N, M)])) for d in 1:Dim]),
68-
max = Point{Dim, Ptype}([maximum((p[d] for p in startpos[1:min(N, M)])) for d in 1:Dim])
117+
min = Point{Dim, Ptype}([minimum((p[d] for p in values(algo.initialpos))) for d in 1:Dim]),
118+
max = Point{Dim, Ptype}([maximum((p[d] for p in values(algo.initialpos))) for d in 1:Dim])
69119
)
70120
end
71121

72122
# fill the rest with random points
73-
for i in (M + 1):N
123+
for i in setdiff(1:N, keys(algo.initialpos))
74124
startpos[i] = (startposbounds.max .- startposbounds.min) .* (2 .* rand(rng, Point{Dim,Ptype}) .- 1) .+ startposbounds.min
75125
end
76126
# iteratorstate: (#iter, energy, step, progress, old pos, stopflag)
@@ -91,7 +141,7 @@ function Base.iterate(iter::LayoutIterator{<:SFDP}, state)
91141
energy = zero(energy0)
92142
Ftype = eltype(locs)
93143
N = size(adj_matrix, 1)
94-
M = algo.fixed ? length(algo.initialpos) : 0
144+
pin = N > length(algo.pin) ? vcat(algo.pin, falses(N-length(algo.pin))) : algo.pin
95145
for i in 1:N
96146
force = zero(Ftype)
97147
for j in 1:N
@@ -106,7 +156,7 @@ function Base.iterate(iter::LayoutIterator{<:SFDP}, state)
106156
((locs[j] .- locs[i]) / norm(locs[j] .- locs[i])))
107157
end
108158
end
109-
if i > M
159+
if !pin[i]
110160
locs[i] = locs[i] .+ step .* (force ./ norm(force))
111161
end
112162
energy = energy + norm(force)^2

test/runtests.jl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ using SparseArrays: sparse
66
using Test
77

88
function jagmesh()
9-
jagmesh_path = joinpath(dirname(@__FILE__), "jagmesh1.mtx")
9+
jagmesh_path = joinpath(pkgdir(NetworkLayout), "test", "jagmesh1.mtx")
1010
array = round.(Int, open(readdlm, jagmesh_path))
1111
row = array[:, 1]
1212
col = array[:, 2]
@@ -29,6 +29,11 @@ jagmesh_adj = jagmesh()
2929
ip = [Point2f(1, 2)]
3030
algo = SFDP(; initialpos=ip)
3131
@test algo isa SFDP{2,Float32}
32+
ip = Dict(1=>Point(1.0,3.0))
33+
algo = SFDP(; initialpos = ip)
34+
@test algo isa SFDP{2, Float64}
35+
p = [Point((true, true))]
36+
algo = SFDP(; initialpos = ip, pin = p)
3237
end
3338

3439
@testset "iterator size" begin
@@ -63,7 +68,7 @@ jagmesh_adj = jagmesh()
6368
@test typeof(positions) == Vector{Point3f}
6469
@test positions == sfdp(adj_matrix; dim=3, Ptype=Float32, tol=0.1, K=1)
6570
ip = [Point2f(3.0, 1.0)]
66-
@test ip[1] == sfdp(adj_matrix; dim=3, Ptype=Float32, tol=0.1, K=1, initialpos = ip, fixed = true)[1]
71+
@test ip[1] == sfdp(adj_matrix; dim=3, Ptype=Float32, tol=0.1, K=1, initialpos = ip, pin = [true])[1]
6772
end
6873
end
6974

0 commit comments

Comments
 (0)