Skip to content

Commit

Permalink
Merge b4e2744 into 9baab74
Browse files Browse the repository at this point in the history
  • Loading branch information
vladimir-ch committed Dec 16, 2018
2 parents 9baab74 + b4e2744 commit 736b212
Show file tree
Hide file tree
Showing 8 changed files with 538 additions and 72 deletions.
141 changes: 141 additions & 0 deletions linsolve/bcgstab.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// 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 linsolve

import (
"math"

"gonum.org/v1/gonum/floats"
)

// BiCGStab implements the BiConjugate Gradient Stabilized method with
// preconditioning for solving systems of linear equations
// A*x = b,
// where A is a square, possibly nonsymmetric matrix.
//
// References:
// - Barrett, R. et al. (1994). Section 2.3.8 BiConjugate Gradient Stabilized (Bi-CGSTAB).
// In Templates for the Solution of Linear Systems: Building Blocks
// for Iterative Methods (2nd ed.) (pp. 24-25). Philadelphia, PA: SIAM.
// Retrieved from http://www.netlib.org/templates/templates.pdf
type BiCGStab struct {
p []float64
phat []float64
rt []float64
shat []float64
t []float64
v []float64

rho, rhoPrev float64
alpha float64
omega float64

first bool
resume int
}

// Init initializes the data for a linear solve. See the Method interface for more details.
func (b *BiCGStab) Init(dim int) {
if dim <= 0 {
panic("bicgstab: dimension not positive")
}

b.p = reuse(b.p, dim)
b.phat = reuse(b.phat, dim)
b.rt = reuse(b.rt, dim)
b.shat = reuse(b.shat, dim)
b.t = reuse(b.t, dim)
b.v = reuse(b.v, dim)

b.first = true
b.resume = 1
}

// Iterate performs an iteration of the linear solve. See the Method interface for more details.
//
// BiCGStab will command the following operations:
// MulVec
// PreconSolve
// CheckResidual
// MajorIteration
// NoOperation
func (b *BiCGStab) Iterate(ctx *Context) (Operation, error) {
switch b.resume {
case 1:
if b.first {
copy(b.rt, ctx.Residual)
}
b.rho = floats.Dot(b.rt, ctx.Residual)
if math.Abs(b.rho) < breakdownTol {
b.resume = 0
return NoOperation, &BreakdownError{math.Abs(b.rho), breakdownTol}
}
if b.first {
b.first = false
copy(b.p, ctx.Residual)
} else {
beta := (b.rho / b.rhoPrev) * (b.alpha / b.omega)
floats.AddScaled(b.p, -b.omega, b.v)
floats.Scale(beta, b.p)
floats.Add(b.p, ctx.Residual)
}
// Solve M^{-1} * p_i.
copy(ctx.Src, b.p)
b.resume = 2
return PreconSolve, nil
case 2:
copy(b.phat, ctx.Dst)
// Compute A * \hat{p}_i.
copy(ctx.Src, b.phat)
b.resume = 3
return MulVec, nil
case 3:
copy(b.v, ctx.Dst)
rtv := floats.Dot(b.rt, b.v)
if rtv == 0 {
b.resume = 0
return NoOperation, &BreakdownError{}
}
b.alpha = b.rho / rtv
// Form the residual and X so that we can check for tolerance early.
floats.AddScaled(ctx.X, b.alpha, b.phat)
floats.AddScaled(ctx.Residual, -b.alpha, b.v)
b.resume = 4
return CheckResidual, nil
case 4:
if ctx.Converged {
b.resume = 0
return MajorIteration, nil
}
// Solve M^{-1} * r_i.
copy(ctx.Src, ctx.Residual)
b.resume = 5
return PreconSolve, nil
case 5:
copy(b.shat, ctx.Dst)
// Compute A * \hat{s}_i.
copy(ctx.Src, b.shat)
b.resume = 6
return MulVec, nil
case 6:
copy(b.t, ctx.Dst)
b.omega = floats.Dot(b.t, ctx.Residual) / floats.Dot(b.t, b.t)
floats.AddScaled(ctx.X, b.omega, b.shat)
floats.AddScaled(ctx.Residual, -b.omega, b.t)
b.resume = 7
return CheckResidual, nil
case 7:
if !ctx.Converged && math.Abs(b.omega) < breakdownTol {
b.resume = 0
return NoOperation, &BreakdownError{math.Abs(b.omega), breakdownTol}
}
b.rhoPrev = b.rho
b.resume = 1
return MajorIteration, nil

default:
panic("bicgstab: Init not called")
}
}
120 changes: 120 additions & 0 deletions linsolve/bicg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// 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 linsolve

