agreement.cc 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // -*- mode: c++; coding: utf-8 -*-
  2. /// @file agreement.cc
  3. /// @brief Demo shape agreement rules
  4. // (c) Daniel Llorens - 2015-2016
  5. // This library is free software; you can redistribute it and/or modify it under
  6. // the terms of the GNU Lesser General Public License as published by the Free
  7. // Software Foundation; either version 3 of the License, or (at your option) any
  8. // later version.
  9. #include "ra/ra.hh"
  10. #include <iostream>
  11. using std::cout, std::endl;
  12. int main()
  13. {
  14. // The general shape agreement rule is 'prefix agreement': all the first
  15. // dimensions must match, all the second dimensions, etc. If some arguments
  16. // have lower rank than others, then the missing dimensions are ignored.
  17. // For example:
  18. ra::Big<float, 3> A({3, 4, 5}, 1.);
  19. ra::Big<float, 2> B({3, 4}, 2.);
  20. ra::Big<float, 1> C({3}, 3.);
  21. ra::Big<float, 3> X({3, 4, 5}, 99.);
  22. // In the following expression, the shapes of the arguments are:
  23. // A: [3 4 5]
  24. // B: [3 4]
  25. // C: [3]
  26. // X: [3 4 5] (taken from the shape of the right hand side)
  27. // All the first dimensions are 3, all the second dimensions are 4, and all
  28. // the third dimensions are 5, so the expression is valid.
  29. // Note that the agreement rules are applied equally to the destination argument.
  30. X = map([](auto && a, auto && b, auto && c) { return a+b-c; }, A, B, C);
  31. cout << "\nX: " << X << endl;
  32. // (you can write the expression above as X = A+B-C).
  33. // This rule comes from the array language J (for function rank 0; see J's
  34. // documentation). Obvious examples include:
  35. {
  36. // multiply any array by a scalar. The shape of a scalar is [];
  37. // therefore, a scalar agrees with anything.
  38. ra::Big<float, 2> X = B*7.;
  39. cout << "\nB*7: " << X << endl;
  40. }
  41. {
  42. // multiply each row of B by a different element of C, X(i, j) = B(i, j)*C(i)
  43. ra::Big<float, 2> X = B*C;
  44. cout << "\nB*C: " << X << endl;
  45. }
  46. {
  47. // multiply arrays componentwise (identical shapes agree).
  48. ra::Big<float, 2> X = B*B;
  49. cout << "\nB*B: " << X << endl;
  50. }
  51. // Some special expressions, such as tensor indices, do not have a
  52. // shape. Therefore they need to be accompanied by some other expression
  53. // that does have a shape, or the overall expression is not valid. That's
  54. // why you can do
  55. {
  56. ra::TensorIndex<0> i;
  57. ra::TensorIndex<1> j;
  58. ra::Big<float, 2> X({3, 4}, i-j);
  59. cout << "\ni-j: " << X << endl;
  60. }
  61. // but the following would be invalid:
  62. {
  63. // ra::_0 i;
  64. // ra::_1 j;
  65. // ra::Big<float, 2> X = i-j; // no shape to construct X with
  66. }
  67. // Axis insertion lets you match arguments more flexibly than simple prefix matching.
  68. {
  69. ra::Big<float, 2> A({3, 4}, 0);
  70. ra::Big<float, 1> b({3}, ra::_0);
  71. ra::Big<float, 1> c({4}, ra::_0);
  72. // Compare:
  73. // [3 4] matches [3] - normal prefix matching. Assign b(i) to A(i, ...)
  74. A = b;
  75. cout << "\nA: " << A << endl;
  76. // [3 4] matches [X 4] - skip 1 dimension when matching. Assign c(i) to A(..., i)
  77. A = c(ra::insert<1>);
  78. cout << "\nA: " << A << endl;
  79. }
  80. return 0;
  81. }