Files
gonum/graph/network/diffusion.go
Dan Kortschak 5f0141ca4c all: run gofmt and generate all packages
Changes made in dsp/fourier/internal/fftpack break the formatting used
there, so these are reverted. There will be complaints in CI.

[git-generate]
gofmt -w .
go generate gonum.org/v1/gonum/blas
go generate gonum.org/v1/gonum/blas/gonum
go generate gonum.org/v1/gonum/unit
go generate gonum.org/v1/gonum/unit/constant
go generate gonum.org/v1/gonum/graph/formats/dot
go generate gonum.org/v1/gonum/graph/formats/rdf
go generate gonum.org/v1/gonum/stat/card

git checkout -- dsp/fourier/internal/fftpack
2022-08-06 07:05:17 +09:30

99 lines
2.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright ©2017 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 network
import (
"gonum.org/v1/gonum/graph/spectral"
"gonum.org/v1/gonum/mat"
)
// Diffuse performs a heat diffusion across nodes of the undirected
// graph described by the given Laplacian using the initial heat distribution,
// h, according to the Laplacian with a diffusion time of t.
// The resulting heat distribution is returned, written into the map dst and
// returned,
//
// d = exp(-Lt)×h
//
// where L is the graph Laplacian. Indexing into h and dst is defined by the
// Laplacian Index field. If dst is nil, a new map is created.
//
// Nodes without corresponding entries in h are given an initial heat of zero,
// and entries in h without a corresponding node in the original graph are
// not altered when written to dst.
func Diffuse(dst, h map[int64]float64, by spectral.Laplacian, t float64) map[int64]float64 {
heat := make([]float64, len(by.Index))
for id, i := range by.Index {
heat[i] = h[id]
}
v := mat.NewVecDense(len(heat), heat)
var m, tl mat.Dense
tl.Scale(-t, by)
m.Exp(&tl)
v.MulVec(&m, v)
if dst == nil {
dst = make(map[int64]float64)
}
for i, n := range heat {
dst[by.Nodes[i].ID()] = n
}
return dst
}
// DiffuseToEquilibrium performs a heat diffusion across nodes of the
// graph described by the given Laplacian using the initial heat
// distribution, h, according to the Laplacian until the update function
//
// h_{n+1} = h_n - L×h_n
//
// results in a 2-norm update difference within tol, or iters updates have
// been made.
// The resulting heat distribution is returned as eq, written into the map dst,
// and a boolean indicating whether the equilibrium converged to within tol.
// Indexing into h and dst is defined by the Laplacian Index field. If dst
// is nil, a new map is created.
//
// Nodes without corresponding entries in h are given an initial heat of zero,
// and entries in h without a corresponding node in the original graph are
// not altered when written to dst.
func DiffuseToEquilibrium(dst, h map[int64]float64, by spectral.Laplacian, tol float64, iters int) (eq map[int64]float64, ok bool) {
heat := make([]float64, len(by.Index))
for id, i := range by.Index {
heat[i] = h[id]
}
v := mat.NewVecDense(len(heat), heat)
last := make([]float64, len(by.Index))
for id, i := range by.Index {
last[i] = h[id]
}
lastV := mat.NewVecDense(len(last), last)
var tmp mat.VecDense
for {
iters--
if iters < 0 {
break
}
lastV, v = v, lastV
tmp.MulVec(by.Matrix, lastV)
v.SubVec(lastV, &tmp)
if normDiff(heat, last) < tol {
ok = true
break
}
}
if dst == nil {
dst = make(map[int64]float64)
}
for i, n := range v.RawVector().Data {
dst[by.Nodes[i].ID()] = n
}
return dst, ok
}