spop_max_meat.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. // Copyright 2008-2016 Conrad Sanderson (http://conradsanderson.id.au)
  2. // Copyright 2008-2016 National ICT Australia (NICTA)
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // ------------------------------------------------------------------------
  15. //! \addtogroup spop_max
  16. //! @{
  17. template<typename T1>
  18. inline
  19. void
  20. spop_max::apply(SpMat<typename T1::elem_type>& out, const SpOp<T1,spop_max>& in)
  21. {
  22. arma_extra_debug_sigprint();
  23. const uword dim = in.aux_uword_a;
  24. arma_debug_check( (dim > 1), "max(): parameter 'dim' must be 0 or 1" );
  25. const SpProxy<T1> p(in.m);
  26. const uword p_n_rows = p.get_n_rows();
  27. const uword p_n_cols = p.get_n_cols();
  28. if( (p_n_rows == 0) || (p_n_cols == 0) || (p.get_n_nonzero() == 0) )
  29. {
  30. if(dim == 0) { out.zeros((p_n_rows > 0) ? 1 : 0, p_n_cols); }
  31. if(dim == 1) { out.zeros(p_n_rows, (p_n_cols > 0) ? 1 : 0); }
  32. return;
  33. }
  34. spop_max::apply_proxy(out, p, dim);
  35. }
  36. template<typename T1>
  37. inline
  38. void
  39. spop_max::apply_proxy
  40. (
  41. SpMat<typename T1::elem_type>& out,
  42. const SpProxy<T1>& p,
  43. const uword dim,
  44. const typename arma_not_cx<typename T1::elem_type>::result* junk
  45. )
  46. {
  47. arma_extra_debug_sigprint();
  48. arma_ignore(junk);
  49. typedef typename T1::elem_type eT;
  50. typename SpProxy<T1>::const_iterator_type it = p.begin();
  51. typename SpProxy<T1>::const_iterator_type it_end = p.end();
  52. const uword p_n_cols = p.get_n_cols();
  53. const uword p_n_rows = p.get_n_rows();
  54. if(dim == 0) // find the maximum in each column
  55. {
  56. Row<eT> value(p_n_cols, fill::zeros);
  57. urowvec count(p_n_cols, fill::zeros);
  58. while(it != it_end)
  59. {
  60. const uword col = it.col();
  61. value[col] = (count[col] == 0) ? (*it) : (std::max)(value[col], (*it));
  62. count[col]++;
  63. ++it;
  64. }
  65. for(uword col=0; col<p_n_cols; ++col)
  66. {
  67. if(count[col] < p_n_rows) { value[col] = (std::max)(value[col], eT(0)); }
  68. }
  69. out = value;
  70. }
  71. else
  72. if(dim == 1) // find the maximum in each row
  73. {
  74. Col<eT> value(p_n_rows, fill::zeros);
  75. ucolvec count(p_n_rows, fill::zeros);
  76. while(it != it_end)
  77. {
  78. const uword row = it.row();
  79. value[row] = (count[row] == 0) ? (*it) : (std::max)(value[row], (*it));
  80. count[row]++;
  81. ++it;
  82. }
  83. for(uword row=0; row<p_n_rows; ++row)
  84. {
  85. if(count[row] < p_n_cols) { value[row] = (std::max)(value[row], eT(0)); }
  86. }
  87. out = value;
  88. }
  89. }
  90. template<typename T1>
  91. inline
  92. typename T1::elem_type
  93. spop_max::vector_max
  94. (
  95. const T1& x,
  96. const typename arma_not_cx<typename T1::elem_type>::result* junk
  97. )
  98. {
  99. arma_extra_debug_sigprint();
  100. arma_ignore(junk);
  101. typedef typename T1::elem_type eT;
  102. const SpProxy<T1> p(x);
  103. if(p.get_n_elem() == 0)
  104. {
  105. arma_debug_check(true, "max(): object has no elements");
  106. return Datum<eT>::nan;
  107. }
  108. if(p.get_n_nonzero() == 0) { return eT(0); }
  109. if(SpProxy<T1>::use_iterator == false)
  110. {
  111. // direct access of values
  112. if(p.get_n_nonzero() == p.get_n_elem())
  113. {
  114. return op_max::direct_max(p.get_values(), p.get_n_nonzero());
  115. }
  116. else
  117. {
  118. return std::max(eT(0), op_max::direct_max(p.get_values(), p.get_n_nonzero()));
  119. }
  120. }
  121. else
  122. {
  123. // use iterator
  124. typename SpProxy<T1>::const_iterator_type it = p.begin();
  125. typename SpProxy<T1>::const_iterator_type it_end = p.end();
  126. eT result = (*it);
  127. ++it;
  128. while(it != it_end)
  129. {
  130. if((*it) > result) { result = (*it); }
  131. ++it;
  132. }
  133. if(p.get_n_nonzero() == p.get_n_elem())
  134. {
  135. return result;
  136. }
  137. else
  138. {
  139. return std::max(eT(0), result);
  140. }
  141. }
  142. }
  143. template<typename T1>
  144. inline
  145. typename arma_not_cx<typename T1::elem_type>::result
  146. spop_max::max(const SpBase<typename T1::elem_type, T1>& X)
  147. {
  148. arma_extra_debug_sigprint();
  149. typedef typename T1::elem_type eT;
  150. const SpProxy<T1> P(X.get_ref());
  151. const uword n_elem = P.get_n_elem();
  152. const uword n_nonzero = P.get_n_nonzero();
  153. if(n_elem == 0)
  154. {
  155. arma_debug_check(true, "max(): object has no elements");
  156. return Datum<eT>::nan;
  157. }
  158. eT max_val = priv::most_neg<eT>();
  159. if(SpProxy<T1>::use_iterator)
  160. {
  161. // We have to iterate over the elements.
  162. typedef typename SpProxy<T1>::const_iterator_type it_type;
  163. it_type it = P.begin();
  164. it_type it_end = P.end();
  165. while (it != it_end)
  166. {
  167. if ((*it) > max_val) { max_val = *it; }
  168. ++it;
  169. }
  170. }
  171. else
  172. {
  173. // We can do direct access of the values, row_indices, and col_ptrs.
  174. // We don't need the location of the max value, so we can just call out to
  175. // other functions...
  176. max_val = op_max::direct_max(P.get_values(), n_nonzero);
  177. }
  178. if(n_elem == n_nonzero)
  179. {
  180. return max_val;
  181. }
  182. else
  183. {
  184. return std::max(eT(0), max_val);
  185. }
  186. }
  187. template<typename T1>
  188. inline
  189. typename arma_not_cx<typename T1::elem_type>::result
  190. spop_max::max_with_index(const SpProxy<T1>& P, uword& index_of_max_val)
  191. {
  192. arma_extra_debug_sigprint();
  193. typedef typename T1::elem_type eT;
  194. const uword n_elem = P.get_n_elem();
  195. const uword n_nonzero = P.get_n_nonzero();
  196. const uword n_rows = P.get_n_rows();
  197. if(n_elem == 0)
  198. {
  199. arma_debug_check(true, "max(): object has no elements");
  200. index_of_max_val = uword(0);
  201. return Datum<eT>::nan;
  202. }
  203. eT max_val = priv::most_neg<eT>();
  204. if(SpProxy<T1>::use_iterator)
  205. {
  206. // We have to iterate over the elements.
  207. typedef typename SpProxy<T1>::const_iterator_type it_type;
  208. it_type it = P.begin();
  209. it_type it_end = P.end();
  210. while (it != it_end)
  211. {
  212. if ((*it) > max_val)
  213. {
  214. max_val = *it;
  215. index_of_max_val = it.row() + it.col() * n_rows;
  216. }
  217. ++it;
  218. }
  219. }
  220. else
  221. {
  222. // We can do direct access.
  223. max_val = op_max::direct_max(P.get_values(), n_nonzero, index_of_max_val);
  224. // Convert to actual position in matrix.
  225. const uword row = P.get_row_indices()[index_of_max_val];
  226. uword col = 0;
  227. while (P.get_col_ptrs()[++col] <= index_of_max_val) { }
  228. index_of_max_val = (col - 1) * n_rows + row;
  229. }
  230. if(n_elem != n_nonzero)
  231. {
  232. max_val = std::max(eT(0), max_val);
  233. // If the max_val is a nonzero element, we need its actual position in the matrix.
  234. if(max_val == eT(0))
  235. {
  236. // Find first zero element.
  237. uword last_row = 0;
  238. uword last_col = 0;
  239. typedef typename SpProxy<T1>::const_iterator_type it_type;
  240. it_type it = P.begin();
  241. it_type it_end = P.end();
  242. while (it != it_end)
  243. {
  244. // Have we moved more than one position from the last place?
  245. if ((it.col() == last_col) && (it.row() - last_row > 1))
  246. {
  247. index_of_max_val = it.col() * n_rows + last_row + 1;
  248. break;
  249. }
  250. else if ((it.col() >= last_col + 1) && (last_row < n_rows - 1))
  251. {
  252. index_of_max_val = last_col * n_rows + last_row + 1;
  253. break;
  254. }
  255. else if ((it.col() == last_col + 1) && (it.row() > 0))
  256. {
  257. index_of_max_val = it.col() * n_rows;
  258. break;
  259. }
  260. else if (it.col() > last_col + 1)
  261. {
  262. index_of_max_val = (last_col + 1) * n_rows;
  263. break;
  264. }
  265. last_row = it.row();
  266. last_col = it.col();
  267. ++it;
  268. }
  269. }
  270. }
  271. return max_val;
  272. }
  273. template<typename T1>
  274. inline
  275. void
  276. spop_max::apply_proxy
  277. (
  278. SpMat<typename T1::elem_type>& out,
  279. const SpProxy<T1>& p,
  280. const uword dim,
  281. const typename arma_cx_only<typename T1::elem_type>::result* junk
  282. )
  283. {
  284. arma_extra_debug_sigprint();
  285. arma_ignore(junk);
  286. typedef typename T1::elem_type eT;
  287. typedef typename get_pod_type<eT>::result T;
  288. typename SpProxy<T1>::const_iterator_type it = p.begin();
  289. typename SpProxy<T1>::const_iterator_type it_end = p.end();
  290. const uword p_n_cols = p.get_n_cols();
  291. const uword p_n_rows = p.get_n_rows();
  292. if(dim == 0) // find the maximum in each column
  293. {
  294. Row<eT> rawval(p_n_cols, fill::zeros);
  295. Row< T> absval(p_n_cols, fill::zeros);
  296. while(it != it_end)
  297. {
  298. const uword col = it.col();
  299. const eT& v = (*it);
  300. const T a = std::abs(v);
  301. if(a > absval[col])
  302. {
  303. absval[col] = a;
  304. rawval[col] = v;
  305. }
  306. ++it;
  307. }
  308. out = rawval;
  309. }
  310. else
  311. if(dim == 1) // find the maximum in each row
  312. {
  313. Col<eT> rawval(p_n_rows, fill::zeros);
  314. Col< T> absval(p_n_rows, fill::zeros);
  315. while(it != it_end)
  316. {
  317. const uword row = it.row();
  318. const eT& v = (*it);
  319. const T a = std::abs(v);
  320. if(a > absval[row])
  321. {
  322. absval[row] = a;
  323. rawval[row] = v;
  324. }
  325. ++it;
  326. }
  327. out = rawval;
  328. }
  329. }
  330. template<typename T1>
  331. inline
  332. typename T1::elem_type
  333. spop_max::vector_max
  334. (
  335. const T1& x,
  336. const typename arma_cx_only<typename T1::elem_type>::result* junk
  337. )
  338. {
  339. arma_extra_debug_sigprint();
  340. arma_ignore(junk);
  341. typedef typename T1::elem_type eT;
  342. typedef typename get_pod_type<eT>::result T;
  343. const SpProxy<T1> p(x);
  344. if(p.get_n_elem() == 0)
  345. {
  346. arma_debug_check(true, "max(): object has no elements");
  347. return Datum<eT>::nan;
  348. }
  349. if(p.get_n_nonzero() == 0) { return eT(0); }
  350. if(SpProxy<T1>::use_iterator == false)
  351. {
  352. // direct access of values
  353. if(p.get_n_nonzero() == p.get_n_elem())
  354. {
  355. return op_max::direct_max(p.get_values(), p.get_n_nonzero());
  356. }
  357. else
  358. {
  359. const eT val1 = eT(0);
  360. const eT val2 = op_max::direct_max(p.get_values(), p.get_n_nonzero());
  361. return ( std::abs(val1) >= std::abs(val2) ) ? val1 : val2;
  362. }
  363. }
  364. else
  365. {
  366. // use iterator
  367. typename SpProxy<T1>::const_iterator_type it = p.begin();
  368. typename SpProxy<T1>::const_iterator_type it_end = p.end();
  369. eT best_val_orig = *it;
  370. T best_val_abs = std::abs(best_val_orig);
  371. ++it;
  372. while(it != it_end)
  373. {
  374. eT val_orig = *it;
  375. T val_abs = std::abs(val_orig);
  376. if(val_abs > best_val_abs)
  377. {
  378. best_val_abs = val_abs;
  379. best_val_orig = val_orig;
  380. }
  381. ++it;
  382. }
  383. if(p.get_n_nonzero() == p.get_n_elem())
  384. {
  385. return best_val_orig;
  386. }
  387. else
  388. {
  389. const eT val1 = eT(0);
  390. return ( std::abs(val1) >= best_val_abs ) ? val1 : best_val_orig;
  391. }
  392. }
  393. }
  394. template<typename T1>
  395. inline
  396. typename arma_cx_only<typename T1::elem_type>::result
  397. spop_max::max(const SpBase<typename T1::elem_type, T1>& X)
  398. {
  399. arma_extra_debug_sigprint();
  400. typedef typename T1::elem_type eT;
  401. typedef typename get_pod_type<eT>::result T;
  402. const SpProxy<T1> P(X.get_ref());
  403. const uword n_elem = P.get_n_elem();
  404. const uword n_nonzero = P.get_n_nonzero();
  405. if(n_elem == 0)
  406. {
  407. arma_debug_check(true, "max(): object has no elements");
  408. return Datum<eT>::nan;
  409. }
  410. T max_val = priv::most_neg<T>();
  411. eT ret_val;
  412. if(SpProxy<T1>::use_iterator)
  413. {
  414. // We have to iterate over the elements.
  415. typedef typename SpProxy<T1>::const_iterator_type it_type;
  416. it_type it = P.begin();
  417. it_type it_end = P.end();
  418. while (it != it_end)
  419. {
  420. const T tmp_val = std::abs(*it);
  421. if (tmp_val > max_val)
  422. {
  423. max_val = tmp_val;
  424. ret_val = *it;
  425. }
  426. ++it;
  427. }
  428. }
  429. else
  430. {
  431. // We can do direct access of the values, row_indices, and col_ptrs.
  432. // We don't need the location of the max value, so we can just call out to
  433. // other functions...
  434. ret_val = op_max::direct_max(P.get_values(), n_nonzero);
  435. max_val = std::abs(ret_val);
  436. }
  437. if(n_elem == n_nonzero)
  438. {
  439. return max_val;
  440. }
  441. else
  442. {
  443. return (T(0) > max_val) ? eT(0) : ret_val;
  444. }
  445. }
  446. template<typename T1>
  447. inline
  448. typename arma_cx_only<typename T1::elem_type>::result
  449. spop_max::max_with_index(const SpProxy<T1>& P, uword& index_of_max_val)
  450. {
  451. arma_extra_debug_sigprint();
  452. typedef typename T1::elem_type eT;
  453. typedef typename get_pod_type<eT>::result T;
  454. const uword n_elem = P.get_n_elem();
  455. const uword n_nonzero = P.get_n_nonzero();
  456. const uword n_rows = P.get_n_rows();
  457. if(n_elem == 0)
  458. {
  459. arma_debug_check(true, "max(): object has no elements");
  460. index_of_max_val = uword(0);
  461. return Datum<eT>::nan;
  462. }
  463. T max_val = priv::most_neg<T>();
  464. if(SpProxy<T1>::use_iterator)
  465. {
  466. // We have to iterate over the elements.
  467. typedef typename SpProxy<T1>::const_iterator_type it_type;
  468. it_type it = P.begin();
  469. it_type it_end = P.end();
  470. while (it != it_end)
  471. {
  472. const T tmp_val = std::abs(*it);
  473. if (tmp_val > max_val)
  474. {
  475. max_val = tmp_val;
  476. index_of_max_val = it.row() + it.col() * n_rows;
  477. }
  478. ++it;
  479. }
  480. }
  481. else
  482. {
  483. // We can do direct access.
  484. max_val = std::abs(op_max::direct_max(P.get_values(), n_nonzero, index_of_max_val));
  485. // Convert to actual position in matrix.
  486. const uword row = P.get_row_indices()[index_of_max_val];
  487. uword col = 0;
  488. while (P.get_col_ptrs()[++col] <= index_of_max_val) { }
  489. index_of_max_val = (col - 1) * n_rows + row;
  490. }
  491. if(n_elem != n_nonzero)
  492. {
  493. max_val = std::max(T(0), max_val);
  494. // If the max_val is a nonzero element, we need its actual position in the matrix.
  495. if(max_val == T(0))
  496. {
  497. // Find first zero element.
  498. uword last_row = 0;
  499. uword last_col = 0;
  500. typedef typename SpProxy<T1>::const_iterator_type it_type;
  501. it_type it = P.begin();
  502. it_type it_end = P.end();
  503. while (it != it_end)
  504. {
  505. // Have we moved more than one position from the last place?
  506. if ((it.col() == last_col) && (it.row() - last_row > 1))
  507. {
  508. index_of_max_val = it.col() * n_rows + last_row + 1;
  509. break;
  510. }
  511. else if ((it.col() >= last_col + 1) && (last_row < n_rows - 1))
  512. {
  513. index_of_max_val = last_col * n_rows + last_row + 1;
  514. break;
  515. }
  516. else if ((it.col() == last_col + 1) && (it.row() > 0))
  517. {
  518. index_of_max_val = it.col() * n_rows;
  519. break;
  520. }
  521. else if (it.col() > last_col + 1)
  522. {
  523. index_of_max_val = (last_col + 1) * n_rows;
  524. break;
  525. }
  526. last_row = it.row();
  527. last_col = it.col();
  528. ++it;
  529. }
  530. }
  531. }
  532. return P[index_of_max_val];
  533. }
  534. //! @}