unitlength.m 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. function [f,len,sc] = unitlength(m,dim,flag,wantcaution,sc)
  2. % function [f,len,sc] = unitlength(m,dim,flag,wantcaution,sc)
  3. %
  4. % <m> is a matrix
  5. % <dim> (optional) is the dimension of interest.
  6. % if supplied, normalize each case oriented along <dim> to have unit length.
  7. % if [] or not supplied, normalize length globally.
  8. % <flag> (optional) is
  9. % 0 means normal case
  10. % 1 means make length sqrt(n) where n is number of non-NaN entries
  11. % default: 0
  12. % <wantcaution> (optional) is whether to perform special handling of
  13. % weird cases where the length of <m> is very small to start with (see zerodiv.m).
  14. % default: 1.
  15. % <sc> (optional) is a special case. supply this and we will use it instead of
  16. % calculating the actual scale factor. also, <len> will be returned as [].
  17. % to indicate not-supplied, pass in [].
  18. %
  19. % unit-length normalize <m> via scaling, operating either on individual cases or globally.
  20. % the output <f> has the same dimensions as <m>. also, return <len> which is
  21. % the vector length of <m> along <dim>. when <dim> is [], <len> is a scalar;
  22. % otherwise, <len> is the same dimensions as <m> except collapsed along <dim>.
  23. % also, return <sc> which is the scale factor divided from <m>. the dimensions
  24. % of <sc> is the same as <len>.
  25. %
  26. % we ignore NaNs gracefully.
  27. %
  28. % note some weird cases:
  29. % unitlength([]) is [].
  30. % unitlength([0 0]) is [NaN NaN].
  31. % unitlength([NaN NaN]) is [NaN NaN].
  32. %
  33. % history:
  34. % 2014/04/27 - oops, make sure NaN is casted to class of <m>
  35. % 2011/06/27 - oops. handle empty case explicitly (it would have crashed)
  36. %
  37. % example:
  38. % a = [3 0 NaN];
  39. % isequalwithequalnans(unitlength(a),[1 0 NaN])
  40. % input
  41. if ~exist('dim','var') || isempty(dim)
  42. dim = [];
  43. end
  44. if ~exist('flag','var') || isempty(flag)
  45. flag = 0;
  46. end
  47. if ~exist('wantcaution','var') || isempty(wantcaution)
  48. wantcaution = 1;
  49. end
  50. % handle degenerate case up front
  51. if isempty(m)
  52. f = [];
  53. len = [];
  54. sc = [];
  55. return;
  56. end
  57. % figure out len and sc
  58. if ~exist('sc','var') || isempty(sc)
  59. % figure out vector length
  60. len = vectorlength(m,dim);
  61. % figure out scale factor
  62. if flag==1
  63. if isempty(dim)
  64. temp = sqrt(sum(~isnan(m(:))));
  65. else
  66. temp = sqrt(sum(~isnan(m),dim));
  67. end
  68. sc = len./temp;
  69. else
  70. sc = len;
  71. end
  72. else
  73. len = [];
  74. end
  75. % ok, do it
  76. f = bsxfun(@(x,y) zerodiv(x,y,cast(NaN,class(m)),wantcaution),m,sc);
  77. % HM, IS THIS SLOWER OR FASTER:
  78. % if isempty(dim)
  79. % f = zerodiv(m,sc,NaN,wantcaution);
  80. % else
  81. % f = zerodiv(m,repmat(sc,copymatrix(ones(1,ndims(m)),dim,size(m,dim))),NaN,wantcaution);
  82. % end