quad.form()
et seqIn versions prior to 1.2-19, the emulator package included a serious
bug in the quad.form()
family of functions in which the
complex conjugate of the correct answer was returned (which did not
matter in my usual use-case because my matrices were Hermitian). This
short vignette demonstrates that the bug has been fixed. Note that the
fix was considerably more complicated than simply returning the complex
conjugate of the old functions’ value, which would have been terribly
inefficient. The actual fix avoids taking more conjugates than
absolutely necessary. The vignette checks all the functions in the
series, including the ones that have not been changed such as
quad.form.inv()
. First load the package:
library("emulator")
We need a helper function to create random complex matrices (NB: we
cannot use the cmvnorm
package because that depends on the
emulator
package):
rcm <- function(row,col){
matrix(rnorm(row*col)+1i*rnorm(row*col),row,col)
}
Then use this function to define a square matrix M
with
complex entries (NB: not Hermitian!), and a couple of rectangular
matrices, also complex:
rcm <- function(row,col){matrix(rnorm(row*col)+1i*rnorm(row*col),row,col)}
M <- rcm(2,2)
x <- rcm(2,3)
y <- rcm(3,2)
x1 <- rcm(2,3)
y1 <- rcm(3,2)
Set up a numerical tester function:
tester <- function(a,b,TOL=1e-13){stopifnot(all(abs(a-b)< TOL))}
(previous versions used a tolerance of 1e-15
, which was
occasionally not met). Now test each function:
ht(x)
= \(x^*\) = \(\overline{x'}\) (Hermitian
transpose):ht(x)=t(Conj(x))
(jj1 <- Conj(t(x)))
#> [,1] [,2]
#> [1,] -0.204576-0.640419i -1.4525117-0.9493113i
#> [2,] -2.153785-0.188260i -0.7882761+0.7939511i
#> [3,] -0.613245+1.024112i -0.7938764+2.7810537i
(jj2 <- t(Conj(x)))
#> [,1] [,2]
#> [1,] -0.204576-0.640419i -1.4525117-0.9493113i
#> [2,] -2.153785-0.188260i -0.7882761+0.7939511i
#> [3,] -0.613245+1.024112i -0.7938764+2.7810537i
(jj3 <- ht(x))
#> [,1] [,2]
#> [1,] -0.204576-0.640419i -1.4525117-0.9493113i
#> [2,] -2.153785-0.188260i -0.7882761+0.7939511i
#> [3,] -0.613245+1.024112i -0.7938764+2.7810537i
tester(jj1,jj3)
tester(jj2,jj3)
cprod()
= \(x^*y\):cprod(x,y)=crossprod(Conj(x),y)
(jj1 <- ht(x) %*% x1)
#> [,1] [,2] [,3]
#> [1,] 1.029839-0.394071i 0.0195763+0.4164957i -3.052500+2.970614i
#> [2,] -3.076731+1.438518i 1.7931570-1.4349116i -0.134602+2.195432i
#> [3,] -0.117493-1.305357i 0.0556772-0.2328632i 6.541921+3.729678i
(jj2 <- cprod(x,x1))
#> [,1] [,2] [,3]
#> [1,] 1.029839-0.394071i 0.0195763+0.4164957i -3.052500+2.970614i
#> [2,] -3.076731+1.438518i 1.7931570-1.4349116i -0.134602+2.195432i
#> [3,] -0.117493-1.305357i 0.0556772-0.2328632i 6.541921+3.729678i
tester(jj1,jj2)
tcprod()
= \(x
y^*\):tcprod(x,y)=crossprod(x,Conj(y))
(jj1 <- ht(x1) %*% x)
#> [,1] [,2] [,3]
#> [1,] 1.0298385+0.3940714i -3.076731-1.438518i -0.1174925+1.3053575i
#> [2,] 0.0195763-0.4164957i 1.793157+1.434912i 0.0556772+0.2328632i
#> [3,] -3.0525005-2.9706144i -0.134602-2.195432i 6.5419211-3.7296778i
(jj2 <- cprod(x1,x))
#> [,1] [,2] [,3]
#> [1,] 1.0298385+0.3940714i -3.076731-1.438518i -0.1174925+1.3053575i
#> [2,] 0.0195763-0.4164957i 1.793157+1.434912i 0.0556772+0.2328632i
#> [3,] -3.0525005-2.9706144i -0.134602-2.195432i 6.5419211-3.7296778i
tester(jj1,jj2)
quad.form()
= \(x^*Mx\):quad.form(M,x)=crossprod(crossprod(M,Conj(x)),x))
(jj1 <- ht(x) %*% M %*% x)
#> [,1] [,2] [,3]
#> [1,] -0.361280-1.642215i 1.317059+1.932716i 2.265098-0.183945i
#> [2,] -2.598642+1.800000i 3.086616+0.822312i -2.943405-4.593919i
#> [3,] -1.780870+1.316800i 2.353631-3.665747i -1.385598-2.269765i
(jj2 <- quad.form(M,x))
#> [,1] [,2] [,3]
#> [1,] -0.361280-1.642215i 1.317059+1.932716i 2.265098-0.183945i
#> [2,] -2.598642+1.800000i 3.086616+0.822312i -2.943405-4.593919i
#> [3,] -1.780870+1.316800i 2.353631-3.665747i -1.385598-2.269765i
tester(jj1,jj2)
quad.form.inv()
= \(x^*M^{-1}x\):quad.form.inv(M,x)=cprod(x,solve(M,x))
(jj1 <- ht(x) %*% solve(M) %*% x)
#> [,1] [,2] [,3]
#> [1,] 3.301444+4.444975i -1.965104+1.331585i -8.531962+ 3.411522i
#> [2,] 6.952041-3.592892i 3.061049+1.989404i 2.684448+13.213309i
#> [3,] 4.284159-7.747642i 2.698008+1.872862i 10.743977+10.076370i
(jj2 <- quad.form(solve(M),x))
#> [,1] [,2] [,3]
#> [1,] 3.301444+4.444975i -1.965104+1.331585i -8.531962+ 3.411522i
#> [2,] 6.952041-3.592892i 3.061049+1.989404i 2.684448+13.213309i
#> [3,] 4.284159-7.747642i 2.698008+1.872862i 10.743977+10.076370i
max(abs(jj1-jj2))
#> [1] 0
quad.3form()
= \(x^*My\):quad.3form(M,l,r)=crossprod(crossprod(M,Conj(l)),r)
(jj1 <- ht(x) %*% M %*% x1)
#> [,1] [,2] [,3]
#> [1,] -2.757785-3.661513i 1.717177+1.465892i 3.355718-0.945156i
#> [2,] -9.449372+2.931895i 4.294998-2.030691i -2.034164-9.085500i
#> [3,] -2.763455+7.175352i 0.624385-3.836955i -4.109222-3.118393i
(jj2 <- quad.3form(M,x,x1))
#> [,1] [,2] [,3]
#> [1,] -2.757785-3.661513i 1.717177+1.465892i 3.355718-0.945156i
#> [2,] -9.449372+2.931895i 4.294998-2.030691i -2.034164-9.085500i
#> [3,] -2.763455+7.175352i 0.624385-3.836955i -4.109222-3.118393i
tester(jj1,jj2)
quad.3tform()
= \(xMy^*\):quad.3tform(M,l,r)=tcrossprod(left,tcrossprod(Conj(right),M))
(jj1 <- y %*% M %*% ht(y1))
#> [,1] [,2] [,3]
#> [1,] 2.259877+5.817718i 0.322623-4.214798i 10.124807-0.885336i
#> [2,] 4.371737+0.802188i -1.599502-0.621855i -2.984204-5.842088i
#> [3,] -3.934572+3.925103i 2.347600-0.779937i 5.252914+2.317635i
(jj2 <- quad.3tform(M,y,y1))
#> [,1] [,2] [,3]
#> [1,] 2.259877+5.817718i 0.322623-4.214798i 10.124807-0.885336i
#> [2,] 4.371737+0.802188i -1.599502-0.621855i -2.984204-5.842088i
#> [3,] -3.934572+3.925103i 2.347600-0.779937i 5.252914+2.317635i
tester(jj1,jj2)
quad.tform()
= \(xMx^*\):quad.tform(M,x)=tcrossprod(x,tcrossprod(Conj(x),M))
(jj1 <- y %*% M %*% ht(y))
#> [,1] [,2] [,3]
#> [1,] 9.737195-4.998527i -0.2167237-2.6083911i -4.818669-2.121937i
#> [2,] -2.394459-7.490901i 0.2953538+0.0874635i -2.368207+1.201750i
#> [3,] 8.017339+3.448196i 0.7731700+0.3924916i 0.652498-3.840184i
(jj2 <- quad.tform(M,y))
#> [,1] [,2] [,3]
#> [1,] 9.737195-4.998527i -0.2167237-2.6083911i -4.818669-2.121937i
#> [2,] -2.394459-7.490901i 0.2953538+0.0874635i -2.368207+1.201750i
#> [3,] 8.017339+3.448196i 0.7731700+0.3924916i 0.652498-3.840184i
tester(jj1,jj2)
quad.tform.inv()
= \(xM^{-1}x^*\):quad.tform.inv(M,x)=quad.form.inv(M,ht(x))
(jj1 <- y %*% solve(M) %*% ht(y))
#> [,1] [,2] [,3]
#> [1,] 0.70258+10.80578i 0.531841+4.672058i 7.649395-2.749588i
#> [2,] 1.55894+10.05695i 2.189819+1.477317i 4.120047-3.688441i
#> [3,] -12.99446- 1.68843i -3.470249+1.353259i 2.556249+7.365396i
(jj2 <- quad.tform.inv(M,y))
#> [,1] [,2] [,3]
#> [1,] 0.70258+10.80578i 0.531841+4.672058i 7.649395-2.749588i
#> [2,] 1.55894+10.05695i 2.189819+1.477317i 4.120047-3.688441i
#> [3,] -12.99446- 1.68843i -3.470249+1.353259i 2.556249+7.365396i
tester(jj1,jj2)
quad.diag()
= \(\operatorname{diag}(x^*Mx)\) =
diag(quad.form())
:quad.diag(M,x)=colSums(crossprod(M,Conj(x)) * x)
(jj1 <- diag(ht(x) %*% M %*% x))
#> [1] -0.361280-1.642215i 3.086616+0.822312i -1.385598-2.269765i
(jj2 <- diag(quad.form(M,x)))
#> [1] -0.361280-1.642215i 3.086616+0.822312i -1.385598-2.269765i
(jj3 <- quad.diag(M,x))
#> [1] -0.361280-1.642215i 3.086616+0.822312i -1.385598-2.269765i
tester(jj1,jj3)
tester(jj2,jj3)
quad.tdiag()
= \(\operatorname{diag}(xMx^*)\) =
diag(quad.tform())
:quad.tdiag(M,x)=rowSums(tcrossprod(Conj(x), M) * x)
(jj1 <- diag(y %*% M %*% ht(y)))
#> [1] 9.7371946-4.9985268i 0.2953538+0.0874635i 0.6524977-3.8401838i
(jj2 <- diag(quad.tform(M,y)))
#> [1] 9.7371946-4.9985268i 0.2953538+0.0874635i 0.6524977-3.8401838i
(jj3 <- quad.tdiag(M,y))
#> [1] 9.7371946-4.9985268i 0.2953538+0.0874635i 0.6524977-3.8401838i
tester(jj1,jj3)
tester(jj2,jj3)
quad.3diag()
= \(\operatorname{diag}(x^*My)\)quad.3diag(M,l,r)=colSums(crossprod(M, Conj(left)) * right)
(jj1 <- diag(ht(x) %*% M %*% x1))
#> [1] -2.757785-3.661513i 4.294998-2.030691i -4.109222-3.118393i
(jj2 <- diag(quad.3form(M,x,x1)))
#> [1] -2.757785-3.661513i 4.294998-2.030691i -4.109222-3.118393i
(jj3 <- quad.3diag(M,x,x1))
#> [1] -2.757785-3.661513i 4.294998-2.030691i -4.109222-3.118393i
tester(jj1,jj3)
tester(jj2,jj3)
quad.3tdiag()
= \(\operatorname{diag}(xMy^*)\)quad.3tdiag(M,l,r)=colSums(t(left) * tcprod(M, right))
(jj1 <- diag(y %*% M %*% ht(y1)))
#> [1] 2.259877+5.817718i -1.599502-0.621855i 5.252914+2.317635i
(jj2 <- diag(quad.3tform(M,y,y1)))
#> [1] 2.259877+5.817718i -1.599502-0.621855i 5.252914+2.317635i
(jj3 <- quad.3tdiag(M,y,y1))
#> [1] 2.259877+5.817718i -1.599502-0.621855i 5.252914+2.317635i
tester(jj1,jj3)
tester(jj2,jj3)