# Raw procedure for learning emergent models by computing cybernetic equilibria. # Run in R statistical computing environment with 'source("pca.r")' in proper directory. # The models phi_i will converge to principal components of data, or at least to the subspace spanned by them. # This algorithm assumes intelligent coupling A between systems x_i, which separates the models. # The process can be extended to self-organize and self-regulate also with simpler coupling Q # when data is consumed for activity. With careful conjugations, also complex values can be implemented. # The models summarize steady states of rapid gradient descents of cybernetic objective function # J(x,u) = 1/2 x^T A x - x^T B u, i.e. dx/dt = - G A x + G B u, i.e. xbar = A^-1 B u = phi^T u, # where A = E{xx^T} and B = E{xu^T}. # 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 <- 15 # number of models/features/systems/attractors x_i lambda <- 0.3 # near zero: inverse of adaptation time scale in sample time loadData <- TRUE # load data from file normalizeSamples <- FALSE # center samples and normalize sample vectors to unity centerDimensions <- FALSE # center data (recommended for numerical stability) normalizeDimensions <- FALSE # normalize data variances to unity initModels <- TRUE # initialize model matrices useRays <- FALSE # enhance sparsity by cutting negative inner products to zero maskA <- TRUE # elicit actual principal components by structural constraints if (loadData) { m <- 256 # number of data dimensions u_j k <- 500 # number of data samples u U <- matrix(scan("digits500.txt"), m, k) # load data samples to columns of matrix U # try library 'matlab' or 'R.matlab' for .mat data files side <- 16 # image width and height for this special data if (normalizeSamples) { # optionally normalize sample vectors to unit length sampleMeans <- colMeans(U) # calculate sample means U <- t(t(U)-sampleMeans) # center samples by substracting the means sampleSqMeans <- colMeans(U^2) # calculate means of sample squares (std.dev^2, RMS^2) sampleSqMeans[sampleSqMeans==0] <- 1 # prevent division by zero U <- t(t(U)/sqrt(sampleSqMeans)) # normalize sample vectors to unit length } if (centerDimensions) { # for numerical stability it is better to center the data meanU <- rowMeans(U) # calculate data dimension averages U <- U - meanU # center the data by substracting the mean (store for reversal) } if (normalizeDimensions) { # if nothing more specific is known about the data distribution varU <- rowMeans(U^2) # calculate data dimension variances varU[varU==0] <- 1 # prevent division by zero U <- U/sqrt(varU) # normalize data by dividing by standard deviations } } # for natural positive data consider instead logarithms and # geometric means of data, for example dividing deviations # from means by those means. # for time series study vectorizing successive samples together if(initModels) { ExuT <- 0.1*matrix(runif(n*m)-0.5,n,m) # initialize matrix E{xu^T} with small random numbers ExxT <- 0.1*matrix(runif(n*n),n,n) # initialize matrix E{xx^T} with small random numbers # should make more effort to generate different scenarios, } # for example to ensure symmetricity and positive-definiteness jet.colors <- colorRampPalette(c("blue","white","red"), space="Lab") # create custom color palette bwr <- jet.colors(255) # palette ranges from blue (-) to white (0) to red (+) for (p in 1:1000) { # iterate for some time or when Esc pressed par(mfrow=c(5,5), mar=c(1,1,1,1)) # create/clear a graphics window with 5x5=25 tiled image blocks Xbar <- solve(ExxT) %*% ExuT %*% U # calculate steady state for each u if (useRays) { # one way to elicit sparse solutions: Xbar[Xbar<0] <- 0 # cut negative inner products to zero } # update system/model matrices ExuT <- (1-lambda) * ExuT + lambda * Xbar %*% t(U) / k ExxT <- (1-lambda) * ExxT + lambda * Xbar %*% t(Xbar) / k if (maskA) { # one way to use structural constraints: ExxT[row(ExxT)