comparison armadillo-3.900.4/include/armadillo_bits/fn_norm.hpp @ 49:1ec0e2823891

Switch to using subrepo copies of qm-dsp, nnls-chroma, vamp-plugin-sdk; update Armadillo version; assume build without external BLAS/LAPACK
author Chris Cannam
date Thu, 13 Jun 2013 10:25:24 +0100
parents
children
comparison
equal deleted inserted replaced
48:69251e11a913 49:1ec0e2823891
1 // Copyright (C) 2008-2012 NICTA (www.nicta.com.au)
2 // Copyright (C) 2008-2012 Conrad Sanderson
3 //
4 // This Source Code Form is subject to the terms of the Mozilla Public
5 // License, v. 2.0. If a copy of the MPL was not distributed with this
6 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8
9 //! \addtogroup fn_norm
10 //! @{
11
12
13
14 template<typename T1>
15 arma_hot
16 inline
17 typename T1::pod_type
18 arma_vec_norm_1(const Proxy<T1>& P)
19 {
20 arma_extra_debug_sigprint();
21
22 typedef typename T1::pod_type T;
23
24 T acc = T(0);
25
26 if(Proxy<T1>::prefer_at_accessor == false)
27 {
28 typename Proxy<T1>::ea_type A = P.get_ea();
29
30 const uword N = P.get_n_elem();
31
32 T acc1 = T(0);
33 T acc2 = T(0);
34
35 uword i,j;
36 for(i=0, j=1; j<N; i+=2, j+=2)
37 {
38 acc1 += std::abs(A[i]);
39 acc2 += std::abs(A[j]);
40 }
41
42 if(i < N)
43 {
44 acc1 += std::abs(A[i]);
45 }
46
47 acc = acc1 + acc2;
48 }
49 else
50 {
51 const uword n_rows = P.get_n_rows();
52 const uword n_cols = P.get_n_cols();
53
54 if(n_rows == 1)
55 {
56 for(uword col=0; col<n_cols; ++col)
57 {
58 acc += std::abs(P.at(0,col));
59 }
60 }
61 else
62 {
63 for(uword col=0; col<n_cols; ++col)
64 {
65 uword i,j;
66
67 for(i=0, j=1; j<n_rows; i+=2, j+=2)
68 {
69 acc += std::abs(P.at(i,col));
70 acc += std::abs(P.at(j,col));
71 }
72
73 if(i < n_rows)
74 {
75 acc += std::abs(P.at(i,col));
76 }
77 }
78 }
79 }
80
81 return acc;
82 }
83
84
85
86 template<typename T1>
87 arma_hot
88 inline
89 typename T1::pod_type
90 arma_vec_norm_2
91 (
92 const Proxy<T1>& P,
93 const typename arma_not_cx<typename T1::elem_type>::result* junk = 0
94 )
95 {
96 arma_extra_debug_sigprint();
97 arma_ignore(junk);
98
99 typedef typename T1::pod_type T;
100
101 T acc = T(0);
102
103 if(Proxy<T1>::prefer_at_accessor == false)
104 {
105 typename Proxy<T1>::ea_type A = P.get_ea();
106
107 const uword N = P.get_n_elem();
108
109 T acc1 = T(0);
110 T acc2 = T(0);
111
112 uword i,j;
113
114 for(i=0, j=1; j<N; i+=2, j+=2)
115 {
116 const T tmp_i = A[i];
117 const T tmp_j = A[j];
118
119 acc1 += tmp_i * tmp_i;
120 acc2 += tmp_j * tmp_j;
121 }
122
123 if(i < N)
124 {
125 const T tmp_i = A[i];
126
127 acc1 += tmp_i * tmp_i;
128 }
129
130 acc = acc1 + acc2;
131 }
132 else
133 {
134 const uword n_rows = P.get_n_rows();
135 const uword n_cols = P.get_n_cols();
136
137 if(n_rows == 1)
138 {
139 for(uword col=0; col<n_cols; ++col)
140 {
141 const T tmp = P.at(0,col);
142
143 acc += tmp * tmp;
144 }
145 }
146 else
147 {
148 for(uword col=0; col<n_cols; ++col)
149 {
150 uword i,j;
151 for(i=0, j=1; j<n_rows; i+=2, j+=2)
152 {
153 const T tmp_i = P.at(i,col);
154 const T tmp_j = P.at(j,col);
155
156 acc += tmp_i * tmp_i;
157 acc += tmp_j * tmp_j;
158 }
159
160 if(i < n_rows)
161 {
162 const T tmp_i = P.at(i,col);
163
164 acc += tmp_i * tmp_i;
165 }
166 }
167 }
168 }
169
170 return std::sqrt(acc);
171 }
172
173
174
175 template<typename T1>
176 arma_hot
177 inline
178 typename T1::pod_type
179 arma_vec_norm_2
180 (
181 const Proxy<T1>& P,
182 const typename arma_cx_only<typename T1::elem_type>::result* junk = 0
183 )
184 {
185 arma_extra_debug_sigprint();
186 arma_ignore(junk);
187
188 typedef typename T1::pod_type T;
189
190 T acc = T(0);
191
192 if(Proxy<T1>::prefer_at_accessor == false)
193 {
194 typename Proxy<T1>::ea_type A = P.get_ea();
195
196 const uword N = P.get_n_elem();
197
198 for(uword i=0; i<N; ++i)
199 {
200 const T tmp = std::abs(A[i]);
201 acc += tmp*tmp;
202 }
203 }
204 else
205 {
206 const uword n_rows = P.get_n_rows();
207 const uword n_cols = P.get_n_cols();
208
209 if(n_rows == 1)
210 {
211 for(uword col=0; col<n_cols; ++col)
212 {
213 const T tmp = std::abs(P.at(0,col));
214 acc += tmp*tmp;
215 }
216 }
217 else
218 {
219 for(uword col=0; col<n_cols; ++col)
220 for(uword row=0; row<n_rows; ++row)
221 {
222 const T tmp = std::abs(P.at(row,col));
223 acc += tmp*tmp;
224 }
225 }
226 }
227
228 return std::sqrt(acc);
229 }
230
231
232
233 template<typename T1>
234 arma_hot
235 inline
236 typename T1::pod_type
237 arma_vec_norm_k
238 (
239 const Proxy<T1>& P,
240 const int k
241 )
242 {
243 arma_extra_debug_sigprint();
244
245 typedef typename T1::pod_type T;
246
247 T acc = T(0);
248
249 if(Proxy<T1>::prefer_at_accessor == false)
250 {
251 typename Proxy<T1>::ea_type A = P.get_ea();
252
253 const uword N = P.get_n_elem();
254
255 uword i,j;
256
257 for(i=0, j=1; j<N; i+=2, j+=2)
258 {
259 acc += std::pow(std::abs(A[i]), k);
260 acc += std::pow(std::abs(A[j]), k);
261 }
262
263 if(i < N)
264 {
265 acc += std::pow(std::abs(A[i]), k);
266 }
267 }
268 else
269 {
270 const uword n_rows = P.get_n_rows();
271 const uword n_cols = P.get_n_cols();
272
273 if(n_rows != 1)
274 {
275 for(uword col=0; col < n_cols; ++col)
276 for(uword row=0; row < n_rows; ++row)
277 {
278 acc += std::pow(std::abs(P.at(row,col)), k);
279 }
280 }
281 else
282 {
283 for(uword col=0; col < n_cols; ++col)
284 {
285 acc += std::pow(std::abs(P.at(0,col)), k);
286 }
287 }
288 }
289
290 return std::pow(acc, T(1)/T(k));
291 }
292
293
294
295 template<typename T1>
296 arma_hot
297 inline
298 typename T1::pod_type
299 arma_vec_norm_max(const Proxy<T1>& P)
300 {
301 arma_extra_debug_sigprint();
302
303 typedef typename T1::pod_type T;
304
305 const uword N = P.get_n_elem();
306
307 T max_val = (N != 1) ? priv::most_neg<T>() : std::abs(P[0]);
308
309 if(Proxy<T1>::prefer_at_accessor == false)
310 {
311 typename Proxy<T1>::ea_type A = P.get_ea();
312
313 uword i,j;
314 for(i=0, j=1; j<N; i+=2, j+=2)
315 {
316 const T tmp_i = std::abs(A[i]);
317 const T tmp_j = std::abs(A[j]);
318
319 if(max_val < tmp_i) { max_val = tmp_i; }
320 if(max_val < tmp_j) { max_val = tmp_j; }
321 }
322
323 if(i < N)
324 {
325 const T tmp_i = std::abs(A[i]);
326
327 if(max_val < tmp_i) { max_val = tmp_i; }
328 }
329 }
330 else
331 {
332 const uword n_rows = P.get_n_rows();
333 const uword n_cols = P.get_n_cols();
334
335 if(n_rows != 1)
336 {
337 for(uword col=0; col < n_cols; ++col)
338 for(uword row=0; row < n_rows; ++row)
339 {
340 const T tmp = std::abs(P.at(row,col));
341
342 if(max_val < tmp) { max_val = tmp; }
343 }
344 }
345 else
346 {
347 for(uword col=0; col < n_cols; ++col)
348 {
349 const T tmp = std::abs(P.at(0,col));
350
351 if(max_val < tmp) { max_val = tmp; }
352 }
353 }
354 }
355
356 return max_val;
357 }
358
359
360
361 template<typename T1>
362 arma_hot
363 inline
364 typename T1::pod_type
365 arma_vec_norm_min(const Proxy<T1>& P)
366 {
367 arma_extra_debug_sigprint();
368
369 typedef typename T1::pod_type T;
370
371 const uword N = P.get_n_elem();
372
373 T min_val = (N != 1) ? priv::most_pos<T>() : std::abs(P[0]);
374
375 if(Proxy<T1>::prefer_at_accessor == false)
376 {
377 typename Proxy<T1>::ea_type A = P.get_ea();
378
379 uword i,j;
380 for(i=0, j=1; j<N; i+=2, j+=2)
381 {
382 const T tmp_i = std::abs(A[i]);
383 const T tmp_j = std::abs(A[j]);
384
385 if(min_val > tmp_i) { min_val = tmp_i; }
386 if(min_val > tmp_j) { min_val = tmp_j; }
387 }
388
389 if(i < N)
390 {
391 const T tmp_i = std::abs(A[i]);
392
393 if(min_val > tmp_i) { min_val = tmp_i; }
394 }
395 }
396 else
397 {
398 const uword n_rows = P.get_n_rows();
399 const uword n_cols = P.get_n_cols();
400
401 if(n_rows != 1)
402 {
403 for(uword col=0; col < n_cols; ++col)
404 for(uword row=0; row < n_rows; ++row)
405 {
406 const T tmp = std::abs(P.at(row,col));
407
408 if(min_val > tmp) { min_val = tmp; }
409 }
410 }
411 else
412 {
413 for(uword col=0; col < n_cols; ++col)
414 {
415 const T tmp = std::abs(P.at(0,col));
416
417 if(min_val > tmp) { min_val = tmp; }
418 }
419 }
420 }
421
422 return min_val;
423 }
424
425
426
427 template<typename T1>
428 inline
429 typename T1::pod_type
430 arma_mat_norm_1(const Proxy<T1>& P)
431 {
432 arma_extra_debug_sigprint();
433
434 // TODO: this can be sped up with a dedicated implementation
435 return as_scalar( max( sum(abs(P.Q), 0), 1) );
436 }
437
438
439
440 template<typename T1>
441 inline
442 typename T1::pod_type
443 arma_mat_norm_2(const Proxy<T1>& P)
444 {
445 arma_extra_debug_sigprint();
446
447 typedef typename T1::pod_type T;
448
449 // TODO: is the SVD based approach only valid for square matrices?
450
451 Col<T> S;
452 svd(S, P.Q);
453
454 return (S.n_elem > 0) ? max(S) : T(0);
455 }
456
457
458
459 template<typename T1>
460 inline
461 typename T1::pod_type
462 arma_mat_norm_inf(const Proxy<T1>& P)
463 {
464 arma_extra_debug_sigprint();
465
466 // TODO: this can be sped up with a dedicated implementation
467 return as_scalar( max( sum(abs(P.Q), 1), 0) );
468 }
469
470
471
472 template<typename T1>
473 inline
474 arma_warn_unused
475 typename enable_if2< is_arma_type<T1>::value, typename T1::pod_type >::result
476 norm
477 (
478 const T1& X,
479 const uword k,
480 const typename arma_real_or_cx_only<typename T1::elem_type>::result* junk = 0
481 )
482 {
483 arma_extra_debug_sigprint();
484 arma_ignore(junk);
485
486 typedef typename T1::pod_type T;
487
488 const Proxy<T1> P(X);
489
490 if(P.get_n_elem() == 0)
491 {
492 return T(0);
493 }
494
495 const bool is_vec = (P.get_n_rows() == 1) || (P.get_n_cols() == 1);
496
497 if(is_vec == true)
498 {
499 switch(k)
500 {
501 case 1:
502 return arma_vec_norm_1(P);
503 break;
504
505 case 2:
506 return arma_vec_norm_2(P);
507 break;
508
509 default:
510 {
511 arma_debug_check( (k == 0), "norm(): k must be greater than zero" );
512 return arma_vec_norm_k(P, int(k));
513 }
514 }
515 }
516 else
517 {
518 switch(k)
519 {
520 case 1:
521 return arma_mat_norm_1(P);
522 break;
523
524 case 2:
525 return arma_mat_norm_2(P);
526 break;
527
528 default:
529 arma_stop("norm(): unsupported matrix norm type");
530 return T(0);
531 }
532 }
533 }
534
535
536
537 template<typename T1>
538 inline
539 arma_warn_unused
540 typename enable_if2< is_arma_type<T1>::value, typename T1::pod_type >::result
541 norm
542 (
543 const T1& X,
544 const char* method,
545 const typename arma_real_or_cx_only<typename T1::elem_type>::result* junk = 0
546 )
547 {
548 arma_extra_debug_sigprint();
549 arma_ignore(junk);
550
551 typedef typename T1::pod_type T;
552
553 const Proxy<T1> P(X);
554
555 if(P.get_n_elem() == 0)
556 {
557 return T(0);
558 }
559
560 const char sig = method[0];
561 const bool is_vec = (P.get_n_rows() == 1) || (P.get_n_cols() == 1);
562
563 if(is_vec == true)
564 {
565 if( (sig == 'i') || (sig == 'I') || (sig == '+') ) // max norm
566 {
567 return arma_vec_norm_max(P);
568 }
569 else
570 if(sig == '-') // min norm
571 {
572 return arma_vec_norm_min(P);
573 }
574 else
575 if( (sig == 'f') || (sig == 'F') )
576 {
577 return arma_vec_norm_2(P);
578 }
579 else
580 {
581 arma_stop("norm(): unsupported vector norm type");
582 return T(0);
583 }
584 }
585 else
586 {
587 if( (sig == 'i') || (sig == 'I') || (sig == '+') ) // inf norm
588 {
589 return arma_mat_norm_inf(P);
590 }
591 else
592 if( (sig == 'f') || (sig == 'F') )
593 {
594 return arma_vec_norm_2(P);
595 }
596 else
597 {
598 arma_stop("norm(): unsupported matrix norm type");
599 return T(0);
600 }
601 }
602 }
603
604
605
606 //
607 // norms for sparse matrices
608
609
610
611 template<typename T1>
612 inline
613 typename T1::pod_type
614 arma_mat_norm_1(const SpProxy<T1>& P)
615 {
616 arma_extra_debug_sigprint();
617
618 // TODO: this can be sped up with a dedicated implementation
619 return as_scalar( max( sum(abs(P.Q), 0), 1) );
620 }
621
622
623
624 // template<typename T1>
625 // inline
626 // typename T1::pod_type
627 // arma_mat_norm_2(const SpProxy<T1>& P)
628 // {
629 // arma_extra_debug_sigprint();
630 //
631 // // TODO: norm = sqrt( largest eigenvalue of (A^H)*A ), where ^H is the conjugate transpose
632 // // TODO: can use ARPACK or directly implement the Arnoldi iteration
633 // // http://math.stackexchange.com/questions/4368/computing-the-largest-eigenvalue-of-a-very-large-sparse-matrix
634 // }
635
636
637
638 template<typename T1>
639 inline
640 typename T1::pod_type
641 arma_mat_norm_inf(const SpProxy<T1>& P)
642 {
643 arma_extra_debug_sigprint();
644
645 // TODO: this can be sped up with a dedicated implementation
646 return as_scalar( max( sum(abs(P.Q), 1), 0) );
647 }
648
649
650
651 template<typename T1>
652 inline
653 arma_warn_unused
654 typename enable_if2< is_arma_sparse_type<T1>::value, typename T1::pod_type >::result
655 norm
656 (
657 const T1& X,
658 const uword k,
659 const typename arma_real_or_cx_only<typename T1::elem_type>::result* junk = 0
660 )
661 {
662 arma_extra_debug_sigprint();
663 arma_ignore(junk);
664
665 typedef typename T1::elem_type eT;
666 typedef typename T1::pod_type T;
667
668 const SpProxy<T1> P(X);
669
670 if(P.get_n_nonzero() == 0)
671 {
672 return T(0);
673 }
674
675 const bool is_vec = (P.get_n_rows() == 1) || (P.get_n_cols() == 1);
676
677 if(is_vec == true)
678 {
679 const unwrap_spmat<typename SpProxy<T1>::stored_type> tmp(P.Q);
680 const SpMat<eT>& A = tmp.M;
681
682 // create a fake dense vector to allow reuse of code for dense vectors
683 Col<eT> fake_vector( access::rwp(A.values), A.n_nonzero, false );
684
685 const Proxy< Col<eT> > P_fake_vector(fake_vector);
686
687 switch(k)
688 {
689 case 1:
690 return arma_vec_norm_1(P_fake_vector);
691 break;
692
693 case 2:
694 return arma_vec_norm_2(P_fake_vector);
695 break;
696
697 default:
698 {
699 arma_debug_check( (k == 0), "norm(): k must be greater than zero" );
700 return arma_vec_norm_k(P_fake_vector, int(k));
701 }
702 }
703 }
704 else
705 {
706 switch(k)
707 {
708 case 1:
709 return arma_mat_norm_1(P);
710 break;
711
712 // case 2:
713 // return arma_mat_norm_2(P);
714 // break;
715
716 default:
717 arma_stop("norm(): unsupported or unimplemented norm type for sparse matrices");
718 return T(0);
719 }
720 }
721 }
722
723
724
725 template<typename T1>
726 inline
727 arma_warn_unused
728 typename enable_if2< is_arma_sparse_type<T1>::value, typename T1::pod_type >::result
729 norm
730 (
731 const T1& X,
732 const char* method,
733 const typename arma_real_or_cx_only<typename T1::elem_type>::result* junk = 0
734 )
735 {
736 arma_extra_debug_sigprint();
737 arma_ignore(junk);
738
739 typedef typename T1::elem_type eT;
740 typedef typename T1::pod_type T;
741
742 const SpProxy<T1> P(X);
743
744 if(P.get_n_nonzero() == 0)
745 {
746 return T(0);
747 }
748
749
750 const unwrap_spmat<typename SpProxy<T1>::stored_type> tmp(P.Q);
751 const SpMat<eT>& A = tmp.M;
752
753 // create a fake dense vector to allow reuse of code for dense vectors
754 Col<eT> fake_vector( access::rwp(A.values), A.n_nonzero, false );
755
756 const Proxy< Col<eT> > P_fake_vector(fake_vector);
757
758
759 const char sig = method[0];
760 const bool is_vec = (P.get_n_rows() == 1) || (P.get_n_cols() == 1);
761
762 if(is_vec == true)
763 {
764 if( (sig == 'i') || (sig == 'I') || (sig == '+') ) // max norm
765 {
766 return arma_vec_norm_max(P_fake_vector);
767 }
768 else
769 if(sig == '-') // min norm
770 {
771 const T val = arma_vec_norm_min(P_fake_vector);
772
773 if( P.get_n_nonzero() < P.get_n_elem() )
774 {
775 return (std::min)(T(0), val);
776 }
777 else
778 {
779 return val;
780 }
781 }
782 else
783 if( (sig == 'f') || (sig == 'F') )
784 {
785 return arma_vec_norm_2(P_fake_vector);
786 }
787 else
788 {
789 arma_stop("norm(): unsupported vector norm type");
790 return T(0);
791 }
792 }
793 else
794 {
795 if( (sig == 'i') || (sig == 'I') || (sig == '+') ) // inf norm
796 {
797 return arma_mat_norm_inf(P);
798 }
799 else
800 if( (sig == 'f') || (sig == 'F') )
801 {
802 return arma_vec_norm_2(P_fake_vector);
803 }
804 else
805 {
806 arma_stop("norm(): unsupported matrix norm type");
807 return T(0);
808 }
809 }
810 }
811
812
813
814 //! @}