0001 function dec = constructProperRepresentation(dec, validityDataOriginal, ...
0002 zerotol, verbose, allowImproper)
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 if rank(dec.mappingReducedToFull) < dec.nC
0028 error('elk:decomposition:wrongInput', ['The input representation is ' ...
0029 'ill-conditioned, its dimension nC can be reduced without loss ' ...
0030 'of shape information']);
0031 end
0032
0033
0034
0035 validityCone.A = validityDataOriginal.A * dec.mappingReducedToFull;
0036
0037 validityCone.A = trimConstraintMatrix(validityCone.A, zerotol, 0);
0038
0039
0040
0041 isProper = 1;
0042
0043
0044 facetFilter = true(1, dec.nH);
0045
0046 facetGroupIndexVector = zeros(1, dec.nH);
0047
0048
0049 mappingReducedToFull = zeros(dec.nH, 0);
0050 mappingImproperToProper = zeros(0, dec.nC);
0051
0052 while any(facetFilter)
0053
0054 remainingFacetVector = find(facetFilter);
0055 thisFacet = remainingFacetVector(1);
0056
0057
0058 referenceConstraintMatrix = validityCone.A(...
0059 validityDataOriginal.responsibleFacetVector == thisFacet, :);
0060 referenceConstraintMatrix = sortrows(referenceConstraintMatrix);
0061 coherentFacetFilter = facetFilter;
0062 remainingIndex = 2;
0063 while remainingIndex <= length(remainingFacetVector)
0064 constraintMatrix = validityCone.A(...
0065 validityDataOriginal.responsibleFacetVector == ...
0066 remainingFacetVector(remainingIndex), :);
0067 constraintMatrix = sortrows(constraintMatrix);
0068 if size(constraintMatrix, 1) == size(referenceConstraintMatrix, 1) && ...
0069 all(referenceConstraintMatrix(:) == constraintMatrix(:))
0070
0071 else
0072
0073 coherentFacetFilter(remainingFacetVector(remainingIndex)) = false;
0074 end
0075
0076 remainingIndex = remainingIndex + 1;
0077 end
0078
0079
0080 matrixMg = dec.mappingReducedToFull;
0081 matrixMg(coherentFacetFilter, :) = 0;
0082 matrixA = dec.A;
0083 matrixA(coherentFacetFilter, :) = 0;
0084 if size(referenceConstraintMatrix, 1) == 0
0085
0086
0087
0088
0089 elseif rank(matrixMg) < dec.nC
0090
0091
0092
0093 elseif rank(dec.constraintMatrix * matrixA) < dec.nDim
0094
0095
0096
0097 else
0098
0099
0100
0101
0102 isProper = 0;
0103 end
0104
0105
0106 facetFilter(coherentFacetFilter) = false;
0107
0108
0109
0110 while any(coherentFacetFilter)
0111 thisIndex = find(coherentFacetFilter, 1, 'first');
0112 subFacetFilter = coherentFacetFilter & all(bsxfun(@minus, ...
0113 dec.mappingReducedToFull, ...
0114 dec.mappingReducedToFull(thisIndex, :)) == 0, 2)';
0115 facetGroupIndexVector(subFacetFilter) = max(facetGroupIndexVector) + 1;
0116
0117
0118 mappingReducedToFull(:, end+1) = double(subFacetFilter)';
0119
0120
0121 mappingImproperToProper(end+1, :) = dec.mappingReducedToFull(thisIndex, :);
0122
0123 coherentFacetFilter(subFacetFilter) = false;
0124 end
0125 end
0126
0127
0128 if isProper
0129 dec.isProper = 1;
0130
0131 return
0132 else
0133
0134 if allowImproper == 0
0135 error('elk:decomposition:improper', ['The input representation is ' ...
0136 'improper. To allow constructing a proper representation, ' ...
0137 'change parameter allowImproper to 1']);
0138 elseif allowImproper == 1
0139 warning('elk:decomposition:improper', ['The input representation ' ...
0140 'is improper. The mapping/constraints are extended to a proper ' ...
0141 'representation. To handle improper representations, look for ' ...
0142 'approximation of decomposition data. To supress this warning, '...
0143 'use allowImproper with (-1)']);
0144 end
0145
0146
0147
0148 dec.isProper = 0;
0149
0150 dec.improperData = dec;
0151
0152 dec.improperData.mappingImproperToProper = mappingImproperToProper;
0153 dec.improperData.mappingProperToImproper = pinv(mappingImproperToProper);
0154
0155
0156 dec.isProper = 1;
0157
0158
0159 dec.constraintMatrix = [];
0160 dec.mappingReducedToFull = mappingReducedToFull;
0161
0162
0163 try
0164 dec = computeMappingAndConstraint(dec, zerotol, 0);
0165 catch me
0166 error('elk:decomposition:numericalError', ['Constructed proper ' ...
0167 'decomposition does not fulfill the fixed-position constraint. ' ...
0168 'This should not happen.']);
0169 end
0170 dec.nC = size(mappingImproperToProper, 1);
0171 end
0172
0173 return
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188 [mappingImproperToProper facetIndexVector directionIndexVector] = ...
0189 unique(dec.mappingReducedToFull, 'rows');
0190 nDir = size(mappingImproperToProper, 1);
0191 directionMatrix = eye(size(mappingImproperToProper, 1));
0192
0193
0194
0195
0196
0197
0198 if size(eliminateRows(mappingImproperToProper, ...
0199 zeros(1, size(mappingImproperToProper, 2)), 0), ...
0200 1) > dec.nC
0201 isProper = 0;
0202 else
0203 isProper = 1;
0204 end
0205
0206
0207
0208
0209 for iDir = 1:nDir
0210 thisFacetIndexVector = find(directionIndexVector == iDir);
0211 flagKeepChecking = 1;
0212 while flagKeepChecking
0213
0214 thisReferenceCone = validityCone.A(...
0215 validityDataOriginal.responsibleFacetVector == ...
0216 thisFacetIndexVector(1), :);
0217 thisReferenceCone = unique(thisReferenceCone, 'rows');
0218
0219 nextFacetIndexVector = [];
0220
0221 for i = 2:length(thisFacetIndexVector)
0222 thisCone = validityCone.A(...
0223 validityDataOriginal.responsibleFacetVector == ...
0224 thisFacetIndexVector(i), :);
0225 thisCone = unique(thisCone, 'rows');
0226 if size(thisCone, 1) == size(thisReferenceCone, 1) && ...
0227 (any(thisCone(:) == thisReferenceCone(:)) || ...
0228 isempty(thisCone))
0229
0230
0231 else
0232
0233 isProper = 0;
0234 nextFacetIndexVector(end+1) = thisFacetIndexVector(i);
0235
0236
0237
0238 end
0239 end
0240 if isempty(nextFacetIndexVector)
0241
0242 flagKeepChecking = 0;
0243 else
0244
0245
0246 directionMatrix(end+1, end+1) = 1;
0247 mappingImproperToProper(end+1, :) = ...
0248 mappingImproperToProper(iDir , :);
0249 directionIndexVector(nextFacetIndexVector) = ...
0250 size(directionMatrix, 1);
0251
0252 if verbose
0253 disp(['Info: facet ' num2str(thisFacetIndexVector(1)) ...
0254 ' and facet(s) ' num2str(nextFacetIndexVector) ' are '...
0255 'not related, but share the same direction in '...
0256 'hC-space.']);
0257 end
0258 thisFacetIndexVector = nextFacetIndexVector;
0259 end
0260 end
0261 end
0262
0263
0264
0265
0266
0267
0268 dec.isProper = 1;
0269 if isProper
0270
0271 else
0272
0273 if allowImproper == 0
0274 error('elk:decomposition:improper', ['The input representation is ' ...
0275 'improper. To allow constructing a proper representation, ' ...
0276 'change parameter allowImproper to 1']);
0277 elseif allowImproper == 1
0278 warning('elk:decomposition:improper', ['The input representation ' ...
0279 'is improper. The mapping/constraints are extended to a proper ' ...
0280 'representation. To handle improper representations, look for ' ...
0281 'approximation of decomposition data. To supress this warning, '...
0282 'use allowImproper with (-1)']);
0283 end
0284
0285
0286 dec.improperData = dec;
0287
0288 dec.improperData.mappingImproperToProper = mappingImproperToProper;
0289 dec.improperData.mappingProperToImproper = ...
0290 pinv(mappingImproperToProper);
0291
0292
0293 dec.constraintMatrix = [];
0294 dec.mappingReducedToFull = directionMatrix(directionIndexVector, :);
0295
0296
0297 try
0298 dec = computeMappingAndConstraint(dec, zerotol, 0);
0299 catch me
0300 error('elk:decomposition:numericalError', ['Constructed proper ' ...
0301 'decomposition does not fulfill the fixed-position constraint. ' ...
0302 'This should not happen.']);
0303 end
0304 dec.nC = max(directionIndexVector);
0305 end
0306
0307 end