@@ -23,52 +23,59 @@ the nodes.
23
23
- `initialtemp=2.0`: Initial "temperature", controls movement per iteration
24
24
- `initialpos=Point{dim,Ptype}[]`
25
25
26
- Provide list of initial positions. If length does not match Network size the initial
27
- positions will be truncated or filled up with random values between [-1,1] in every coordinate.
26
+ Provide `Vector` or `Dict` of initial positions. All positions will be initialized
27
+ using random coordinates between [-1,1]. Random positions will be overwritten using
28
+ the key-val-pairs provided by this argument.
29
+
30
+ - `pin=[]`: Pin node positions (won't be updated). Can be given as `Vector` or `Dict`
31
+ of node index -> value pairings. Values can be either
32
+ - `(12, 4.0)` : overwrite initial position and pin
33
+ - `true/false` : pin this position
34
+ - `(true, false, false)` : only pin certain coordinates
28
35
29
36
- `seed=1`: Seed for random initial positions.
30
37
"""
31
38
@addcall struct Spring{Dim,Ptype} <: IterativeLayout{Dim,Ptype}
32
39
C:: Float64
33
40
iterations:: Int
34
41
initialtemp:: Float64
35
- initialpos:: Vector{Point{Dim,Ptype}}
42
+ initialpos:: Dict{Int,Point{Dim,Ptype}}
43
+ pin:: Dict{Int,SVector{Dim,Bool}}
36
44
seed:: UInt
37
45
end
38
46
39
- function Spring (; dim= 2 , Ptype= Float64, C= 2.0 , iterations= 100 , initialtemp= 2.0 , initialpos= Point{dim,Ptype}[],
47
+ function Spring (; dim= 2 , Ptype= Float64,
48
+ C= 2.0 , iterations= 100 , initialtemp= 2.0 ,
49
+ initialpos= [], pin= [],
40
50
seed= 1 )
41
51
if ! isempty (initialpos)
42
- initialpos = Point .(initialpos)
43
- Ptype = eltype (eltype (initialpos))
44
- # TODO fix initial pos if list has points of multiple types
45
- Ptype == Any && error (" Please provide list of Point{N,T} with same T" )
46
- dim = length (eltype (initialpos))
52
+ dim, Ptype = infer_pointtype (initialpos)
53
+ Ptype = promote_type (Float32, Ptype) # make sure to get at least f32 if given as int
47
54
end
48
- return Spring {dim,Ptype} (C, iterations, initialtemp, initialpos, seed)
55
+ _initialpos, _pin = _sanitize_initialpos_pin (dim, Ptype, initialpos, pin)
56
+
57
+ return Spring {dim,Ptype} (C, iterations, initialtemp, _initialpos, _pin, seed)
49
58
end
50
59
51
60
function Base. iterate (iter:: LayoutIterator{<:Spring{Dim,Ptype}} ) where {Dim,Ptype}
52
61
algo, adj_matrix = iter. algorithm, iter. adj_matrix
53
62
N = size (adj_matrix, 1 )
54
- M = length (algo. initialpos)
55
63
rng = MersenneTwister (algo. seed)
56
- startpos = Vector {Point{Dim,Ptype}} (undef, N)
57
- # take the first
58
- for i in 1 : min (N, M)
59
- startpos[i] = algo. initialpos[i]
60
- end
61
- # fill the rest with random points
62
- for i in (M + 1 ): N
63
- startpos[i] = 2 .* rand (rng, Point{Dim,Ptype}) .- 1
64
+ startpos = [2 .* rand (rng, Point{Dim,Ptype}) .- 1 for _ in 1 : N]
65
+
66
+ for (k, v) in algo. initialpos
67
+ startpos[k] = v
64
68
end
65
- # iteratorstate: #iter nr, old pos
66
- return (startpos, (1 , startpos))
69
+
70
+ pin = [get (algo. pin, i, SVector {Dim,Bool} (false for _ in 1 : Dim)) for i in 1 : N]
71
+
72
+ # iteratorstate: #iter nr, old pos, pin
73
+ return (startpos, (1 , startpos, pin))
67
74
end
68
75
69
76
function Base. iterate (iter:: LayoutIterator{<:Spring} , state)
70
77
algo, adj_matrix = iter. algorithm, iter. adj_matrix
71
- iteration, old_pos = state
78
+ iteration, old_pos, pin = state
72
79
iteration >= algo. iterations && return nothing
73
80
74
81
# The optimal distance bewteen vertices
@@ -108,8 +115,10 @@ function Base.iterate(iter::LayoutIterator{<:Spring}, state)
108
115
force_mag = norm (force[i])
109
116
iszero (force_mag) && continue
110
117
scale = min (force_mag, temp) ./ force_mag
111
- locs[i] += force[i] .* scale
118
+
119
+ mask = (! ). (pin[i]) # where pin=true mask will multiply with 0
120
+ locs[i] += force[i] .* scale .* mask
112
121
end
113
122
114
- return locs, (iteration + 1 , locs)
123
+ return locs, (iteration + 1 , locs, pin )
115
124
end
0 commit comments