3 #' Normalize a vector or a matrix (by columns), using euclidian norm
5 #' @param X Vector or matrix to be normalized
7 #' @return The normalized matrix (1 column if X is a vector)
10 normalize = function(X)
13 norm2 = sqrt( colSums(X^2) )
14 sweep(X, 2, norm2, '/')
17 # Computes a tensor-vector product
19 # @param Te third-order tensor (size dxdxd)
20 # @param w vector of size d
22 # @return Matrix of size dxd
24 .T_I_I_w = function(Te, w)
27 Ma = matrix(0,nrow=d,ncol=d)
29 Ma = Ma + w[j] * Te[,,j]
33 # Computes the second-order empirical moment between input X and output Y
35 # @param X matrix of covariates (of size n*d)
36 # @param Y vector of responses (of size n)
38 # @return Matrix of size dxd
40 .Moments_M2 = function(X, Y)
44 M2 = matrix(0,nrow=d,ncol=d)
45 matrix( .C("Moments_M2", X=as.double(X), Y=as.double(Y), pn=as.integer(n),
46 pd=as.integer(d), M2=as.double(M2), PACKAGE="morpheus")$M2, nrow=d, ncol=d)
49 # Computes the third-order empirical moment between input X and output Y
51 # @param X matrix of covariates (of size n*d)
52 # @param Y vector of responses (of size n)
54 # @return Array of size dxdxd
56 .Moments_M3 = function(X, Y)
60 M3 = array(0,dim=c(d,d,d))
61 array( .C("Moments_M3", X=as.double(X), Y=as.double(Y), pn=as.integer(n),
62 pd=as.integer(d), M3=as.double(M3), PACKAGE="morpheus")$M3, dim=c(d,d,d) )
67 #' Compute cross-moments of order 1,2,3 from X,Y
69 #' @inheritParams computeMu
71 #' @return A list L where L[[i]] is the i-th cross-moment
74 computeMoments = function(X, Y)
75 list( colMeans(Y * X), .Moments_M2(X,Y), .Moments_M3(X,Y) )
77 # Find the optimal assignment (permutation) between two sets (minimize cost)
79 # @param distances The distances matrix, in columns (distances[i,j] is distance between i
82 # @return A permutation minimizing cost
84 .hungarianAlgorithm = function(distances)
87 .C("hungarianAlgorithm", distances=as.double(distances), pn=as.integer(n),
88 assignment=integer(n), PACKAGE="morpheus")$assignment
93 #' Align a set of parameters matrices, with potential permutations.
95 #' @param Ms A list of matrices, all of same size DxK
96 #' @param ref Either a reference matrix or "mean" to align on empirical mean
97 #' @param ls_mode How to compute the labels assignment: "exact" for exact algorithm
98 #' (default, but might be time-consuming, complexity is O(K^3) ), or "approx1", or
99 #' "approx2" to apply a greedy matching algorithm (heuristic) which for each column in
100 #' reference (resp. in current row) compare to all unassigned columns in current row
101 #' (resp. in reference)
103 #' @return The aligned list (of matrices), of same size as Ms
106 alignMatrices = function(Ms, ref, ls_mode)
108 if (!is.matrix(ref) && ref != "mean")
109 stop("ref: matrix or 'mean'")
110 if (!ls_mode %in% c("exact","approx1","approx2"))
111 stop("ls_mode in {'exact','approx1','approx2'}")
114 if (is.character(ref)) #ref=="mean"
117 for (i in ifelse(is.character(ref),2,1):L)
119 m_ref = if (is.character(ref)) m_sum / (i-1) else ref
120 m = Ms[[i]] #shorthand
122 if (ls_mode == "exact")
124 #distances[i,j] = distance between m column i and ref column j
125 distances = apply( m_ref, 2, function(col) ( sqrt(colSums((m-col)^2)) ) )
126 assignment = .hungarianAlgorithm(distances)
127 col <- m[,assignment]
128 if (is.list(Ms)) Ms[[i]] <- col else Ms[,,i] <- col
133 # approx1: li[[i]][,j] is assigned to m[,k] minimizing dist(li[[i]][,j],m[,k'])
134 # approx2: m[,j] is assigned to li[[i]][,k] minimizing dist(m[,j],li[[i]][,k'])
135 available_indices = 1:K
139 if (ls_mode == "approx1")
141 apply(as.matrix(m[,available_indices]), 2,
142 function(col) ( sqrt(sum((col - m_ref[,j])^2)) ) )
146 apply(as.matrix(m_ref[,available_indices]), 2,
147 function(col) ( sqrt(sum((col - m[,j])^2)) ) )
149 indMin = which.min(distances)
150 if (ls_mode == "approx1")
152 col <- m[ , available_indices[indMin] ]
153 if (is.list(Ms)) Ms[[i]][,j] <- col else Ms[,j,i] <- col
157 col <- available_indices[indMin]
158 if (is.list(Ms)) Ms[[i]][,col] <- m[,j] else Ms[,col,i] <- m[,j]
160 available_indices = available_indices[-indMin]
164 # Update current sum with "label-switched" li[[i]]
165 if (is.character(ref)) #ref=="mean"
166 m_sum = m_sum + Ms[[i]]