## Raw procedure for learning resonant basis (adaptive filters / generative models) by computing elastic equilibria # # Run in R statistical computing environment with 'source("csca.r")' in proper directory. Use getwd() and setwd(). # With intelligent coupling Q = E{xx^H}^-1 between systems x_i, and with zero response/consuming constants R, # the models phi_i would converge to principal components of data, or at least to the subspace spanned by them. # The algorithm is extended to approximate completely distributed models with simpler diagonal coupling q_i = constant # by consuming the data for activity, R > 0, which separates the models. The data can be complex valued, # and the default constraint Re(x_i) > 0, Im(x_i) = 0 elicits sparse components. Other constraints are possible, # and complex coupling constants would simulate inductive and conductive phenomena in frequency space. # The models summarize steady states of rapid gradient descents of cybernetic objective function # J(x,u) = 1/2 x^H A x - x^H B u, i.e. dx/dt = - G A x + G B u, i.e. xbar = A^-1 B u = phi^H ubar, # where A = (Q^-1 + R E{xbarxbar^H}) and B = E{xbarubar^H}, # and data is consumed for activity, ubar = u - phi R xbar. # Heikki Hyötyniemi & Petri Lievonen -- http://neocybernetics.com/ #library('Matrix') # use Matrix library instead of standard 'matrix' command # for larger sparse data and matrices of specific form # Set: n <- 50 # number of models/features/systems/attractors x_i lambda <- 0.05 # learning rate, near zero: inverse of adaptation time scale in sample time; reduce by several magnitudes if problems complexModels <- TRUE # operate on complex field. stores real and imaginary parts separately instead of using built-in complexSystem <- FALSE # complex data types to illustrate explicit calculations and workaround unimplemented methods. loadData <- TRUE # load data from file centerSamples <- FALSE # center samples to zero mean normalizeSamples <- FALSE # normalize sample vectors (and thus their component sum of squares) to unity whitenSamples <- FALSE # whiten data in its main principal subspace centerVariables <- TRUE # center data dimensions (recommended for numerical stability) normalizeVariables <- FALSE # normalize data dimension variances to unity (recommended for unknown data) initModels <- TRUE # initialize model matrices, set false to continue iteration offlineProcessing <- TRUE # adapt to all data simultaneously; alternatively process only one sample at a time breakSymmetry <- TRUE # enhance sparsity by truncating negative Re(x_i) to zero (rectifying), so that linear subspaces become convex rays searchCoherence <- TRUE # simplify sparsity by constraining Im(x_i) to zero (this constant is not implemented yet) maskA <- FALSE # elicit actual principal components by structural constraints q_i <- 4 # coupling constants' initial values intelligentCoupling = FALSE # Q = E{xx^H}^-1, set response constants r_i to zero to prevent exhaustion regulatedCoupling = TRUE # q_i = 1/E{|x_i|^2} will keep the models near unit length and maximize perceptions E{|x_i|^2} r_i <- 1 # response constants between 0 (decoupled) and 1 (consuming data for activity) (start small if necessary) showModels = TRUE # show models as images showStructure = TRUE # show higher-order structure as images, matrices phi^H phi and E{xx^H} for example showCriterion = TRUE # plot some objective function of iteration, showing convergence for example showEstimate = TRUE # show some data estimates by current models showBalance = TRUE # show some data balances (natural residuals ubar and model activities xbar) by current models showLabels = TRUE # show labels for different plots if (loadData) { m <- 256 # number of data dimensions u_j k <- 500 # number of data samples u # example data from http://neocybernetics.com/research/digits500.txt U_re <- matrix(scan("digits500.txt"), m, k) # load real-valued data samples to columns of matrix Re(U) U_im <- 0 # try library 'matlab' or 'R.matlab' for .mat data files imageW <- imageH <- 16 # image width and height for this special data # also all kinds of transformations are possible, such as generating higher combinatorics, ## U <- mvfft(U_re); U_re <- Re(U); U_im <- Im(U) # or using Fourier-transform, but must be inverse-transformed later #m <- 1024; k <- 8940; imageW <- 32; imageH <- 32 #U_re <- matrix(scan("digits8940.txt"), m+1, k) # example data from http://neocybernetics.com/research/digits8940.zip #U_re <- U_re[1:m,] # last dimension contains labeling data, removed here #U_re <- (U_re+1)/2 # some example data sets courtesy of http://www.cs.nyu.edu/~roweis/data.html #m <- 256; k <- 1100*10; imageW <- 16; imageH <- 16 #library('R.matlab'); mat <- readMat("usps_all.mat"); U_re <- matrix(mat$data,m) / 256 # class labels available, see dim(mat$data) #m <- 1024; k <- 10000 #50000; #imageW <- 32; imageH <- 32 #library('R.matlab'); mat <- readMat("patches.mat"); U_re <- matrix(mat$X[(m*20000+1):(m*20000+m*k)],m,k) #m <- 320; k <- 1404; imageW <- 20; imageH <- 16 #library('R.matlab'); mat <- readMat("binaryalphadigs.mat"); U_re <- matrix(unlist(mat$dat),nrow=m) # extra dimensions available, see summary(mat) #m <- 560; k <- 1965; imageW <- 20; imageH <- 28 #library('R.matlab'); mat <- readMat("frey_rawface.mat"); U_re <- mat$ff #/255 #log(mat$ff) #U_re <- U_re/rowMeans(U_re) - 1; # == (U_re-rowMeans(U_re))/rowMeans(U_re) # cybernetic preprocessing #1 #U_re <- log(U_re); #U_re <- U_re - rowMeans(U_re); # == log(U_re/exp(rowMeans(log(U_re)))) # cybernetic preprocessing #2 #centerSamples <- TRUE; #centerSamples <- TRUE; normalizeSamples <- TRUE; centerVariables <- TRUE; normalizeVariables <- TRUE #m <- 4096; k <- 400; imageW <- 64; imageH <- 64 #library('R.matlab'); mat <- readMat("olivettifaces.mat"); U_re <- mat$faces / 256 #centerSamples <- TRUE; normalizeSamples <- TRUE; centerVariables <- TRUE; normalizeVariables <- TRUE # extra dimensions available, see summary(mat) #m <- 784; k <- 60000; imageW <- 28; imageH <- 28 #library('R.matlab'); mat <- readMat("mnist_all_mod.mat") #U_re <- t( rbind(mat$train0,mat$train1,mat$train2,mat$train3,mat$train4,mat$train5,mat$train6,mat$train7,mat$train8,mat$train9) ) # use sparse Matrix library instead to save memory! #m <- 784; k <- 6006; imageW <- 28; imageH <- 28 #library('R.matlab'); mat <- readMat("mnist_bw_small.mat") #U_re <- t(mat$X.train) #U_re <- U_re[1:m,] # last dimension contains labeling data, not used yet #m <- 10304; k <- 575; imageW <- 112; imageH <- 92 #library('R.matlab'); mat <- readMat("umist_cropped.mat"); U_re <- matrix(mat$facedat[[1]],m) / 256 #for (i in 2:20) { # U_re <- cbind( U_re, matrix(mat$facedat[[i]],m)/256 ) #} #centerSamples <- TRUE; normalizeSamples <- TRUE; centerVariables <- TRUE; normalizeVariables <- TRUE # extra dimensions available, see summary(mat) #m <- 1024; k <- 1428; imageW <- 32; imageH <- 32 #library('R.matlab'); mat <- readMat("lights=27.mat"); U_re <- t(mat$fea) / 256 #centerSamples <- TRUE; normalizeSamples <- TRUE; centerVariables <- TRUE; normalizeVariables <- TRUE # extra dimensions available, see summary(mat) #m <- 1024; k <- 400; imageW <- 32; imageH <- 32 #library('R.matlab'); mat <- readMat("ORL_32x32.mat"); U_re <- t(mat$fea) / 256 #centerSamples <- TRUE; normalizeSamples <- TRUE; centerVariables <- TRUE; normalizeVariables <- TRUE # extra dimensions available, see summary(mat) #m <- 4096; k <- 400; imageW <- 64; imageH <- 64 #library('R.matlab'); mat <- readMat("ORL_64x64.mat"); U_re <- t(mat$fea) / 256 #centerSamples <- TRUE; normalizeSamples <- TRUE; centerVariables <- TRUE; normalizeVariables <- TRUE # extra dimensions available, see summary(mat) #m <- 1024; k <- 11554; imageW <- 32; imageH <- 32 #library('R.matlab'); mat <- readMat("PIE_32x32.mat"); U_re <- t(mat$fea) / 256 #centerSamples <- TRUE; normalizeSamples <- TRUE; centerVariables <- TRUE; normalizeVariables <- TRUE # extra dimensions available, see summary(mat) #m <- 100; k <- 16242; imageW <- 10; imageH <- 10 #library('R.matlab'); mat <- readMat("20news_w100.mat"); U_re <- as.matrix(mat$documents) # data should be preprocessed properly # extra dimensions available, see summary(mat) ##library('R.matlab'); mat <- readMat("grolier15276.mat"); ##library('R.matlab'); mat <- readMat("pnas_all.mat"); ##library('R.matlab'); mat <- readMat("nips12raw_str602.mat"); ##library('R.matlab'); mat <- readMat("nips_1-17.mat"); ##library('R.matlab'); mat <- readMat("visterms_1000.mat"); if (centerSamples) { # optionally center sample vectors (remove the DC component) sampleMeans_re <- colMeans(U_re) # calculate sample means U_re <- t(t(U_re)-sampleMeans_re) # center samples by substracting the means if (complexModels) {} # center also imaginary component if present } if (normalizeSamples) { # optionally normalize sample vectors to unit length sampleSqMeans <- colMeans(U_re^2) # calculate means of sample squares (std.dev^2, RMS^2) sampleSqMeans[sampleSqMeans==0] <- 1 # prevent division by zero U_re <- t(t(U_re)/sqrt(sampleSqMeans)) # normalize sample vectors to unit length if (complexModels) {} # normalize properly with sqrt(Mod()) if imaginary component is present } if (whitenSamples) { # experiment with prewhitening pca <- eigen(tcrossprod(U_re)/k) nbasis <- floor(0.25*length(pca$values)) invvar <- 1/sqrt(pca$values[1:nbasis]) #invvar <- rep(1,nbasis) basis <- pca$vectors[,1:nbasis] #U_re <- basis %*% diag(invvar) %*% t(basis) %*% U_re U_re <- diag(invvar) %*% t(basis) %*% U_re m <- dim(U_re)[1] } maxU <- max(abs(range(U_re))) # store maximum value for drawing if (centerVariables) { # for numerical stability it is better to center the data meanU_re <- rowMeans(U_re) # calculate data dimension averages to set affine subspaces #meanU_re <- exp(rowMeans(log(U_re))) # alternatively, use geometric means for positive data U_re <- U_re - meanU_re # center the data by substracting the mean (store for reversal) if (complexModels) { # center also imaginary component if present #meanU_im <- rowMeans(U_im) #U_im <- U_im - meanU_im } } else { meanU_re <- 0; meanU_im <- 0 } #U_re[m,] <- 1 # experiment with setting some dimension to constant unity to facilitate affine modeling if (normalizeVariables) { # if nothing more specific is known about the data distribution if (complexModels) { varU <- rowMeans(U_re^2 + U_im^2) # calculate data dimension variances } else { varU <- rowMeans(U_re^2) # calculate data dimension variances } #varU <- mean(varU) # optionally treat several dimensions as similar #varU <- meanU_re^2 # cybernetic standardization: divide deviations from means by those means varU[varU==0] <- 1 # prevent division by zero U_re <- U_re/sqrt(varU) # normalize data by dividing by standard deviations if (complexModels) { # normalize properly with sqrt(Mod()) if imaginary component is present U_im <- U_im/sqrt(varU) } } else { varU <- 1 } maxUbar <- max(abs(range(U_re))) # store maximum value for drawing if (complexModels) { # a special example for this data: U_im <- matrix(0,m,k) # set the first 10 imaginary components of data to imply digit U_im[1:10,] <- (row(U_im)%%10 == col(U_im)%%10)[1:10,] meanU_im <- 0 #U_im[,1:(k-1)] <- U_re[,2:k] # second special example: set imaginary component to denote the next real sample #U_im[,1:(k-1)] <- U_re[,2:k] - U_re[,1:(k-1)] # or set imaginary component to denote the gradient ##meanU_im <- meanU_re ##limits <- range(U_re) # third special example: ###U_im <- sin( (U_re - limits[1])/(limits[2]-limits[1]) * pi - pi/2 ) # one can also experiment coding values to ##U_im <- sin( (U_re - limits[1])/(limits[2]-limits[1]) * pi - pi/2 ) * ( (U_re - limits[1])/(limits[2]-limits[1]) * 2 - 1 ) ###U_re <- cos( (U_re - limits[1])/(limits[2]-limits[1]) * pi - pi/2 ) # phases/arguments and confidences to magnitudes/modulus ##U_re <- cos( (U_re - limits[1])/(limits[2]-limits[1]) * pi - pi/2 ) * ( (U_re - limits[1])/(limits[2]-limits[1]) * 2 - 1 ) } else { U_im <- 0 } #U_re[1:10,] <- (row(U_re)%%10 == col(U_re)%%10)[1:10,] # also real dimensions could be used for extra data (this overwrites for simplicity) } # for natural positive data consider instead logarithms and geometric means of data, # for example dividing deviations from means by those means. (see "freyface.mat" above for example) # for time series study vectorizing successive samples together if(initModels) { ExuH_re <- 1/n*matrix(runif(n*m)-0.5,n,m) # initialize matrix Re(E{xu^H}) with small random real numbers (1/sqrt(m), for example) ##ExuH_re <- ExuH_re * t(U_re[,sample.int(k,n)]) # could try different initializations if (complexModels) { ExuH_im <- 1/n*matrix(runif(n*m)-0.5,n,m) # initialize matrix Im(E{xu^H}) with small random imaginary numbers (1/sqrt(m), for example) } else { ExuH_im <- 0 } ExxH_re <- 1/n*matrix(runif(n*n),n,n) # initialize matrix E{xx^H} with small random numbers (or just a diagonal) #invExxH_re <- solve(ExxH_re) if (complexSystem) { ExxH_im <- 1/n*matrix(runif(n*n),n,n) # initialize matrix E{xx^H} with small random numbers (or just a diagonal) } else { ExxH_im <- 0 } Q_re <- q_i*diag(n) # initialize matrix Q with equal coupling constants in diagonal, just for this case if (complexSystem) { Q_im <- 0*diag(n) } else { Q_im <- 0 } if (intelligentCoupling) { # if intelligent coupling is assumed Q_re <- solve(ExxH_re) # initialize coupling matrix as inverse of activity covariance matrix } if (complexSystem) { phi_re <- t(Q_re %*% ExuH_re - Q_im %*% ExuH_im) # initialize real parts of models/filters as columns of matrix Re(phi) phi_im <- -t(Q_re %*% ExuH_im + Q_im %*% ExuH_re) # imaginary part is negative due to complex conjugation ^H } else if (complexModels) { phi_re <- t(Q_re %*% ExuH_re) # initialize real parts of models/filters as columns of matrix Re(phi) phi_im <- -t(Q_re %*% ExuH_im) # initialize imaginary parts of models/filters as columns of matrix Im(phi) } else { phi_re <- t(Q_re %*% ExuH_re) # initialize real parts of models/filters as columns of matrix Re(phi) phi_im <- 0 } R_re <- r_i # initialize matrix R with equal response constants in diagonal (or replace with a scalar) if (complexSystem) { R_im <- 0 } else { R_im <- 0 } Xbar_re <- matrix(0,n,k) # initialize perceptions if (complexSystem) { Xbar_im <- matrix(0,n,k) } else { Xbar_im <- 0 } Ubar_re <- matrix(0,m,k) # initialize effective variables if (complexModels) { Ubar_im <- matrix(0,m,k) } else { Ubar_im <- 0 } } # should make more effort to generate different scenarios and bootstraps, # to reduce the initial transient, for example #jet.colors <- colorRampPalette(c("blue","white","red"), space="Lab") # create custom color palette jet.colors <- colorRampPalette(c("black","white"), space="Lab") # alternative custom color palette bwr <- jet.colors(255) # palette ranges from blue (-) to white (0) to red (+) J <- c(0) # initialize vector for storing some cost criterion to be plotted #Jprev <- sum(diag(ExxH_re)) # Main loop: for (p in 1:10000) { # iterate for some time or when Esc or Ctrl+C pressed currentSample = (p-1)%%k + 1 # index of current sample: iteration number p limited to number of samples k # create/clear a graphics window with 5x5=25 tiled image blocks gridSize = ceiling(sqrt(n*showModels + 2*showStructure + showCriterion + 2*showEstimate + 2*showBalance)) if (complexModels) { par(mfrow=c(gridSize,gridSize*2), mar=c(1,0.1,0.1,0.1)) #edit to fit } else { par(mfrow=c(gridSize,gridSize), mar=c(1,0.1,0.1,0.1)) #edit to fit #par(mfrow=c(6,6), mar=c(1,1,1,1)) #edit to fit } # Filter data u to perceptions xbar: if (offlineProcessing) { if (complexSystem) { # let's calculate the slow way for simplicity varphiH <- Conj(solve(Conj(solve(matrix(complex(real=Q_re,imag=Q_im),n,n))) + complex(real=R_re,imag=R_im) * matrix(complex(real=ExxH_re,imag=ExxH_im),n,n))) %*% matrix(complex(real=ExuH_re,imag=ExuH_im),n,m) Xbar_re <- Re(varphiH) %*% U_re - Im(varphiH) %*% U_im # calculate steady state for each u Xbar_im <- Im(varphiH) %*% U_re + Re(varphiH) %*% U_im # calculate steady state for each u } else if (complexModels) { Xbar_re <- solve(solve(Q_re) + R_re * ExxH_re) %*% (ExuH_re %*% U_re - ExuH_im %*% U_im) # calculate steady state for each u #Xbar_im <- 0 # not calculated: only coherent solutions are searched for #Xbar_im <- solve(solve(Q_re) + R_re * ExxH_re) %*% (ExuH_im %*% U_re + ExuH_re %*% U_im) # calculate steady state for each u #Xbar_re <- (Xbar_re) + Xbar_im # results in rotation, if the next sample is coded in imaginary component #Xbar_re[1:5,] <- Xbar_im[1:5,] # or manipulate only some of the filters } else { Xbar_re <- solve(solve(Q_re) + R_re * ExxH_re) %*% ExuH_re %*% U_re # calculate steady state for each u ##Xbar_re <- solve(diag(n) + R_re %*% phiTphi_re) %*% t(phi_re) %*% U_re # equivalent alternative formulation } } else { # process one sample at a time if (complexSystem) { # let's calculate the slow way for simplicity varphiH <- Conj(solve(Conj(solve(matrix(complex(real=Q_re,imag=Q_im),n,n))) + complex(real=R_re,imag=R_im) * matrix(complex(real=ExxH_re,imag=ExxH_im),n,n))) %*% matrix(complex(real=ExuH_re,imag=ExuH_im),n,m) Xbar_re[,currentSample] <- Re(varphiH) %*% U_re[,currentSample] - Im(varphiH) %*% U_im[,currentSample] # calculate steady state for this u Xbar_im[,currentSample] <- Im(varphiH) %*% U_re[,currentSample] + Re(varphiH) %*% U_im[,currentSample] # calculate steady state for this u } else if (complexModels) { Xbar_re[,currentSample] <- solve(solve(Q_re) + R_re * ExxH_re) %*% (ExuH_re %*% U_re[,currentSample] - ExuH_im %*% U_im[,currentSample]) # calculate steady state for this u } else { Xbar_re[,currentSample] <- solve(solve(Q_re) + R_re * ExxH_re) %*% ExuH_re %*% U_re[,currentSample] # calculate steady state for this u # experiment optimizations by matrix inversion lemma #invAold <- solve(solve(Q_re) + R_re * ExxH_re) #invAnew <- invAold - invAold #Xbar_re[,currentSample] <- invA %*% ExuH_re %*% U_re[,currentSample] # calculate steady state for this u } } # Apply nonlinearity to perceptions xbar: if (breakSymmetry) { # one way to elicit sparse solutions: if (offlineProcessing) { if (complexSystem) { #Xbar_re <- Xbar_re - sqrt(diag(ExxH_re)) #Xbar_re <- Xbar_re - 1/sqrt(diag(Q_re)) #Xbar_re[Xbar_re<(1/sqrt(diag(Q_re)))] <- 0 # truncate negative (or smaller than some constant) inner products to zero, or multiply by small number #Xbar_im[Xbar_re<0] <- 0 # truncate negative (or smaller than some constant) inner products to zero, or multiply by small number Xbar_re[Xbar_re<0] <- 0 # proper nonlinearity should be applied recursively with active models #Xbar_re <- t(phi) %*% U - R_re * phiTphi %*% Xbar_re # but not possible in a linear matrix form #Xbar_re <- matrix(0,n,k) Xbar_im <- matrix(0,n,k) } else if (complexModels) { Xbar_re[Xbar_re<0] <- 0 } else { Xbar_re[Xbar_re<0] <- 0 # one could study applying approximations a few times recursively #Xbar_re <- Xbar_re^2 #Xbar_re <- log(cosh(Xbar_re)) #Xbar_re <- Xbar_re - tanh(Xbar_re) #Xbar_re <- Xbar_re*tanh(Xbar_re) } } else { if (complexSystem) { Xbar_re[Xbar_re[,currentSample]<0,currentSample] <- 0 # truncate negative (or smaller than some constant) inner products to zero Xbar_im[,currentSample] <- 0 } else if (complexModels) { Xbar_re[Xbar_re[,currentSample]<0,currentSample] <- 0 # truncate negative (or smaller than some constant) inner products to zero } else { Xbar_re[Xbar_re[,currentSample]<0,currentSample] <- 0 # truncate negative (or smaller than some constant) inner products to zero } } } # testing: #Xbar_re <- (Xbar_re + Xbar_re*diag(crossprod(phi_re))) * diag(Q_re) #Xbar_re <- (Xbar_re + Xbar_re*diag(crossprod(phi_re))) * 1 #Xbar_re[abs(Xbar_re)<0.3] <- 0 # possible additional sparsifying constraints, based on number of nonzeros, lower quantiles etc. #Xbar_re[abs(Xbar_re)<0.1] <- 0 # possible additional sparsifying constraints, based on number of nonzeros, lower quantiles etc. #Xbar_re[Xbar_re>0.1] <- (Xbar_re/diag(Q_re)/diag(crossprod(phi_re)) + 0.1/diag(Q_re)/diag(crossprod(phi_re)))[Xbar_re>0.1] #Xbar_re[Xbar_re>0.3] <- (Xbar_re/diag(crossprod(phi_re)) + 0.3/diag(crossprod(phi_re)))[Xbar_re>0.3] #Xbar_re[Xbar_re<0.1] <- (Xbar_re/diag(Q_re)/diag(crossprod(phi_re)) - 0.1/diag(Q_re)/diag(crossprod(phi_re)))[Xbar_re<0.1] #Xbar_re[Xbar_re<0.3] <- (Xbar_re/diag(crossprod(phi_re)) - 0.3/diag(crossprod(phi_re)))[Xbar_re<0.3] #Xbar_re[Xbar_re<0.1] <- Xbar_re[Xbar_re<0.1] + (Xbar_re[Xbar_re<0.1]-0.1)/diag(crossprod(phi_re)) #diag(R_re) <- diag(crossprod(phi_re)) #Xbar_re <- Xbar_re^2 # Xbar_re <- sqrt(Xbar_re) # Substract implicit response uest from u to get effective variables ubar: if (offlineProcessing) { if (complexSystem) { if (R_im == 0) { Ubar_re <- U_re - R_re * (phi_re %*% Xbar_re - phi_im %*% Xbar_im) # calculate the effective data by substracting the effect of Ubar_im <- U_im - R_re * (phi_im %*% Xbar_re + phi_re %*% Xbar_im) # steady states: the estimate that is implicit in consuming/dampening response } else { Ubar_re <- U_re - (R_re * (phi_re %*% Xbar_re - phi_im %*% Xbar_im) - R_im * (phi_im %*% Xbar_re + phi_re %*% Xbar_im)) Ubar_im <- U_im - (R_re * (phi_im %*% Xbar_re + phi_re %*% Xbar_im) + R_im * (phi_re %*% Xbar_re - phi_im %*% Xbar_im)) } } else if (complexModels) { Ubar_re <- U_re - R_re * phi_re %*% Xbar_re Ubar_im <- U_im - R_re * phi_im %*% Xbar_re } else { Ubar_re <- U_re - R_re * phi_re %*% Xbar_re } } else { if (complexSystem) { Ubar_re[,currentSample] <- U_re[,currentSample] - R_re * (phi_re %*% Xbar_re[,currentSample] - phi_im %*% Xbar_im[,currentSample]) Ubar_im[,currentSample] <- U_im[,currentSample] - R_re * (phi_im %*% Xbar_re[,currentSample] + phi_re %*% Xbar_im[,currentSample]) } else if (complexModels) { Ubar_re[,currentSample] <- U_re[,currentSample] - R_re * phi_re %*% Xbar_re[,currentSample] Ubar_im[,currentSample] <- U_im[,currentSample] - R_re * phi_im %*% Xbar_re[,currentSample] } else { Ubar_re[,currentSample] <- U_re[,currentSample] - R_re * phi_re %*% Xbar_re[,currentSample] } } # Update system/model matrices essential for filtering and generative modeling: if (offlineProcessing) { # E{xu^H}: if (complexSystem) { ExuH_re <- (1-lambda) * ExuH_re + lambda * (tcrossprod(Xbar_re,Ubar_re) + tcrossprod(Xbar_im,Ubar_im))/k # E{xu^T}_re ~ (Xbar_re %*% t(Ubar_re) - Xbar_im %*% t(-Ubar_im)) / k ExuH_im <- (1-lambda) * ExuH_im + lambda * (tcrossprod(Xbar_im,Ubar_re) - tcrossprod(Xbar_re,Ubar_im))/k # E{xu^T}_im ~ (Xbar_re %*% t(-Ubar_im) + Xbar_im %*% t(Ubar_re)) / k } else if (complexModels) { ExuH_re <- (1-lambda) * ExuH_re + lambda * tcrossprod(Xbar_re,Ubar_re)/k # E{xu^T}_re ~ Xbar_re %*% t(Ubar_re) / k ExuH_im <- (1-lambda) * ExuH_im - lambda * tcrossprod(Xbar_re,Ubar_im)/k # E{xu^T}_im ~ Xbar_re %*% t(-Ubar_im) / k } else { ExuH_re <- (1-lambda) * ExuH_re + lambda * tcrossprod(Xbar_re,Ubar_re)/k # E{xu^T}_re ~ Xbar_re %*% t(Ubar_re) / k } # E{xx^H}: if (complexSystem) { ExxH_re <- (1-lambda) * ExxH_re + lambda * (tcrossprod(Xbar_re) + tcrossprod(Xbar_im))/k # E{xx^T}_re ~ (Xbar_re %*% t(Xbar_re) - Xbar_im %*% t(-Xbar_im)) / k ExxH_im <- (1-lambda) * ExxH_im + lambda * (tcrossprod(Xbar_im,Xbar_re) - tcrossprod(Xbar_re,Xbar_im))/k # E{xx^T}_im ~ (Xbar_re %*% t(-Xbar_im) + Xbar_im %*% t(Xbar_re)) / k } else { ExxH_re <- (1-lambda) * ExxH_re + lambda * tcrossprod(Xbar_re)/k # E{xx^T} ~ Xbar_re %*% t(Xbar_re) / k } } else { # E{xu^H}: if (complexSystem) { ExuH_re <- (1-lambda) * ExuH_re + lambda * (tcrossprod(Xbar_re[,currentSample],Ubar_re[,currentSample]) + tcrossprod(Xbar_im[,currentSample],Ubar_im[,currentSample])) # E{xu^T}_re +~ (xbar_re %*% t(ubar_re) - xbar_im %*% t(-ubar_im)) ExuH_im <- (1-lambda) * ExuH_im + lambda * (tcrossprod(Xbar_im[,currentSample],Ubar_re[,currentSample]) - tcrossprod(Xbar_re[,currentSample],Ubar_im[,currentSample])) # E{xu^T}_im ~ (xbar_re %*% t(-ubar_im) + xbar_im %*% t(ubar_re)) } else if (complexModels) { ExuH_re <- (1-lambda) * ExuH_re + lambda * tcrossprod(Xbar_re[,currentSample],Ubar_re[,currentSample]) # E{xu^T}_re +~ xbar_re %*% t(ubar_re) ExuH_im <- (1-lambda) * ExuH_im - lambda * tcrossprod(Xbar_re[,currentSample],Ubar_im[,currentSample]) # E{xu^T}_im +~ xbar_re %*% t(-ubar_im) } else { ExuH_re <- (1-lambda) * ExuH_re + lambda * tcrossprod(Xbar_re[,currentSample],Ubar_re[,currentSample]) # E{xu^T}_re +~ xbar_re %*% t(ubar_re) } # E{xx^H}: if (complexSystem) { ExxH_re <- (1-lambda) * ExxH_re + lambda * (tcrossprod(Xbar_re[,currentSample]) + tcrossprod(Xbar_im[,currentSample])) # E{xx^T}_re +~ (xbar_re %*% t(xbar_re) - xbar_im %*% t(-xbar_im)) ExxH_im <- (1-lambda) * ExxH_im + lambda * (tcrossprod(Xbar_im[,currentSample],Xbar_re[,currentSample]) - tcrossprod(Xbar_re[,currentSample],Xbar_im[,currentSample])) # E{xx^T}_im +~ (xbar_re %*% t(-xbar_im) + xbar_im %*% t(xbar_re)) } else { ExxH_re <- (1-lambda) * ExxH_re + lambda * tcrossprod(Xbar_re[,currentSample]) # E{xx^T} +~ xbar_re %*% t(xbar_re) #invExxHold <- invExxH_re # experimenting iterative inversion by matrix inversion lemma #invExxH_re <- 1/(1-lambda) * ( invExxHold - (invExxHold %*% tcrossprod(Xbar_re[,currentSample]) %*% invExxHold) / c( t(Xbar_re[,currentSample]) %*% invExxHold %*% Xbar_re[,currentSample] + (1-lambda)/lambda) ) } } # Miscellaneous options: if (maskA) { # one way to use structural constraints for intelligent coupling: ExxH_re[row(ExxH_re)