import (
"math"

"gonum.org/v1/gonum/floats"
)

// BiCG implements the Bi-Conjugate Gradient method with
// preconditioning for solving systems of linear equations
// A*x = b,
// where A is a square, possibly nonsymmetric matrix.
//
// References:
// - Barrett, R. et al. (1994). Section 2.3.5 BiConjugate Gradient (BiCG).
// In Templates for the Solution of Linear Systems: Building Blocks
// for Iterative Methods (2nd ed.) (pp. 19-20). Philadelphia, PA: SIAM.
// Retrieved from http://www.netlib.org/templates/templates.pdf
type BiCG struct {
p, pt []float64
rt []float64
z, zt []float64

rho, rhoPrev float64

first bool
resume int
}

// Init initializes the data for a linear solve. See the Method interface for more details.
func (b *BiCG) Init(dim int) {
if dim <= 0 {
panic("bicg: dimension not positive")
}

b.p = reuse(b.p, dim)
b.pt = reuse(b.pt, dim)
b.rt = reuse(b.rt, dim)
b.z = reuse(b.z, dim)
b.zt = reuse(b.zt, dim)

b.first = true
b.resume = 1
}

// Iterate performs an iteration of the linear solve. See the Method interface for more details.
//
// BiCG will command the following operations:
// MulVec
// MulVec|Trans
// PreconSolve
// PreconSolve|Trans
// CheckResidual
// MajorIteration
// NoOperation
func (b *BiCG) Iterate(ctx *Context) (Operation, error) {
switch b.resume {
case 1:
if b.first {
copy(b.rt, ctx.Residual)
}
// Solve M^{-1} * r_{i-1}.
copy(ctx.Src, ctx.Residual)
b.resume = 2
return PreconSolve, nil
case 2:
copy(b.z, ctx.Dst)
// Solve M^{-T} * rt_{i-1}.
copy(ctx.Src, b.rt)
b.resume = 3
return PreconSolve | Trans, nil
case 3:
copy(b.zt, ctx.Dst)
b.rho = floats.Dot(b.z, b.rt)
if math.Abs(b.rho) < breakdownTol {
b.resume = 0
return NoOperation, &BreakdownError{math.Abs(b.rho), breakdownTol}
}
if b.first {
copy(b.p, b.z)
copy(b.pt, b.zt)
} else {
beta := b.rho / b.rhoPrev
floats.AddScaledTo(b.p, b.z, beta, b.p)
floats.AddScaledTo(b.pt, b.zt, beta, b.pt)
}
// Compute A * p.
copy(ctx.Src, b.p)
b.resume = 4
return MulVec, nil
case 4:
// z is overwritten and reused.
copy(b.z, ctx.Dst)
// Compute A^T * pt.
copy(ctx.Src, b.pt)
b.resume = 5
return MulVec | Trans, nil
case 5:
// zt is overwritten and reused.
copy(b.zt, ctx.Dst)
alpha := b.rho / floats.Dot(b.pt, b.z)
floats.AddScaled(b.rt, -alpha, b.zt)
floats.AddScaled(ctx.X, alpha, b.p)
floats.AddScaled(ctx.Residual, -alpha, b.z)
b.resume = 6
return CheckResidual, nil
case 6:
b.rhoPrev = b.rho
b.first = false
b.resume = 1
return MajorIteration, nil

default:
panic("bicg: Init not called")
}
}
12 changes: 7 additions & 5 deletions linsolve/cg.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ import (
// - Málek, J. and Strakoš, Z. (2015). Preconditioning and the Conjugate Gradient
// Method in the Context of Solving PDEs. Philadelphia, PA: SIAM.
type CG struct {
rho, rhoPrev float64

p []float64

rho, rhoPrev float64

first bool
resume int
}

// Init implements the Method interface.
// Init initializes the data for a linear solve. See the Method interface for more details.
func (cg *CG) Init(dim int) {
if dim <= 0 {
panic("cg: dimension not positive")
Expand All @@ -43,10 +43,12 @@ func (cg *CG) Init(dim int) {
cg.resume = 1
}

// Iterate implements the Method interface. It will command the following
// operations:
// Iterate performs an iteration of the linear solve. See the Method interface for more details.
//
// CG will command the following operations:
// MulVec
// PreconSolve
// CheckResidual
// MajorIteration
func (cg *CG) Iterate(ctx *Context) (Operation, error) {
switch cg.resume {
Expand Down
37 changes: 20 additions & 17 deletions linsolve/gmres.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,8 @@ type GMRES struct {
// a problem-dependent value less than n.
Restart int

m int
s []float64
y []float64
av []float64

// m is the used value of Restart.
m int
// vt is an (m+1)×n matrix. It corresponds to V^T in
// standard descriptions of GMRES. Its rows form an orthonormal basis of the
// Krylov subspace.
Expand All @@ -54,6 +51,10 @@ type GMRES struct {
// upper-triangular form.
givs []givens

av []float64
s []float64
y []float64

k int // Loop variable for inner iterations.
resume int
}
Expand All @@ -63,13 +64,7 @@ type givens struct {
c, s float64
}

// Init implements the Method interface. It will command the following
// operations:
// MulVec
// PreconSolve
// CheckResidualNorm
// ComputeResidual
// MajorIteration
// Init initializes the data for a linear solve. See the Method interface for more details.
func (g *GMRES) Init(dim int) {
if dim <= 0 {
panic("gmres: dimension not positive")
Expand All @@ -83,10 +78,6 @@ func (g *GMRES) Init(dim int) {
panic("gmres: invalid value of Restart")
}

g.s = reuse(g.s, g.m+1)
g.y = reuse(g.y, dim)
g.av = reuse(g.av, dim)

ldv := dim
g.vt = reuse(g.vt, (g.m+1)*ldv)
ldh := g.m + 1
Expand All @@ -102,10 +93,22 @@ func (g *GMRES) Init(dim int) {
}
}

g.s = reuse(g.s, g.m+1)
g.y = reuse(g.y, dim)
g.av = reuse(g.av, dim)

g.resume = 1
}

// Iterate implements the Method interface.
// Iterate performs an iteration of the linear solve. See the Method interface for more details.
//
// GMRES will command the following operations:
// MulVec
// PreconSolve
// CheckResidualNorm
// ComputeResidual
// MajorIteration
// NoOperation
func (g *GMRES) Iterate(ctx *Context) (Operation, error) {
switch g.resume {
case 1:
Expand Down
6 changes: 3 additions & 3 deletions linsolve/iterative.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func defaultSettings(s *Settings, dim int) {
s.Tolerance = defaultTolerance
}
if s.MaxIterations == 0 {
s.MaxIterations = 2 * dim
s.MaxIterations = 4 * dim
}
if s.PreconSolve == nil {
s.PreconSolve = NoPreconditioner
Expand Down Expand Up @@ -233,10 +233,10 @@ func iterate(a MulVecToer, b []float64, settings Settings, method Method, stats

switch op {
case NoOperation:
case MulVec:
case MulVec, MulVec | Trans:
stats.MulVec++
a.MulVecTo(ctx.Dst, op&Trans == Trans, ctx.Src)
case PreconSolve:
case PreconSolve, PreconSolve | Trans:
stats.PreconSolve++
err = settings.PreconSolve(ctx.Dst, op&Trans == Trans, ctx.Src)
if err != nil {
Expand Down

0 comments on commit 736b212

Please sign in to comment.