@@ -86,13 +86,6 @@ function Stress(; dim=2, Ptype=Float64, iterations=:auto, abstols=(√(eps(Float
86
86
Stress {dim,Ptype,IT,FT,WT} (iterations, abstols, reltols, abstolx, weights, initialpos, seed)
87
87
end
88
88
89
- function initialweights (D, T):: SparseMatrixCSC{T,Int64}
90
- map (D) do d
91
- x = T (d^ (- 2.0 ))
92
- return isfinite (x) ? x : zero (T)
93
- end
94
- end
95
-
96
89
function Base. iterate (iter:: LayoutIterator{<:Stress{Dim,Ptype,IT,FT}} ) where {Dim,Ptype,IT,FT}
97
90
algo, δ = iter. algorithm, iter. adj_matrix
98
91
N = size (δ, 1 )
@@ -109,45 +102,46 @@ function Base.iterate(iter::LayoutIterator{<:Stress{Dim,Ptype,IT,FT}}) where {Di
109
102
end
110
103
111
104
# calculate iteration if :auto
112
- maxiter = algo. iterations === :auto ? 400 * size (δ, 1 ) ^ 2 : algo. iterations
105
+ maxiter = algo. iterations === :auto ? 400 * N ^ 2 : algo. iterations
113
106
@assert maxiter > 0 " Iterations need to be > 0"
114
107
115
108
# if user provided weights not empty try those
116
- weights = isempty (algo. weights) ? initialweights (δ, FT) : algo. weights
109
+ make_symmetric! (δ)
110
+ distances = pairwise_distance (δ, FT)
111
+ weights = isempty (algo. weights) ? distances .^ (- 2 ) : algo. weights
117
112
118
113
@assert length (startpos) == size (δ, 1 ) == size (δ, 2 ) == size (weights, 1 ) == size (weights, 2 ) " Wrong size of weights?"
119
114
120
115
Lw = weightedlaplacian (weights)
121
116
pinvLw = pinv (Lw)
122
- s = stress (startpos, δ , weights)
117
+ oldstress = stress (startpos, distances , weights)
123
118
124
- # the `state` of the iterator is (#iter, old stress, old pos, weights, pinvLw, stopflag)
125
- return startpos, (1 , s , startpos, weights, pinvLw, maxiter, false )
119
+ # the `state` of the iterator is (#iter, old stress, old pos, weights, distances pinvLw, stopflag)
120
+ return startpos, (1 , oldstress , startpos, weights, distances , pinvLw, maxiter, false )
126
121
end
127
122
128
123
function Base. iterate (iter:: LayoutIterator{<:Stress{Dim,Ptype}} , state) where {Dim,Ptype}
129
124
algo, δ = iter. algorithm, iter. adj_matrix
130
- i, oldstress, oldpos, weights, pinvLw, maxiter, stopflag = state
131
- # newstress, oldstress, X0, i = state
125
+ i, oldstress, oldpos, weights, distances, pinvLw, maxiter, stopflag = state
132
126
133
127
if i >= maxiter || stopflag
134
128
return nothing
135
129
end
136
130
137
131
# TODO the faster way is to drop the first row and col from the iteration
138
- t = LZ (oldpos, δ , weights)
132
+ t = LZ (oldpos, distances , weights)
139
133
positions = similar (oldpos) # allocate new array but keep type of oldpos
140
134
mul! (positions, pinvLw, (t * oldpos))
141
135
@assert all (x -> all (map (isfinite, x)), positions)
142
- newstress = stress (positions, δ , weights)
136
+ newstress = stress (positions, distances , weights)
143
137
144
138
if abs (newstress - oldstress) < algo. reltols * newstress ||
145
139
abs (newstress - oldstress) < algo. abstols ||
146
140
norm (positions - oldpos) < algo. abstolx
147
141
stopflag = true
148
142
end
149
143
150
- return positions, (i + 1 , newstress, positions, weights, pinvLw, maxiter, stopflag)
144
+ return positions, (i + 1 , newstress, positions, weights, distances, pinvLw, maxiter, stopflag)
151
145
end
152
146
153
147
"""
@@ -160,8 +154,7 @@ Input:
160
154
161
155
See (1) of Reference
162
156
"""
163
- function stress (positions:: AbstractArray{Point{T,N}} , d= ones (T, length (positions), length (positions)),
164
- weights= initialweights (d, T)) where {T,N}
157
+ function stress (positions:: AbstractArray{Point{T,N}} , d, weights) where {T,N}
165
158
s = zero (T)
166
159
n = length (positions)
167
160
@assert n == size (d, 1 ) == size (d, 2 ) == size (weights, 1 ) == size (weights, 2 )
196
189
Computes L^Z defined in (5) of the Reference
197
190
198
191
Input: Z: current layout (coordinates)
199
- d: Ideal distances (default: all 1)
200
- weights: weights (default: d.^-2)
192
+ d: Ideal distances
193
+ weights: weights
201
194
"""
202
195
function LZ (Z:: AbstractVector{Point{N,T}} , d, weights) where {N,T}
203
196
n = length (Z)
@@ -217,3 +210,32 @@ function LZ(Z::AbstractVector{Point{N,T}}, d, weights) where {N,T}
217
210
end
218
211
return L
219
212
end
213
+
214
+ """
215
+ pairwise_distance(δ)
216
+
217
+ Calculate the pairwise distances of a the graph from a adjacency matrix
218
+ using the Floyd-Warshall algorithm.
219
+
220
+ https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm
221
+ """
222
+ function pairwise_distance (δ, :: Type{T} = Float64) where {T}
223
+ N = size (δ, 1 )
224
+ d = Matrix {T} (undef, N, N)
225
+ @inbounds for j in 1 : N, i in 1 : N
226
+ if i == j
227
+ d[i, j] = zero (eltype (d))
228
+ elseif iszero (δ[i, j])
229
+ d[i, j] = typemax (eltype (d))
230
+ else
231
+ d[i, j] = δ[i, j]
232
+ end
233
+ end
234
+
235
+ @inbounds for k in 1 : N, i in 1 : N, j in 1 : N
236
+ if d[i, k] + d[k, j] < d[i, j]
237
+ d[i, j] = d[i, k] + d[k, j]
238
+ end
239
+ end
240
+ return d
241
+ end
0 commit comments