function C = unadjoint(A, F) % UNADJOINT Given an adjoint matrix, constructs the original % quaternion matrix. % % unadjoint(A) or % unadjoint(A, 'complex') assumes A is a complex adjoint matrix. % unadjoint(A, 'real') assumes A is a real adjoint matrix. % % This function reverses the result of the ADJOINT function, so % that UNADJOINT(ADJOINT(A)) == A. % Copyright © 2005 Stephen J. Sangwine and Nicolas Le Bihan. % See the file : Copyright.m for further details. % References: see the code for ADJOINT. error(nargchk(1, 2, nargin)), error(nargoutchk(0, 1, nargout)) if nargin == 1 F = 'complex'; % Supply the default parameter value. end if ~strcmp(F, 'real') & ~strcmp(F, 'complex') error('Second parameter value must be ''real'' or ''complex''.') end % We have to be sure that A is a adjoint matrix, and not just some % arbitrary real or complex matrix. To do this we reconstruct the % original matrix, assuming A is an adjoint, then build the adjoint % from the reconstruction and compare it with A. If these are not % equal to within a tolerance, A was not an adjoint. We are also % able to eliminate some matrices as non-adjoints simply because of % their dimensions. When we build the adjoint C, we make an arbitrary % choice about which redundant parts of A to use. However, the unused % redundant parts are compared against the adjoint built from C and % if they are not close enough to the values used to build C an error % occurs. [r, c] = size(A); if strcmp(F, 'complex') r2 = r ./ 2; c2 = c ./ 2; if fix(r2) .* 2 ~= r | fix(c2) .* 2 ~= c error(['Matrix is incorrect size to be a ', F, ' adjoint']); end A1 = A(1 : r2, 1 : c2); A2 = A(1 : r2, c2 + 1 : c ); C = quaternion(real(A1), imag(A1), real(A2), imag(A2)); else % F must be 'real', since we checked it above. r4 = r ./ 4; c4 = c ./ 4; if fix(r4) .* 4 ~= r | fix(c4) .* 4 ~= c error(['Matrix is incorrect size to be a ', F, ' adjoint']); end W = A(1 : r4, 1 : c4); X = A(1 : r4, c4 + 1 : 2 .* c4); Y = A(1 : r4, 2 .* c4 + 1 : 3 .* c4); Z = A(1 : r4, 3 .* c4 + 1 : c ); C = quaternion(W, X, Y, Z); end T = adjoint(C, F); if any(size(T) ~= size(A)) error(['Matrix is incorrect size to be a ', F, ' adjoint']); end % Now we verify that A was indeed an adjoint matrix to within a tolerance. % We cannot test for exact equality, because A may be a product or the % result of some algorithm that theoretically yields an adjoint matrix, % but in practice yields an almost-adjoint because of rounding errors. RT = real(T); RA = real(A); IT = imag(T); IA = imag(A); % In the case of real quaternions, these will be 0. if any(any(abs(RT - RA) .* eps > abs(RA) | abs(IT - IA) .* eps > abs(IA))) error('Matrix is not (accurately) a valid adjoint matrix.'); end % Notes: the above test is not ideal. It is difficult to devise a simple % test that will work for complexified quaternions (because the modulus % can vanish). We can define a non-vanishing quasi-modulus and use that, % but it might not work correctly for all cases. For the moment the above % test will do. It will correctly raise an error in simple cases of bad % code.