mirror of
https://github.com/gonum/gonum.git
synced 2025-10-08 08:30:14 +08:00
64 lines
1.8 KiB
Go
64 lines
1.8 KiB
Go
// Copyright ©2019 The Gonum Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package layout
|
|
|
|
import (
|
|
"gonum.org/v1/gonum/graph"
|
|
"gonum.org/v1/gonum/graph/path"
|
|
"gonum.org/v1/gonum/mat"
|
|
"gonum.org/v1/gonum/spatial/r2"
|
|
"gonum.org/v1/gonum/stat/mds"
|
|
)
|
|
|
|
// IsomapR2 implements a graph layout algorithm based on the Isomap
|
|
// non-linear dimensionality reduction method. Coordinates of nodes
|
|
// are computed by finding a Torgerson multidimensional scaling of
|
|
// the shortest path distances between all pairs of node in the graph.
|
|
// The all pair shortest path distances are calculated using the
|
|
// Floyd-Warshall algorithm and so IsomapR2 will not scale to large
|
|
// graphs. Graphs with more than one connected component cannot be
|
|
// laid out by IsomapR2.
|
|
type IsomapR2 struct{}
|
|
|
|
// Update is the IsomapR2 spatial graph update function.
|
|
func (IsomapR2) Update(g graph.Graph, layout LayoutR2) bool {
|
|
nodes := graph.NodesOf(g.Nodes())
|
|
v := isomap(g, nodes, 2)
|
|
if v == nil {
|
|
return false
|
|
}
|
|
|
|
// FIXME(kortschak): The Layout types do not have the capacity to
|
|
// be cleared in the current API. Is this a problem? I don't know
|
|
// at this stage. It might be if the layout is reused between graphs.
|
|
// Someone may do this.
|
|
|
|
for i, n := range nodes {
|
|
layout.SetCoord2(n.ID(), r2.Vec{X: v.At(i, 0), Y: v.At(i, 1)})
|
|
}
|
|
return false
|
|
}
|
|
|
|
func isomap(g graph.Graph, nodes []graph.Node, dims int) *mat.Dense {
|
|
p, ok := path.FloydWarshall(g)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
dist := mat.NewSymDense(len(nodes), nil)
|
|
for i, u := range nodes {
|
|
for j, v := range nodes {
|
|
dist.SetSym(i, j, p.Weight(u.ID(), v.ID()))
|
|
}
|
|
}
|
|
|
|
k, v, _ := mds.TorgersonScaling(nil, nil, dist)
|
|
if k < dims {
|
|
return nil
|
|
}
|
|
|
|
return v
|
|
}
|