github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/graph/layout/isomap.go (about)

     1  // Copyright ©2019 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package layout
     6  
     7  import (
     8  	"github.com/jingcheng-WU/gonum/graph"
     9  	"github.com/jingcheng-WU/gonum/graph/path"
    10  	"github.com/jingcheng-WU/gonum/mat"
    11  	"github.com/jingcheng-WU/gonum/spatial/r2"
    12  	"github.com/jingcheng-WU/gonum/stat/mds"
    13  )
    14  
    15  // IsomapR2 implements a graph layout algorithm based on the Isomap
    16  // non-linear dimensionality reduction method. Coordinates of nodes
    17  // are computed by finding a Torgerson multidimensional scaling of
    18  // the shortest path distances between all pairs of node in the graph.
    19  // The all pair shortest path distances are calculated using the
    20  // Floyd-Warshall algorithm and so IsomapR2 will not scale to large
    21  // graphs. Graphs with more than one connected component cannot be
    22  // laid out by IsomapR2.
    23  type IsomapR2 struct{}
    24  
    25  // Update is the IsomapR2 spatial graph update function.
    26  func (IsomapR2) Update(g graph.Graph, layout LayoutR2) bool {
    27  	nodes := graph.NodesOf(g.Nodes())
    28  	v := isomap(g, nodes, 2)
    29  	if v == nil {
    30  		return false
    31  	}
    32  
    33  	// FIXME(kortschak): The Layout types do not have the capacity to
    34  	// be cleared in the current API. Is this a problem? I don't know
    35  	// at this stage. It might be if the layout is reused between graphs.
    36  	// Someone may do this.
    37  
    38  	for i, n := range nodes {
    39  		layout.SetCoord2(n.ID(), r2.Vec{X: v.At(i, 0), Y: v.At(i, 1)})
    40  	}
    41  	return false
    42  }
    43  
    44  func isomap(g graph.Graph, nodes []graph.Node, dims int) *mat.Dense {
    45  	p, ok := path.FloydWarshall(g)
    46  	if !ok {
    47  		return nil
    48  	}
    49  
    50  	dist := mat.NewSymDense(len(nodes), nil)
    51  	for i, u := range nodes {
    52  		for j, v := range nodes {
    53  			dist.SetSym(i, j, p.Weight(u.ID(), v.ID()))
    54  		}
    55  	}
    56  	var v mat.Dense
    57  	k, _ := mds.TorgersonScaling(&v, nil, dist)
    58  	if k < dims {
    59  		return nil
    60  	}
    61  
    62  	return &v
    63  }