1 #include <stan/model/indexing.hpp>
2 #include <stan/math/rev/fun/sum.hpp>
3 #include <test/unit/util.hpp>
4 #include <test/unit/model/indexing/util.hpp>
5 #include <gtest/gtest.h>
6 #include <iostream>
7 #include <stdexcept>
8 #include <vector>
9 
10 using Eigen::Dynamic;
11 using Eigen::Matrix;
12 using Eigen::MatrixXd;
13 using Eigen::RowVectorXd;
14 using Eigen::VectorXd;
15 using stan::model::assign;
16 using stan::model::index_max;
17 using stan::model::index_min;
18 using stan::model::index_min_max;
19 using stan::model::index_multi;
20 using stan::model::index_omni;
21 using stan::model::index_uni;
22 using std::vector;
23 
24 struct VarAssign : public testing::Test {
SetUpVarAssign25   void SetUp() {
26     // make sure memory's clean before starting each test
27     stan::math::recover_memory();
28   }
TearDownVarAssign29   void TearDown() {
30     // make sure memory's clean before starting each test
31     stan::math::recover_memory();
32   }
33 };
34 
check_multi_duplicate(const stan::arena_t<std::vector<std::array<int,2>>> & x_idx,int i,int j)35 inline bool check_multi_duplicate(
36     const stan::arena_t<std::vector<std::array<int, 2>>>& x_idx, int i, int j) {
37   for (size_t k = 0; k < x_idx.size(); ++k) {
38     if (x_idx[k][0] == i && x_idx[k][1] == j) {
39       return true;
40     }
41   }
42   return false;
43 }
44 
check_multi_duplicate(const stan::arena_t<std::vector<int>> & x_idx,int i)45 inline bool check_multi_duplicate(const stan::arena_t<std::vector<int>>& x_idx,
46                                   int i) {
47   for (size_t k = 0; k < x_idx.size(); ++k) {
48     if (x_idx[k] == i) {
49       return true;
50     }
51   }
52   return false;
53 }
54 
55 template <typename T1, typename T2, typename... I>
test_throw_out_of_range(T1 & lhs,const T2 & rhs,const I &...idxs)56 void test_throw_out_of_range(T1& lhs, const T2& rhs, const I&... idxs) {
57   EXPECT_THROW(stan::model::assign(lhs, rhs, "", idxs...), std::out_of_range);
58 }
59 
60 template <typename T1, typename T2, typename... I>
test_throw_invalid_arg(T1 & lhs,const T2 & rhs,const I &...idxs)61 void test_throw_invalid_arg(T1& lhs, const T2& rhs, const I&... idxs) {
62   EXPECT_THROW(stan::model::assign(lhs, rhs, "", idxs...),
63                std::invalid_argument);
64 }
65 
66 template <typename Vec, typename RhsScalar>
test_nil_vec()67 void test_nil_vec() {
68   using stan::math::var;
69   using stan::math::var_value;
70   using stan::model::test::check_adjs;
71   using stan::model::test::conditionally_generate_linear_var_vector;
72   auto x = conditionally_generate_linear_var_vector<Vec, var>(5);
73   Eigen::VectorXd x_val = x.val();
74   auto y = conditionally_generate_linear_var_vector<Vec, RhsScalar>(5, 1.0);
75   assign(x, y, "");
76   EXPECT_MATRIX_EQ(x.val(), stan::math::value_of(y));
77   stan::math::sum(x).grad();
78   auto check_all = [](int i) { return true; };
79   if (stan::is_var<RhsScalar>::value) {
80     EXPECT_MATRIX_EQ(x.val(), stan::math::value_of(y));
81     check_adjs(check_all, x, "lhs", 1);
82     check_adjs(check_all, y, "rhs", 1);
83   } else {
84     EXPECT_MATRIX_EQ(x.val(), x_val);
85     check_adjs(check_all, x, "lhs", 0.0);
86   }
87 }
TEST_F(VarAssign,nil)88 TEST_F(VarAssign, nil) {
89   test_nil_vec<Eigen::VectorXd, stan::math::var>();
90   test_nil_vec<Eigen::VectorXd, double>();
91 }
92 
93 template <typename Vec, typename RhsScalar>
test_uni_vec()94 void test_uni_vec() {
95   using stan::math::sum;
96   using stan::math::var_value;
97   using stan::model::test::check_adjs;
98   using stan::model::test::conditionally_generate_linear_var_vector;
99   auto x = conditionally_generate_linear_var_vector<Vec>(5);
100   Vec x_val = x.val();
101   RhsScalar y(18);
102   assign(x, y, "", index_uni(2));
103   EXPECT_FLOAT_EQ(stan::math::value_of(y), x.val()[1]);
104   stan::math::sum(x).grad();
105   EXPECT_MATRIX_EQ(x.val(), x_val);
106   auto check_i = [](int i) { return i != 1; };
107   check_adjs(check_i, x, "lhs");
108   check_adjs(y, "rhs", 1);
109   test_throw_out_of_range(x, y, index_uni(0));
110   test_throw_out_of_range(x, y, index_uni(6));
111 }
112 
TEST_F(VarAssign,uni_vec)113 TEST_F(VarAssign, uni_vec) {
114   test_uni_vec<Eigen::VectorXd, stan::math::var>();
115   test_uni_vec<Eigen::VectorXd, double>();
116 }
117 
TEST_F(VarAssign,uni_rowvec)118 TEST_F(VarAssign, uni_rowvec) {
119   test_uni_vec<Eigen::RowVectorXd, stan::math::var>();
120   test_uni_vec<Eigen::RowVectorXd, double>();
121 }
122 
123 template <typename Vec, typename RhsScalar>
test_multi_vec()124 void test_multi_vec() {
125   using stan::math::sum;
126   using stan::math::var_value;
127   using stan::model::test::check_adjs;
128   using stan::model::test::conditionally_generate_linear_var_vector;
129   auto x = conditionally_generate_linear_var_vector<Vec>(5);
130   Vec x_val = x.val();
131   auto y = conditionally_generate_linear_var_vector<Vec, RhsScalar>(3, 10);
132   vector<int> ns;
133   ns.push_back(2);
134   ns.push_back(4);
135   ns.push_back(2);
136   assign(x, y, "", index_multi(ns));
137   EXPECT_FLOAT_EQ(stan::math::value_of(y)[1], x.val()[3]);
138   EXPECT_FLOAT_EQ(stan::math::value_of(y)[2], x.val()[1]);
139   stan::math::sum(x).grad();
140   EXPECT_MATRIX_EQ(x.val(), x_val);
141   auto check_i_x = [](int i) { return i == 1 || i == 3; };
142   check_adjs(check_i_x, x, "lhs", 0);
143   auto check_i_y = [](int i) { return i > 0; };
144   check_adjs(check_i_y, y, "rhs", 1);
145   ns[2] = 20;
146   test_throw_out_of_range(x, y, index_multi(ns));
147   ns[2] = 0;
148   test_throw_out_of_range(x, y, index_multi(ns));
149   ns.push_back(2);
150   test_throw_invalid_arg(x, y, index_multi(ns));
151   ns.pop_back();
152   test_throw_invalid_arg(x, conditionally_generate_linear_var_vector<Vec>(4),
153                          index_multi(ns));
154   test_throw_invalid_arg(x, conditionally_generate_linear_var_vector<Vec>(2),
155                          index_multi(ns));
156 }
157 
TEST_F(VarAssign,multi_vec)158 TEST_F(VarAssign, multi_vec) {
159   test_multi_vec<Eigen::VectorXd, stan::math::var>();
160   test_multi_vec<Eigen::VectorXd, double>();
161 }
162 
TEST_F(VarAssign,multi_rowvec)163 TEST_F(VarAssign, multi_rowvec) {
164   test_multi_vec<Eigen::RowVectorXd, stan::math::var>();
165   test_multi_vec<Eigen::RowVectorXd, double>();
166 }
167 
168 template <typename Vec>
test_multi_alias_vec()169 void test_multi_alias_vec() {
170   using stan::math::sum;
171   using stan::math::var_value;
172   using stan::model::test::check_adjs;
173   using stan::model::test::conditionally_generate_linear_var_vector;
174   auto x = conditionally_generate_linear_var_vector<Eigen::VectorXd>(5, 1);
175   Eigen::VectorXd x_val = x.val();
176   vector<int> ns{1, 1, 2, 3};
177   assign(x, x.segment(1, 4), "", index_multi(ns));
178   EXPECT_MATRIX_EQ(x.val().segment(0, 3), x_val.segment(2, 3));
179   EXPECT_MATRIX_EQ(x.val().segment(3, 2), x_val.segment(3, 2));
180   stan::math::sum(x).grad();
181   EXPECT_MATRIX_EQ(x.val(), x_val);
182   Eigen::VectorXd exp_adj(5);
183   exp_adj << 0, 0, 1, 2, 2;
184   EXPECT_MATRIX_EQ(x.adj(), exp_adj);
185 }
186 
TEST_F(VarAssign,multi_alias_vec)187 TEST_F(VarAssign, multi_alias_vec) { test_multi_alias_vec<Eigen::VectorXd>(); }
188 
189 template <typename Vec, typename RhsScalar>
test_omni_vec()190 void test_omni_vec() {
191   using stan::math::sum;
192   using stan::math::var_value;
193   using stan::model::test::check_adjs;
194   using stan::model::test::conditionally_generate_linear_var_vector;
195   auto x = conditionally_generate_linear_var_vector<Vec>(5);
196   Vec x_val = stan::math::value_of(x);
197   auto y = conditionally_generate_linear_var_vector<Vec, RhsScalar>(5, 10);
198   Vec y_val = stan::math::value_of(y);
199   auto x_copy = var_value<Vec>(x.vi_);
200   assign(x, y, "", index_omni());
201   EXPECT_FLOAT_EQ(y_val[0], x.val()[0]);
202   EXPECT_FLOAT_EQ(y_val[1], x.val()[1]);
203   EXPECT_FLOAT_EQ(y_val[2], x.val()[2]);
204   EXPECT_FLOAT_EQ(y_val[3], x.val()[3]);
205   EXPECT_FLOAT_EQ(y_val[4], x.val()[4]);
206   sum(x).grad();
207   if (stan::is_var<RhsScalar>::value) {
208     EXPECT_MATRIX_EQ(x.val(), y_val);
209     EXPECT_MATRIX_EQ(x_copy.val(), x_val);
210   } else {
211     EXPECT_MATRIX_EQ(x.val(), x_val);
212   }
213   auto check_i = [](int i) { return true; };
214   if (stan::is_var<RhsScalar>::value) {
215     check_adjs(check_i, x, "lhs", 1.0);
216   } else {
217     check_adjs(check_i, x, "lhs", 0.0);
218   }
219   check_adjs(check_i, y, "rhs", 1.0);
220   test_throw_invalid_arg(
221       x, conditionally_generate_linear_var_vector<Vec, RhsScalar>(4),
222       index_omni());
223   test_throw_invalid_arg(
224       x, conditionally_generate_linear_var_vector<Vec, RhsScalar>(6),
225       index_omni());
226 }
227 
TEST_F(VarAssign,omni_vec)228 TEST_F(VarAssign, omni_vec) {
229   test_omni_vec<Eigen::VectorXd, stan::math::var>();
230   test_omni_vec<Eigen::VectorXd, double>();
231 }
232 
TEST_F(VarAssign,omni_rowvec)233 TEST_F(VarAssign, omni_rowvec) {
234   test_omni_vec<Eigen::RowVectorXd, stan::math::var>();
235   test_omni_vec<Eigen::RowVectorXd, double>();
236 }
237 
238 template <typename Vec, typename RhsScalar>
test_min_vec()239 void test_min_vec() {
240   using stan::math::sum;
241   using stan::math::var_value;
242   using stan::model::test::check_adjs;
243   using stan::model::test::conditionally_generate_linear_var_vector;
244   auto x = conditionally_generate_linear_var_vector<Vec>(5);
245   auto y = conditionally_generate_linear_var_vector<Vec, RhsScalar>(3, 10);
246   Vec x_val(x.val());
247   auto y_val = stan::math::value_of(y).eval();
248   assign(x, y, "", index_min(3));
249   EXPECT_FLOAT_EQ(x.val()(2), y_val(0));
250   EXPECT_FLOAT_EQ(x.val()(3), y_val(1));
251   EXPECT_FLOAT_EQ(x.val()(4), y_val(2));
252   sum(x).grad();
253   EXPECT_MATRIX_EQ(x.val(), x_val);
254   auto check_i = [](int i) { return i < 2; };
255   check_adjs(check_i, x, "lhs");
256   check_adjs([](int /* i */) { return true; }, y, "rhs");
257   test_throw_out_of_range(x, y, index_min(0));
258   test_throw_out_of_range(x, y, index_min(6));
259   test_throw_invalid_arg(x, conditionally_generate_linear_var_vector<Vec>(4),
260                          index_min(3));
261   test_throw_invalid_arg(x, conditionally_generate_linear_var_vector<Vec>(2),
262                          index_min(3));
263 }
TEST_F(VarAssign,min_vec)264 TEST_F(VarAssign, min_vec) {
265   test_min_vec<Eigen::VectorXd, stan::math::var>();
266   test_min_vec<Eigen::VectorXd, double>();
267 }
268 
TEST_F(VarAssign,min_rowvec)269 TEST_F(VarAssign, min_rowvec) {
270   test_min_vec<Eigen::RowVectorXd, stan::math::var>();
271   test_min_vec<Eigen::RowVectorXd, double>();
272 }
273 
274 template <typename Vec, typename RhsScalar>
test_max_vec()275 void test_max_vec() {
276   using stan::math::sum;
277   using stan::math::var_value;
278   using stan::model::test::check_adjs;
279   using stan::model::test::conditionally_generate_linear_var_vector;
280   auto x = conditionally_generate_linear_var_vector<Vec>(5);
281   Vec x_val = x.val();
282   auto y = conditionally_generate_linear_var_vector<Vec, RhsScalar>(2, 10);
283   auto y_val = stan::math::value_of(y);
284   assign(x, y, "", index_max(2));
285   EXPECT_FLOAT_EQ(y_val[0], x.val()[0]);
286   EXPECT_FLOAT_EQ(y_val[1], x.val()[1]);
287   stan::math::sum(x).grad();
288   EXPECT_MATRIX_EQ(x.val(), x_val);
289   auto check_i = [](int i) { return i > 1; };
290   check_adjs(check_i, x, "lhs");
291   check_adjs([](int /* i */) { return true; }, y, "rhs");
292   test_throw_out_of_range(x, y, index_max(0));
293   test_throw_out_of_range(x, y, index_max(6));
294   test_throw_invalid_arg(x, conditionally_generate_linear_var_vector<Vec>(3),
295                          index_max(2));
296   test_throw_invalid_arg(x, conditionally_generate_linear_var_vector<Vec>(1),
297                          index_max(2));
298 }
299 
TEST_F(VarAssign,max_vec)300 TEST_F(VarAssign, max_vec) {
301   test_max_vec<Eigen::VectorXd, stan::math::var>();
302   test_max_vec<Eigen::VectorXd, double>();
303 }
304 
TEST_F(VarAssign,max_rowvec)305 TEST_F(VarAssign, max_rowvec) {
306   test_max_vec<Eigen::RowVectorXd, stan::math::var>();
307   test_max_vec<Eigen::RowVectorXd, double>();
308 }
309 
310 template <typename Vec, typename RhsScalar>
test_positive_minmax_varvector()311 void test_positive_minmax_varvector() {
312   using stan::math::sum;
313   using stan::math::var_value;
314   using stan::model::test::check_adjs;
315   using stan::model::test::conditionally_generate_linear_var_vector;
316   auto x = conditionally_generate_linear_var_vector<Vec>(5);
317   Vec x_val = x.val();
318   auto y = conditionally_generate_linear_var_vector<Vec, RhsScalar>(4, 10);
319 
320   assign(x, y, "", index_min_max(1, 4));
321   EXPECT_FLOAT_EQ(x.val()(0), 10);
322   EXPECT_FLOAT_EQ(x.val()(1), 11);
323   EXPECT_FLOAT_EQ(x.val()(2), 12);
324   EXPECT_FLOAT_EQ(x.val()(3), 13);
325   EXPECT_FLOAT_EQ(x.val()(4), 4);
326   sum(x).grad();
327   EXPECT_MATRIX_EQ(x.val(), x_val);
328   auto check_i = [](int i) { return (i > 3); };
329   check_adjs(check_i, x, "lhs");
330   check_adjs([](int /* i */) { return true; }, y, "rhs");
331   test_throw_out_of_range(x, y, index_min_max(0, 3));
332   test_throw_out_of_range(x, y, index_min_max(1, 6));
333   test_throw_invalid_arg(x, conditionally_generate_linear_var_vector<Vec>(5),
334                          index_min_max(1, 4));
335   test_throw_invalid_arg(x, conditionally_generate_linear_var_vector<Vec>(3),
336                          index_min_max(1, 4));
337 }
338 
TEST_F(VarAssign,positive_minmax_vec)339 TEST_F(VarAssign, positive_minmax_vec) {
340   test_positive_minmax_varvector<Eigen::VectorXd, stan::math::var>();
341   test_positive_minmax_varvector<Eigen::VectorXd, double>();
342 }
343 
TEST_F(VarAssign,positive_minmax_rowvec)344 TEST_F(VarAssign, positive_minmax_rowvec) {
345   test_positive_minmax_varvector<Eigen::RowVectorXd, stan::math::var>();
346   test_positive_minmax_varvector<Eigen::RowVectorXd, double>();
347 }
348 
349 template <typename Vec, typename RhsScalar>
test_negative_minmax_varvector()350 void test_negative_minmax_varvector() {
351   using stan::math::sum;
352   using stan::math::var_value;
353   using stan::model::test::check_adjs;
354   using stan::model::test::conditionally_generate_linear_var_vector;
355   auto x = conditionally_generate_linear_var_vector<Vec>(5);
356   Vec x_val = x.val();
357   auto y = conditionally_generate_linear_var_vector<Vec, RhsScalar>(4, 10);
358 
359   assign(x, y, "", index_min_max(4, 1));
360   EXPECT_FLOAT_EQ(x.val()(0), 13);
361   EXPECT_FLOAT_EQ(x.val()(1), 12);
362   EXPECT_FLOAT_EQ(x.val()(2), 11);
363   EXPECT_FLOAT_EQ(x.val()(3), 10);
364   EXPECT_FLOAT_EQ(x.val()(4), 4);
365   sum(x).grad();
366   EXPECT_MATRIX_EQ(x.val(), x_val);
367   auto check_i = [](int i) { return (i > 3); };
368   check_adjs(check_i, x, "lhs");
369   check_adjs([](int /* i */) { return true; }, y, "rhs");
370   test_throw_out_of_range(x, y, index_min_max(3, 0));
371   test_throw_out_of_range(x, y, index_min_max(6, 1));
372   test_throw_invalid_arg(x, conditionally_generate_linear_var_vector<Vec>(5),
373                          index_min_max(4, 1));
374   test_throw_invalid_arg(x, conditionally_generate_linear_var_vector<Vec>(3),
375                          index_min_max(4, 1));
376 }
377 
TEST_F(VarAssign,negative_minmax_vec)378 TEST_F(VarAssign, negative_minmax_vec) {
379   test_negative_minmax_varvector<Eigen::VectorXd, stan::math::var>();
380   test_negative_minmax_varvector<Eigen::VectorXd, double>();
381 }
382 
TEST_F(VarAssign,negative_minmax_rowvec)383 TEST_F(VarAssign, negative_minmax_rowvec) {
384   test_negative_minmax_varvector<Eigen::RowVectorXd, stan::math::var>();
385   test_negative_minmax_varvector<Eigen::RowVectorXd, double>();
386 }
387 
388 template <typename Vec>
test_uni_uni_vec_eigvec()389 void test_uni_uni_vec_eigvec() {
390   using stan::math::sum;
391   using stan::math::var;
392   using stan::math::var_value;
393 
394   Vec xs0_val(3);
395   xs0_val << 0.0, 0.1, 0.2;
396 
397   Vec xs1_val(3);
398   xs1_val << 1.0, 1.1, 1.2;
399 
400   var_value<Vec> xs0(xs0_val);
401   var_value<Vec> xs1(xs1_val);
402   vector<var_value<Vec>> xs;
403   xs.push_back(xs0);
404   xs.push_back(xs1);
405 
406   var y = 15;
407   assign(xs, y, "", index_uni(2), index_uni(3));
408   EXPECT_FLOAT_EQ(y.val(), xs[1].val()(2));
409 
410   (sum(xs[0]) + sum(xs[1])).grad();
411   EXPECT_FLOAT_EQ(y.adj(), 1);
412 
413   for (Eigen::Index i = 0; i < xs[0].size(); ++i) {
414     EXPECT_FLOAT_EQ(xs[0].val()(i), xs0_val(i));
415     EXPECT_FLOAT_EQ(xs[0].adj()(i), 1);
416   }
417 
418   for (Eigen::Index i = 0; i < xs[0].size(); ++i) {
419     EXPECT_FLOAT_EQ(xs[1].val()(i), xs1_val(i));
420     if (i == 2) {
421       EXPECT_FLOAT_EQ(xs[1].adj()(i), 0);
422     } else {
423       EXPECT_FLOAT_EQ(xs[1].adj()(i), 1);
424     }
425   }
426 
427   test_throw_out_of_range(xs, y, index_uni(0), index_uni(3));
428   test_throw_out_of_range(xs, y, index_uni(2), index_uni(0));
429   test_throw_out_of_range(xs, y, index_uni(10), index_uni(3));
430   test_throw_out_of_range(xs, y, index_uni(2), index_uni(10));
431 }
432 
TEST_F(VarAssign,uni_uni_std_vecvec)433 TEST_F(VarAssign, uni_uni_std_vecvec) {
434   test_uni_uni_vec_eigvec<Eigen::VectorXd>();
435 }
436 
TEST_F(VarAssign,uni_uni_std_vecrowvec)437 TEST_F(VarAssign, uni_uni_std_vecrowvec) {
438   test_uni_uni_vec_eigvec<Eigen::RowVectorXd>();
439 }
440 
441 /**
442  * Tests are not exhaustive. They cover each index individually and each
443  * index as the right hand side of a double index.
444  * index_uni - A single cell.
445  * index_multi - Access multiple cells.
446  * index_omni - A no-op for all indices along a dimension.
447  * index_min - index from min:N
448  * index_max - index from 1:max
449  * index_min_max - index from min:max
450  * Tests are sorted in the above order and first call the individual index
451  * and then with the index on the right hand side of an index list.
452  */
453 
454 // uni
455 
456 template <typename RhsScalar>
uni_mat_test()457 auto uni_mat_test() {
458   using stan::math::sum;
459   using stan::math::var_value;
460   using stan::model::test::check_adjs;
461   using stan::model::test::conditionally_generate_linear_var_matrix;
462   using stan::model::test::conditionally_generate_linear_var_vector;
463 
464   auto x = conditionally_generate_linear_var_matrix(5, 5);
465   Eigen::MatrixXd x_val = x.val();
466   auto y
467       = conditionally_generate_linear_var_vector<Eigen::RowVectorXd, RhsScalar>(
468           5, 10);
469   assign(x, y, "", index_uni(1));
470   EXPECT_MATRIX_EQ(y.val().row(0), x.val().row(0));
471   sum(x).grad();
472   EXPECT_MATRIX_EQ(x.val(), x_val);
473   auto check_i = [](int i) { return i != 0; };
474   auto check_all = [](int /* j */) { return true; };
475   check_adjs(check_i, check_all, x, "lhs");
476   check_adjs(check_all, y, "rhs");
477   test_throw_out_of_range(x, y, index_uni(0));
478   test_throw_out_of_range(x, y, index_uni(6));
479 }
TEST_F(VarAssign,uni_matrix)480 TEST_F(VarAssign, uni_matrix) {
481   uni_mat_test<stan::math::var>();
482   uni_mat_test<double>();
483 }
484 
485 template <typename RhsScalar>
uni_uni_mat_test()486 auto uni_uni_mat_test() {
487   using stan::math::sum;
488   using stan::math::var;
489   using stan::math::var_value;
490   using stan::model::test::check_adjs;
491   using stan::model::test::conditionally_generate_linear_var_matrix;
492   auto x = conditionally_generate_linear_var_matrix(5, 5);
493   Eigen::MatrixXd x_val = x.val();
494   RhsScalar y = 10.12;
495   assign(x, y, "", index_uni(2), index_uni(3));
496   EXPECT_FLOAT_EQ(stan::math::value_of(y), x.val()(1, 2));
497   sum(x).grad();
498   EXPECT_MATRIX_EQ(x.val(), x_val);
499   auto check_i = [](int i) { return i == 1; };
500   auto check_j = [](int j) { return j == 2; };
501   check_adjs(check_i, check_j, x, "lhs", 0);
502   check_adjs(y, 1);
503 
504   test_throw_out_of_range(x, y, index_uni(0), index_uni(3));
505   test_throw_out_of_range(x, y, index_uni(2), index_uni(0));
506   test_throw_out_of_range(x, y, index_uni(7), index_uni(3));
507   test_throw_out_of_range(x, y, index_uni(2), index_uni(7));
508 }
509 
TEST_F(VarAssign,uni_uni_matrix)510 TEST_F(VarAssign, uni_uni_matrix) {
511   uni_uni_mat_test<stan::math::var>();
512   uni_uni_mat_test<double>();
513 }
514 
515 template <typename RhsScalar>
multi_uni_mat_test()516 auto multi_uni_mat_test() {
517   using stan::math::sum;
518   using stan::math::var_value;
519   using stan::model::test::check_adjs;
520   using stan::model::test::conditionally_generate_linear_var_matrix;
521   using stan::model::test::conditionally_generate_linear_var_vector;
522 
523   auto x = conditionally_generate_linear_var_matrix(3, 4);
524   Eigen::MatrixXd x_val = x.val();
525   auto y
526       = conditionally_generate_linear_var_vector<Eigen::RowVectorXd, RhsScalar>(
527           3, 10);
528 
529   std::vector<int> ns;
530   ns.push_back(3);
531   ns.push_back(1);
532   ns.push_back(1);
533   assign(x, y, "", index_multi(ns), index_uni(3));
534   auto y_val = stan::math::value_of(y);
535   EXPECT_FLOAT_EQ(y_val(0), x.val()(2, 2));
536   EXPECT_FLOAT_EQ(y_val(2), x.val()(0, 2));
537   sum(x).grad();
538   EXPECT_MATRIX_EQ(x.val(), x_val);
539   auto check_i_x = [](int i) { return (i == 0 || i == 2); };
540   auto check_j_x = [](int j) { return j == 2; };
541   check_adjs(check_i_x, check_j_x, x, "lhs", 0);
542   auto check_i_y = [](int i) { return i != 1; };
543   check_adjs(check_i_y, y, "rhs", 1);
544 
545   ns[ns.size() - 1] = 0;
546   test_throw_out_of_range(x, y, index_multi(ns), index_uni(3));
547   ns[ns.size() - 1] = 4;
548   test_throw_out_of_range(x, y, index_multi(ns), index_uni(3));
549   ns.push_back(2);
550   test_throw_invalid_arg(x, y, index_multi(ns), index_uni(3));
551 }
552 
TEST_F(VarAssign,multi_uni_matrix)553 TEST_F(VarAssign, multi_uni_matrix) {
554   multi_uni_mat_test<stan::math::var>();
555   multi_uni_mat_test<double>();
556 }
557 
558 template <typename RhsScalar>
omni_uni_mat_test()559 auto omni_uni_mat_test() {
560   using stan::math::var_value;
561   using stan::model::test::check_adjs;
562   using stan::model::test::conditionally_generate_linear_var_matrix;
563   using stan::model::test::conditionally_generate_linear_var_vector;
564 
565   auto x = conditionally_generate_linear_var_matrix(5, 5);
566   Eigen::MatrixXd x_val = x.val();
567   auto y = conditionally_generate_linear_var_vector<Eigen::VectorXd, RhsScalar>(
568       5, 10);
569   assign(x, y, "", index_omni(), index_uni(1));
570   auto y_val = stan::math::value_of(y);
571   EXPECT_MATRIX_EQ(y_val, x.val().col(0));
572   sum(x).grad();
573   EXPECT_MATRIX_EQ(x.val(), x_val);
574   auto check_all = [](int i) { return true; };
575   auto check_j = [](int j) { return j == 0; };
576   check_adjs(check_all, check_j, x, "lhs", 0);
577   check_adjs(check_all, y, "rhs");
578   test_throw_out_of_range(x, y, index_omni(), index_uni(0));
579   test_throw_out_of_range(x, y, index_omni(), index_uni(6));
580   test_throw_invalid_arg(
581       x, conditionally_generate_linear_var_vector<Eigen::VectorXd>(6),
582       index_omni(), index_uni(1));
583   test_throw_invalid_arg(
584       x, conditionally_generate_linear_var_vector<Eigen::VectorXd>(4),
585       index_omni(), index_uni(1));
586 }
587 
TEST_F(VarAssign,omni_uni_matrix)588 TEST_F(VarAssign, omni_uni_matrix) {
589   omni_uni_mat_test<stan::math::var>();
590   omni_uni_mat_test<double>();
591 }
592 
593 template <typename RhsScalar>
minmax_uni_mat_test()594 auto minmax_uni_mat_test() {
595   using stan::math::sum;
596   using stan::math::var_value;
597   using stan::model::test::check_adjs;
598   using stan::model::test::conditionally_generate_linear_var_matrix;
599   using stan::model::test::conditionally_generate_linear_var_vector;
600 
601   auto x = conditionally_generate_linear_var_matrix(3, 4);
602   Eigen::MatrixXd x_val = x.val();
603   auto y = conditionally_generate_linear_var_vector<Eigen::VectorXd, RhsScalar>(
604       2, 10);
605 
606   assign(x, y, "", index_min_max(2, 3), index_uni(4));
607   EXPECT_MATRIX_EQ(stan::math::value_of(y), x.val().col(3).segment(1, 2));
608   sum(x).grad();
609   EXPECT_MATRIX_EQ(x.val(), x_val);
610   auto check_i = [](int i) { return (i == 1 || i == 2); };
611   auto check_j = [](int j) { return j == 3; };
612   check_adjs(check_i, check_j, x, "lhs", 0);
613   check_adjs([](int /* */) { return true; }, y, "rhs");
614 
615   test_throw_out_of_range(x, y, index_min_max(2, 3), index_uni(0));
616   test_throw_out_of_range(x, y, index_min_max(2, 3), index_uni(5));
617   test_throw_out_of_range(x, y, index_min_max(0, 1), index_uni(4));
618   test_throw_out_of_range(x, y, index_min_max(2, 4), index_uni(4));
619   test_throw_invalid_arg(x, conditionally_generate_linear_var_vector(1, 10),
620                          index_min_max(2, 3), index_uni(4));
621   test_throw_invalid_arg(x, conditionally_generate_linear_var_vector(3, 10),
622                          index_min_max(2, 3), index_uni(4));
623 }
624 
TEST_F(VarAssign,minmax_uni_matrix)625 TEST_F(VarAssign, minmax_uni_matrix) {
626   minmax_uni_mat_test<stan::math::var>();
627   minmax_uni_mat_test<double>();
628 }
629 
630 template <typename RhsScalar>
multi_mat_test()631 auto multi_mat_test() {
632   using stan::math::sum;
633   using stan::math::var_value;
634   using stan::model::test::check_adjs;
635   using stan::model::test::conditionally_generate_linear_var_matrix;
636 
637   auto x = conditionally_generate_linear_var_matrix(5, 5);
638   Eigen::MatrixXd x_val = x.val();
639   auto y = conditionally_generate_linear_var_matrix<RhsScalar>(7, 5, 10);
640   std::vector<int> row_idx{3, 4, 1, 4, 1, 4, 5};
641   stan::arena_t<std::vector<int>> x_idx;
642   stan::arena_t<std::vector<int>> y_idx;
643   // Need to remove duplicates for cases like {2, 3, 2, 2}
644   for (int i = row_idx.size() - 1; i >= 0; --i) {
645     if (!check_multi_duplicate(x_idx, row_idx[i] - 1)) {
646       y_idx.push_back(i);
647       x_idx.push_back(row_idx[i] - 1);
648     }
649   }
650   assign(x, y, "", index_multi(row_idx));
651   // We use these to check the adjoints
652   for (int i = 0; i < x_idx.size(); ++i) {
653     EXPECT_MATRIX_EQ(x.val().row(x_idx[i]), y.val().row(y_idx[i]))
654   }
655   sum(x).grad();
656   EXPECT_MATRIX_EQ(x.val(), x_val);
657   // We don't assign to row 1
658   auto check_i_x = [](int i) { return i == 1; };
659   auto check_j_x = [](int j) { return true; };
660   check_adjs(check_i_x, check_j_x, x, "lhs", 1);
661 
662   auto check_i_y = [](int i) { return (i == 0 || i > 3); };
663   auto check_j_y = [](int j) { return true; };
664   check_adjs(check_i_y, check_j_y, y, "rhs", 1);
665   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(8, 5, 10),
666                          index_multi(row_idx));
667   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(6, 5, 10),
668                          index_multi(row_idx));
669   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(7, 4, 10),
670                          index_multi(row_idx));
671   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(7, 6, 10),
672                          index_multi(row_idx));
673   row_idx[3] = 20;
674   test_throw_out_of_range(x, y, index_multi(row_idx));
675   row_idx[3] = 2;
676   row_idx.push_back(2);
677   test_throw_invalid_arg(x, y, index_multi(row_idx));
678 }
679 
680 // multi
TEST_F(VarAssign,multi_matrix)681 TEST_F(VarAssign, multi_matrix) {
682   multi_mat_test<stan::math::var>();
683   multi_mat_test<double>();
684 }
685 
TEST_F(VarAssign,multi_alias_matrix)686 TEST_F(VarAssign, multi_alias_matrix) {
687   using stan::math::sum;
688   using stan::math::var_value;
689   using stan::model::test::check_adjs;
690   using stan::model::test::conditionally_generate_linear_var_matrix;
691 
692   auto x = conditionally_generate_linear_var_matrix(5, 5);
693   Eigen::MatrixXd x_val = x.val();
694   std::vector<int> row_idx{2, 3, 1, 3};
695   assign(x, x.block(0, 0, 4, 5), "", index_multi(row_idx));
696   Eigen::MatrixXd x_val_tmp = x_val;
697   x_val_tmp.row(0) = x_val.row(2);
698   x_val_tmp.row(1) = x_val.row(0);
699   x_val_tmp.row(2) = x_val.row(3);
700   EXPECT_MATRIX_EQ(x.val(), x_val_tmp);
701   sum(x).grad();
702   Eigen::MatrixXd exp_adj = Eigen::MatrixXd::Ones(5, 5);
703   exp_adj.row(1) = Eigen::RowVectorXd::Zero(5);
704   exp_adj.row(3) = Eigen::RowVectorXd::Constant(5, 2);
705   EXPECT_MATRIX_EQ(x.adj(), exp_adj);
706 }
707 
708 template <typename RhsScalar>
uni_multi_mat_test()709 auto uni_multi_mat_test() {
710   using stan::math::sum;
711   using stan::math::var_value;
712   using stan::model::test::check_adjs;
713   using stan::model::test::conditionally_generate_linear_var_matrix;
714   using stan::model::test::conditionally_generate_linear_var_vector;
715 
716   auto x = conditionally_generate_linear_var_matrix(5, 5);
717   Eigen::MatrixXd x_val = x.val();
718   auto y
719       = conditionally_generate_linear_var_vector<Eigen::RowVectorXd, RhsScalar>(
720           4, 10);
721 
722   vector<int> ns{4, 1, 3, 3};
723   assign(x, y, "", index_uni(3), index_multi(ns));
724   EXPECT_FLOAT_EQ(y.val()(0), x.val()(2, 3));
725   EXPECT_FLOAT_EQ(y.val()(1), x.val()(2, 0));
726   EXPECT_FLOAT_EQ(y.val()(3), x.val()(2, 2));
727 
728   sum(x).grad();
729   EXPECT_MATRIX_EQ(x.val(), x_val);
730   auto check_i_x = [](int i) { return i == 2; };
731   auto check_j_x = [](int j) { return (j == 0 || j == 2 || j == 3); };
732   check_adjs(check_i_x, check_j_x, x, "lhs", 0);
733   auto check_i_y = [](int i) { return i != 2; };
734   check_adjs(check_i_y, y, "rhs", 1);
735   test_throw_invalid_arg(
736       x, conditionally_generate_linear_var_vector<Eigen::RowVectorXd>(5, 10),
737       index_uni(3), index_multi(ns));
738   test_throw_invalid_arg(
739       x, conditionally_generate_linear_var_vector<Eigen::RowVectorXd>(3, 10),
740       index_uni(3), index_multi(ns));
741   test_throw_out_of_range(x, y, index_uni(0), index_multi(ns));
742   test_throw_out_of_range(x, y, index_uni(6), index_multi(ns));
743   ns[ns.size() - 1] = 0;
744   test_throw_out_of_range(x, y, index_uni(3), index_multi(ns));
745   ns[ns.size() - 1] = 20;
746   test_throw_out_of_range(x, y, index_uni(3), index_multi(ns));
747   ns.push_back(2);
748   test_throw_invalid_arg(x, y, index_uni(3), index_multi(ns));
749 }
750 
TEST_F(VarAssign,uni_multi_matrix)751 TEST_F(VarAssign, uni_multi_matrix) {
752   uni_multi_mat_test<stan::math::var>();
753   uni_multi_mat_test<double>();
754 }
755 
TEST_F(VarAssign,uni_multi_alias_matrix)756 TEST_F(VarAssign, uni_multi_alias_matrix) {
757   using stan::math::sum;
758   using stan::math::var_value;
759   using stan::model::test::check_adjs;
760   using stan::model::test::conditionally_generate_linear_var_matrix;
761   using stan::model::test::conditionally_generate_linear_var_vector;
762 
763   auto x = conditionally_generate_linear_var_matrix(5, 5);
764   Eigen::MatrixXd x_val = x.val();
765   vector<int> ns{1, 1, 2, 3};
766   assign(x, x.row(2).segment(0, 4), "", index_uni(3), index_multi(ns));
767   Eigen::MatrixXd x_val_tmp = x_val;
768   x_val_tmp(2, 0) = 7;
769   x_val_tmp(2, 1) = 12;
770   x_val_tmp(2, 2) = 17;
771   EXPECT_MATRIX_EQ(x.val(), x_val_tmp);
772   sum(x).grad();
773   EXPECT_MATRIX_EQ(x.val(), x_val);
774   Eigen::MatrixXd exp_adj = Eigen::MatrixXd::Ones(5, 5);
775   exp_adj(2, 0) = 0;
776   exp_adj(2, 3) = 2;
777   EXPECT_MATRIX_EQ(x.adj(), exp_adj);
778 }
779 
780 template <typename RhsScalar>
multi_multi_mat_test()781 auto multi_multi_mat_test() {
782   using stan::math::sum;
783   using stan::math::var_value;
784   using stan::model::test::check_adjs;
785   using stan::model::test::conditionally_generate_linear_var_matrix;
786 
787   auto x = conditionally_generate_linear_var_matrix(5, 5);
788   Eigen::MatrixXd x_val = x.val();
789   auto y = conditionally_generate_linear_var_matrix<RhsScalar>(7, 7, 10);
790   std::vector<int> row_idx{3, 4, 1, 4, 1, 4, 5};
791   std::vector<int> col_idx{1, 4, 4, 3, 2, 1, 5};
792 
793   stan::arena_t<std::vector<std::array<int, 2>>> x_idx;
794   stan::arena_t<std::vector<std::array<int, 2>>> y_idx;
795   // Need to remove duplicates for cases like {2, 3, 2, 2}
796   for (int j = col_idx.size() - 1; j >= 0; --j) {
797     for (int i = row_idx.size() - 1; i >= 0; --i) {
798       if (!check_multi_duplicate(x_idx, row_idx[i] - 1, col_idx[j] - 1)) {
799         y_idx.push_back(std::array<int, 2>{i, j});
800         x_idx.push_back(std::array<int, 2>{row_idx[i] - 1, col_idx[j] - 1});
801       }
802     }
803   }
804   assign(x, y, "", index_multi(row_idx), index_multi(col_idx));
805   // We use these to check the adjoints
806   auto y_val = stan::math::value_of(y);
807   for (int i = 0; i < x_idx.size(); ++i) {
808     EXPECT_FLOAT_EQ(x.val()(x_idx[i][0], x_idx[i][1]),
809                     y_val(y_idx[i][0], y_idx[i][1]))
810         << "Failed for \ni: " << i << "\nx_idx[i][0]: " << x_idx[i][0]
811         << " x_idx[i][1]: " << x_idx[i][1] << "\ny_idx[i][0]: " << y_idx[i][0]
812         << " y_idx[i][1]: " << y_idx[i][1];
813   }
814   sum(x).grad();
815   EXPECT_MATRIX_EQ(x.val(), x_val);
816   // We don't assign to row 1
817   auto check_i_x = [](int i) { return i == 1; };
818   auto check_j_x = [](int j) { return true; };
819   check_adjs(check_i_x, check_j_x, x, "lhs", 1);
820 
821   auto check_i_y = [](int i) { return (i == 0 || i > 3); };
822   auto check_j_y = [](int j) { return (j > 1); };
823   check_adjs(check_i_y, check_j_y, y, "rhs", 1);
824 
825   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(6, 7, 10),
826                          index_multi(row_idx), index_multi(col_idx));
827   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(8, 7, 10),
828                          index_multi(row_idx), index_multi(col_idx));
829   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(7, 6, 10),
830                          index_multi(row_idx), index_multi(col_idx));
831   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(7, 8, 10),
832                          index_multi(row_idx), index_multi(col_idx));
833   col_idx.pop_back();
834   test_throw_invalid_arg(x, y, index_multi(row_idx), index_multi(col_idx));
835   col_idx.push_back(22);
836   test_throw_out_of_range(x, y, index_multi(row_idx), index_multi(col_idx));
837   col_idx.pop_back();
838   col_idx.push_back(5);
839 
840   row_idx.pop_back();
841   test_throw_invalid_arg(x, y, index_multi(row_idx), index_multi(col_idx));
842   row_idx.push_back(22);
843   test_throw_out_of_range(x, y, index_multi(row_idx), index_multi(col_idx));
844 }
845 
TEST_F(VarAssign,multi_multi_matrix)846 TEST_F(VarAssign, multi_multi_matrix) {
847   multi_multi_mat_test<stan::math::var>();
848   multi_multi_mat_test<double>();
849 }
850 
TEST_F(VarAssign,multi_multi_alias_matrix)851 TEST_F(VarAssign, multi_multi_alias_matrix) {
852   using stan::math::sum;
853   using stan::math::var_value;
854   using stan::model::test::check_adjs;
855   using stan::model::test::conditionally_generate_linear_var_matrix;
856 
857   auto x = conditionally_generate_linear_var_matrix(5, 5);
858   Eigen::MatrixXd x_val = x.val();
859   std::vector<int> row_idx{1, 2, 2, 4};
860   std::vector<int> col_idx{1, 2, 2, 3};
861   assign(x, x.block(0, 0, 4, 4).eval(), "", index_multi(row_idx),
862          index_multi(col_idx));
863   Eigen::MatrixXd x_val_tmp(5, 5);
864   /* clang-format off */
865   x_val_tmp << 0, 10, 15, 15, 20,
866                2, 12, 17, 16, 21,
867                2,  7, 12, 17, 22,
868                3, 13, 18, 18, 23,
869                4,  9, 14, 19, 24;
870   /* clang-format on */
871 
872   EXPECT_MATRIX_EQ(x.val(), x_val_tmp);
873   sum(x).grad();
874   EXPECT_MATRIX_EQ(x.val(), x_val);
875   Eigen::MatrixXd exp_adj(5, 5);
876   /* clang-format off */
877   exp_adj << 1, 0, 1, 2, 1,
878              0, 0, 0, 1, 1,
879              2, 1, 2, 2, 1,
880              1, 0, 1, 2, 1,
881              1, 1, 1, 1, 1;
882   /* clang-format on */
883   EXPECT_MATRIX_EQ(x.adj(), exp_adj);
884 }
885 
886 template <typename RhsScalar>
minmax_multi_mat_test()887 auto minmax_multi_mat_test() {
888   using stan::math::sum;
889   using stan::math::var_value;
890   using stan::model::test::check_adjs;
891   using stan::model::test::conditionally_generate_linear_var_matrix;
892   using stan::model::test::conditionally_generate_linear_var_vector;
893 
894   auto x = conditionally_generate_linear_var_matrix(5, 5);
895   Eigen::MatrixXd x_val = x.val();
896   auto y = conditionally_generate_linear_var_matrix(3, 4, 25);
897 
898   vector<int> ns{4, 1, 3, 3};
899   assign(x, y, "", index_min_max(1, 3), index_multi(ns));
900   Eigen::MatrixXd x_val_tmp = x_val;
901   x_val_tmp.col(0).segment(0, 3) = y.val().col(1);
902   x_val_tmp.col(2).segment(0, 3) = y.val().col(3);
903   x_val_tmp.col(3).segment(0, 3) = y.val().col(0);
904   EXPECT_MATRIX_EQ(x.val(), x_val_tmp);
905   sum(x).grad();
906   EXPECT_MATRIX_EQ(x.val(), x_val);
907   auto check_i_x = [](int i) { return i < 3; };
908   auto check_j_x = [](int j) { return (j == 0 || j == 2 || j == 3); };
909   check_adjs(check_i_x, check_j_x, x, "lhs", 0);
910   auto check_i_y = [](int i) { return true; };
911   auto check_j_y = [](int j) { return j != 2; };
912   check_adjs(check_i_y, check_j_y, y, "lhs", 1);
913   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(3, 5, 10),
914                          index_min_max(1, 3), index_multi(ns));
915   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(3, 3, 10),
916                          index_min_max(1, 3), index_multi(ns));
917   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(4, 4, 10),
918                          index_min_max(1, 3), index_multi(ns));
919   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(2, 4, 10),
920                          index_min_max(1, 3), index_multi(ns));
921 
922   test_throw_out_of_range(x, y, index_min_max(0, 3), index_multi(ns));
923   test_throw_out_of_range(x, y, index_min_max(1, 6), index_multi(ns));
924   ns[ns.size() - 1] = 0;
925   test_throw_out_of_range(x, y, index_min_max(1, 3), index_multi(ns));
926   ns[ns.size() - 1] = 20;
927   test_throw_out_of_range(x, y, index_min_max(1, 3), index_multi(ns));
928   ns.push_back(2);
929   test_throw_invalid_arg(x, y, index_min_max(1, 3), index_multi(ns));
930 }
931 
TEST_F(VarAssign,minmax_multi_matrix)932 TEST_F(VarAssign, minmax_multi_matrix) {
933   minmax_multi_mat_test<stan::math::var>();
934   minmax_multi_mat_test<double>();
935 }
936 
TEST_F(VarAssign,minmax_multi_alias_matrix)937 TEST_F(VarAssign, minmax_multi_alias_matrix) {
938   using stan::math::sum;
939   using stan::math::var_value;
940   using stan::model::test::check_adjs;
941   using stan::model::test::conditionally_generate_linear_var_matrix;
942   using stan::model::test::conditionally_generate_linear_var_vector;
943 
944   auto x = conditionally_generate_linear_var_matrix(5, 5);
945   Eigen::MatrixXd x_val = x.val();
946 
947   vector<int> ns{4, 1, 3, 3};
948   assign(x, x.block(0, 0, 3, 4), "", index_min_max(1, 3), index_multi(ns));
949   Eigen::MatrixXd x_val_tmp = x_val;
950   x_val_tmp.col(0).segment(0, 3) = x_val.col(1).segment(0, 3);
951   x_val_tmp.col(2).segment(0, 3) = x_val.col(3).segment(0, 3);
952   x_val_tmp.col(3).segment(0, 3) = x_val.col(0).segment(0, 3);
953   EXPECT_MATRIX_EQ(x.val(), x_val_tmp);
954   sum(x).grad();
955   EXPECT_MATRIX_EQ(x.val(), x_val);
956   Eigen::MatrixXd exp_adj = Eigen::MatrixXd::Ones(5, 5);
957   exp_adj.col(1).segment(0, 3).array() = 2;
958   exp_adj.col(2).segment(0, 3).array() = 0;
959   EXPECT_MATRIX_EQ(x.adj(), exp_adj);
960 }
961 
962 // omni
963 template <typename RhsScalar>
omni_matrix_test()964 void omni_matrix_test() {
965   using stan::math::value_of;
966   using stan::math::var_value;
967   using stan::model::test::check_adjs;
968   using stan::model::test::conditionally_generate_linear_var_matrix;
969   using stan::model::test::conditionally_generate_linear_var_vector;
970   auto x = conditionally_generate_linear_var_matrix(5, 5);
971   var_value<Eigen::MatrixXd> x_copy(x.vi_);
972   Eigen::MatrixXd x_val = x.val();
973   auto y = conditionally_generate_linear_var_matrix<RhsScalar>(5, 5, 10);
974   assign(x, y, "", index_omni());
975   if (stan::is_var<RhsScalar>::value) {
976     EXPECT_MATRIX_EQ(value_of(y), x.val());
977   } else {
978     EXPECT_MATRIX_EQ(value_of(y), x.val());
979     EXPECT_MATRIX_EQ(value_of(y), x_copy.val());
980   }
981   sum(x).grad();
982   auto check_all = [](int /* i */) { return true; };
983   if (stan::is_var<RhsScalar>::value) {
984     EXPECT_MATRIX_EQ(x.val(), value_of(y));
985     check_adjs(check_all, check_all, x, "lhs");
986     check_adjs(check_all, check_all, y, "rhs");
987   } else {
988     // Need to double check this.
989     check_adjs(check_all, check_all, x, "lhs", 0.0);
990     check_adjs(check_all, check_all, x_copy, "lhs", 0.0);
991   }
992   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(5, 6, 10),
993                          index_omni());
994   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(5, 4, 10),
995                          index_omni());
996   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(6, 5, 10),
997                          index_omni());
998   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(4, 5, 10),
999                          index_omni());
1000 }
1001 
TEST_F(VarAssign,omni_matrix)1002 TEST_F(VarAssign, omni_matrix) {
1003   omni_matrix_test<stan::math::var>();
1004   omni_matrix_test<double>();
1005 }
1006 
1007 template <typename RhsScalar>
omni_omni_matrix_test()1008 void omni_omni_matrix_test() {
1009   using stan::math::value_of;
1010   using stan::math::var_value;
1011   using stan::model::test::check_adjs;
1012   using stan::model::test::conditionally_generate_linear_var_matrix;
1013   using stan::model::test::conditionally_generate_linear_var_vector;
1014   auto x = conditionally_generate_linear_var_matrix(5, 5);
1015   var_value<Eigen::MatrixXd> x_copy(x.vi_);
1016   Eigen::MatrixXd x_val = x.val();
1017   auto y = conditionally_generate_linear_var_matrix<RhsScalar>(5, 5, 10);
1018   stan::math::var lp = sum(x_copy);
1019   lp.adj() = 1;
1020   assign(x, y, "", index_omni(), index_omni());
1021   if (stan::is_var<RhsScalar>::value) {
1022     EXPECT_MATRIX_EQ(value_of(y), x.val());
1023   } else {
1024     EXPECT_MATRIX_EQ(value_of(y), x.val());
1025     EXPECT_MATRIX_EQ(value_of(y), x_copy.val());
1026   }
1027   sum(x).grad();
1028   auto check_all = [](int /* i */) { return true; };
1029   if (stan::is_var<RhsScalar>::value) {
1030     EXPECT_MATRIX_EQ(x.val(), value_of(y));
1031     check_adjs(check_all, check_all, x, "lhs");
1032     check_adjs(check_all, check_all, y, "rhs");
1033   } else {
1034     EXPECT_MATRIX_EQ(x.val(), x_val);
1035     // Both are one in this case
1036     check_adjs(check_all, check_all, x, "lhs", 1.0);
1037     check_adjs(check_all, check_all, x_copy, "lhs", 1.0);
1038   }
1039   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(5, 6, 10),
1040                          index_omni(), index_omni());
1041   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(5, 4, 10),
1042                          index_omni(), index_omni());
1043   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(6, 5, 10),
1044                          index_omni(), index_omni());
1045   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(4, 5, 10),
1046                          index_omni(), index_omni());
1047 }
1048 
TEST_F(VarAssign,omni_omni_matrix_var)1049 TEST_F(VarAssign, omni_omni_matrix_var) {
1050   omni_omni_matrix_test<stan::math::var>();
1051 }
TEST_F(VarAssign,omni_omni_matrix_dbl)1052 TEST_F(VarAssign, omni_omni_matrix_dbl) { omni_omni_matrix_test<double>(); }
1053 
1054 template <typename RhsScalar>
uni_omni_matrix_test()1055 void uni_omni_matrix_test() {
1056   using stan::math::sum;
1057   using stan::math::var_value;
1058   using stan::model::test::check_adjs;
1059   using stan::model::test::conditionally_generate_linear_var_matrix;
1060   using stan::model::test::conditionally_generate_linear_var_vector;
1061 
1062   auto x = conditionally_generate_linear_var_matrix(5, 5);
1063   Eigen::MatrixXd x_val = x.val();
1064   auto y
1065       = conditionally_generate_linear_var_vector<Eigen::RowVectorXd, RhsScalar>(
1066           5, 10);
1067   assign(x, y, "", index_uni(1), index_omni());
1068   EXPECT_MATRIX_EQ(stan::math::value_of(y).row(0), x.val().row(0));
1069   sum(x).grad();
1070   EXPECT_MATRIX_EQ(x.val(), x_val);
1071   auto check_i = [](int i) { return i != 0; };
1072   auto check_all = [](int j) { return true; };
1073   check_adjs(check_i, check_all, x, "lhs");
1074   check_adjs(check_all, y, "rhs");
1075 
1076   test_throw_invalid_arg(
1077       x,
1078       conditionally_generate_linear_var_vector<Eigen::RowVectorXd, RhsScalar>(
1079           4, 10),
1080       index_uni(1), index_omni());
1081   test_throw_invalid_arg(
1082       x,
1083       conditionally_generate_linear_var_vector<Eigen::RowVectorXd, RhsScalar>(
1084           6, 10),
1085       index_uni(1), index_omni());
1086   test_throw_out_of_range(x, y, index_uni(0), index_omni());
1087   test_throw_out_of_range(x, y, index_uni(6), index_omni());
1088 }
1089 
TEST_F(VarAssign,uni_omni_matrix)1090 TEST_F(VarAssign, uni_omni_matrix) {
1091   uni_omni_matrix_test<stan::math::var>();
1092   uni_omni_matrix_test<double>();
1093 }
1094 
1095 // min
1096 template <typename RhsScalar>
min_matrix_test()1097 void min_matrix_test() {
1098   using stan::math::sum;
1099   using stan::math::var_value;
1100   using stan::model::test::check_adjs;
1101   using stan::model::test::conditionally_generate_linear_var_matrix;
1102 
1103   auto x = conditionally_generate_linear_var_matrix(3, 4);
1104   Eigen::MatrixXd x_val = x.val();
1105   auto y = conditionally_generate_linear_var_matrix<RhsScalar>(2, 4, 10);
1106 
1107   assign(x, y, "", index_min(2));
1108   EXPECT_MATRIX_EQ(x.val().bottomRows(2), stan::math::value_of(y));
1109   sum(x).grad();
1110   // We don't assign to row 1
1111   auto check_i_x = [](int i) { return i > 0; };
1112   auto check_all = [](int j) { return true; };
1113   check_adjs(check_i_x, check_all, x, "lhs", 0);
1114   check_adjs(check_all, y, "rhs", 1.0);
1115   test_throw_out_of_range(x, y, index_min(0));
1116   test_throw_out_of_range(x, y, index_min(4));
1117   test_throw_invalid_arg(x, y, index_min(1));
1118   var_value<MatrixXd> z(MatrixXd::Ones(1, 2));
1119   test_throw_invalid_arg(x, z, index_min(2));
1120 }
1121 
TEST_F(VarAssign,min_matrix)1122 TEST_F(VarAssign, min_matrix) {
1123   min_matrix_test<stan::math::var>();
1124   min_matrix_test<double>();
1125 }
1126 
1127 template <typename RhsScalar>
minmax_min_matrix_test()1128 void minmax_min_matrix_test() {
1129   using stan::math::sum;
1130   using stan::math::var_value;
1131   using stan::model::test::check_adjs;
1132   using stan::model::test::conditionally_generate_linear_var_matrix;
1133 
1134   auto x = conditionally_generate_linear_var_matrix(3, 4);
1135   Eigen::MatrixXd x_val = x.val();
1136   auto y = conditionally_generate_linear_var_matrix<RhsScalar>(2, 3, 10);
1137   assign(x, y, "", index_min_max(2, 3), index_min(2));
1138   EXPECT_MATRIX_EQ(stan::math::value_of(y), x.val().block(1, 1, 2, 3));
1139   sum(x).grad();
1140   EXPECT_MATRIX_EQ(x.val(), x_val);
1141   auto check_i = [](int i) { return (i == 1 || i == 2); };
1142   auto check_j = [](int j) { return j > 0; };
1143   check_adjs(check_i, check_j, x, "lhs", 0);
1144   auto check_all = [](int /* */) { return true; };
1145   check_adjs(check_all, check_all, y, "rhs");
1146   test_throw_out_of_range(x, y, index_min_max(0, 3), index_min(2));
1147   test_throw_out_of_range(x, y, index_min_max(2, 4), index_min(2));
1148   test_throw_out_of_range(x, y, index_min_max(2, 3), index_min(0));
1149   test_throw_out_of_range(x, y, index_min_max(2, 3), index_min(5));
1150   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(1, 3, 10),
1151                          index_min_max(2, 3), index_min(2));
1152   test_throw_invalid_arg(x, conditionally_generate_linear_var_matrix(2, 5, 10),
1153                          index_min_max(2, 3), index_min(2));
1154 }
1155 
TEST_F(VarAssign,minmax_min_matrix)1156 TEST_F(VarAssign, minmax_min_matrix) {
1157   minmax_min_matrix_test<stan::math::var>();
1158   minmax_min_matrix_test<double>();
1159 }
1160 
1161 // max
1162 template <typename RhsScalar>
max_matrix_test()1163 void max_matrix_test() {
1164   using stan::math::sum;
1165   using stan::math::var_value;
1166   using stan::model::test::check_adjs;
1167   using stan::model::test::conditionally_generate_linear_var_matrix;
1168 
1169   auto x = conditionally_generate_linear_var_matrix(3, 4);
1170   Eigen::MatrixXd x_val = x.val();
1171   auto y = conditionally_generate_linear_var_matrix<RhsScalar>(2, 4, 10);
1172 
1173   assign(x, y, "", index_max(2));
1174   EXPECT_MATRIX_EQ(x.val().topRows(2), stan::math::value_of(y));
1175   sum(x).grad();
1176   EXPECT_MATRIX_EQ(x.val(), x_val);
1177   auto check_i_x = [](int i) { return i < 2; };
1178   auto check_all = [](int j) { return true; };
1179   check_adjs(check_i_x, check_all, x, "lhs", 0);
1180   check_adjs(check_all, y, "rhs");
1181   test_throw_out_of_range(x, y, index_max(0));
1182   test_throw_out_of_range(x, y, index_max(4));
1183   test_throw_invalid_arg(x, y, index_max(1));
1184   var_value<MatrixXd> z(MatrixXd::Ones(1, 2));
1185   test_throw_invalid_arg(x, z, index_max(2));
1186 }
TEST_F(VarAssign,max_matrix)1187 TEST_F(VarAssign, max_matrix) {
1188   max_matrix_test<stan::math::var>();
1189   max_matrix_test<double>();
1190 }
1191 
1192 template <typename RhsScalar>
min_max_matrix_test()1193 void min_max_matrix_test() {
1194   using stan::math::sum;
1195   using stan::math::var_value;
1196   using stan::model::test::check_adjs;
1197   using stan::model::test::conditionally_generate_linear_var_matrix;
1198 
1199   auto x = conditionally_generate_linear_var_matrix(3, 4);
1200   Eigen::MatrixXd x_val = x.val();
1201   auto y = conditionally_generate_linear_var_matrix<RhsScalar>(2, 2, 10);
1202 
1203   assign(x, y, "", index_min(2), index_max(2));
1204   EXPECT_MATRIX_EQ(x.val().block(1, 0, 2, 2), stan::math::value_of(y));
1205   sum(x).grad();
1206   EXPECT_MATRIX_EQ(x.val(), x_val);
1207   // We don't assign to row 1
1208   auto check_i_x = [](int i) { return i > 0; };
1209   auto check_j_x = [](int j) { return j < 2; };
1210   check_adjs(check_i_x, check_j_x, x, "lhs", 0);
1211   auto check_all = [](int /* i*/) { return true; };
1212   check_adjs(check_all, check_all, y, "rhs");
1213   test_throw_out_of_range(x, y, index_min(0), index_max(2));
1214   test_throw_out_of_range(x, y, index_min(5), index_max(2));
1215   test_throw_out_of_range(x, y, index_min(2), index_max(0));
1216   test_throw_out_of_range(x, y, index_min(2), index_max(5));
1217   test_throw_invalid_arg(x, y, index_min(2), index_max(1));
1218   var_value<MatrixXd> z(MatrixXd::Ones(1, 4));
1219   test_throw_invalid_arg(x, z, index_min(2), index_max(2));
1220   test_throw_invalid_arg(x, z, index_min(2), index_max(3));
1221 }
TEST_F(VarAssign,min_max_matrix)1222 TEST_F(VarAssign, min_max_matrix) {
1223   min_max_matrix_test<stan::math::var>();
1224   min_max_matrix_test<double>();
1225 }
1226 
1227 // minmax
1228 template <typename RhsScalar>
positive_minmax_matrix_test()1229 void positive_minmax_matrix_test() {
1230   using stan::math::sum;
1231   using stan::math::var_value;
1232   using stan::model::test::check_adjs;
1233   using stan::model::test::conditionally_generate_linear_var_matrix;
1234   Eigen::Matrix<double, -1, -1> x_val(5, 5);
1235   Eigen::Matrix<double, -1, -1> x_rev_val(5, 5);
1236   for (int i = 0; i < x_val.size(); ++i) {
1237     x_val(i) = i;
1238     x_rev_val(i) = x_val.size() - i - 1;
1239   }
1240 
1241   for (int i = 0; i < x_val.rows(); ++i) {
1242     var_value<Eigen::MatrixXd> x(x_val);
1243     std::conditional_t<stan::is_var<RhsScalar>::value,
1244                        var_value<Eigen::MatrixXd>, Eigen::MatrixXd>
1245         x_rev(x_rev_val);
1246     const int ii = i + 1;
1247     assign(x, x_rev.block(0, 0, ii, 5), "", index_min_max(1, ii));
1248     auto x_val_check = x.val().block(0, 0, ii, 5);
1249     auto x_rev_val_check = stan::math::value_of(x_rev).block(0, 0, ii, 5);
1250     EXPECT_MATRIX_EQ(x_val_check, x_rev_val_check);
1251     sum(x).grad();
1252     auto check_i = [i](int kk) { return kk <= i; };
1253     auto check_all = [i](int jj) { return true; };
1254     check_adjs(check_i, check_all, x, "lhs", 0);
1255     check_adjs(check_i, check_all, x_rev, "rhs", 1);
1256     test_throw_out_of_range(x, x_rev.block(0, 0, ii, 5), index_min_max(0, ii));
1257     test_throw_out_of_range(x, x_rev.block(0, 0, ii, 5),
1258                             index_min_max(1, ii + x.rows()));
1259     test_throw_invalid_arg(x, x_rev.block(0, 0, ii, 5), index_min_max(2, ii));
1260     test_throw_invalid_arg(x, x_rev.block(0, 0, ii, 4), index_min_max(1, ii));
1261     stan::math::recover_memory();
1262   }
1263 }
TEST_F(VarAssign,positive_minmax_matrix)1264 TEST_F(VarAssign, positive_minmax_matrix) {
1265   positive_minmax_matrix_test<stan::math::var>();
1266   positive_minmax_matrix_test<double>();
1267 }
1268 
1269 template <typename RhsScalar>
negative_minmax_matrix_test()1270 void negative_minmax_matrix_test() {
1271   using stan::math::sum;
1272   using stan::math::var_value;
1273   using stan::model::test::check_adjs;
1274   using std::vector;
1275   Eigen::Matrix<double, -1, -1> x_val(5, 5);
1276   Eigen::Matrix<double, -1, -1> x_rev_val(5, 5);
1277   for (int i = 0; i < x_val.size(); ++i) {
1278     x_val(i) = i;
1279     x_rev_val(i) = x_val.size() - i - 1;
1280   }
1281 
1282   for (int i = 0; i < x_val.rows(); ++i) {
1283     var_value<Eigen::MatrixXd> x(x_val);
1284     std::conditional_t<stan::is_var<RhsScalar>::value,
1285                        var_value<Eigen::MatrixXd>, Eigen::MatrixXd>
1286         x_rev(x_rev_val);
1287     const int ii = i + 1;
1288     assign(x, x_rev.block(0, 0, ii, 5), "", index_min_max(ii, 1));
1289     auto x_val_check = x.val().block(0, 0, ii, 5);
1290     auto x_rev_val_check
1291         = stan::math::value_of(x_rev).block(0, 0, ii, 5).colwise().reverse();
1292     EXPECT_MATRIX_EQ(x_val_check, x_rev_val_check);
1293     sum(x).grad();
1294     auto check_i = [i](int kk) { return kk <= i; };
1295     auto check_all = [i](int jj) { return true; };
1296     check_adjs(check_i, check_all, x, "lhs", 0);
1297     check_adjs(check_i, check_all, x_rev, "rhs", 1);
1298     test_throw_out_of_range(x, x_rev.block(0, 0, ii, 5), index_min_max(ii, 0));
1299     test_throw_out_of_range(x, x_rev.block(0, 0, ii, 5),
1300                             index_min_max(ii + x.rows(), 1));
1301     test_throw_invalid_arg(x, x_rev.block(0, 0, ii, 5), index_min_max(ii, 2));
1302     test_throw_invalid_arg(x, x_rev.block(0, 0, ii, 4), index_min_max(1, ii));
1303     stan::math::recover_memory();
1304   }
1305 }
TEST_F(VarAssign,negative_minmax_matrix)1306 TEST_F(VarAssign, negative_minmax_matrix) {
1307   negative_minmax_matrix_test<stan::math::var>();
1308   negative_minmax_matrix_test<double>();
1309 }
1310 
1311 template <typename RhsScalar>
positive_minmax_positive_minmax_matrix_test()1312 void positive_minmax_positive_minmax_matrix_test() {
1313   using stan::math::sum;
1314   using stan::math::var_value;
1315   using stan::model::test::check_adjs;
1316   using stan::model::test::conditionally_generate_linear_var_matrix;
1317   Eigen::Matrix<double, -1, -1> x_val(5, 5);
1318   Eigen::Matrix<double, -1, -1> x_rev_val(5, 5);
1319   for (int i = 0; i < x_val.size(); ++i) {
1320     x_val(i) = i;
1321     x_rev_val(i) = x_val.size() - i - 1;
1322   }
1323 
1324   for (int i = 0; i < x_val.rows(); ++i) {
1325     var_value<Eigen::MatrixXd> x(x_val);
1326     std::conditional_t<stan::is_var<RhsScalar>::value,
1327                        var_value<Eigen::MatrixXd>, Eigen::MatrixXd>
1328         x_rev(x_rev_val);
1329     const int ii = i + 1;
1330     assign(x, x_rev.block(0, 0, ii, ii), "", index_min_max(1, ii),
1331            index_min_max(1, ii));
1332     auto x_val_check = x.val().block(0, 0, ii, ii);
1333     auto x_rev_val_check = x_rev.val().block(0, 0, ii, ii);
1334     EXPECT_MATRIX_EQ(x_val_check, x_rev_val_check);
1335     sum(x).grad();
1336     auto check_i = [i](int kk) { return kk <= i; };
1337     auto check_j = [i](int jj) { return jj <= i; };
1338     check_adjs(check_i, check_j, x, "lhs", 0);
1339     check_adjs(check_i, check_j, x_rev, "rhs", 1);
1340     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii), index_min_max(0, ii),
1341                             index_min_max(1, ii));
1342     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii), index_min_max(1, ii),
1343                             index_min_max(0, ii));
1344     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii),
1345                             index_min_max(1, x.rows() + 1),
1346                             index_min_max(1, ii));
1347     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii), index_min_max(1, ii),
1348                             index_min_max(1, x.rows() + 1));
1349     // We don't want to go out of bounds when making the eigen block.
1350     auto ii_range_high = ii == 5 ? 4 : ii + 1;
1351     test_throw_invalid_arg(x, x_rev.block(0, 0, ii - 1, ii),
1352                            index_min_max(1, ii), index_min_max(1, ii));
1353     test_throw_invalid_arg(x, x_rev.block(0, 0, ii_range_high, ii),
1354                            index_min_max(1, ii), index_min_max(1, ii));
1355     test_throw_invalid_arg(x, x_rev.block(0, 0, ii, ii - 1),
1356                            index_min_max(1, ii), index_min_max(1, ii));
1357     test_throw_invalid_arg(x, x_rev.block(0, 0, ii, ii_range_high),
1358                            index_min_max(1, ii), index_min_max(1, ii));
1359     stan::math::recover_memory();
1360   }
1361 }
1362 
TEST_F(VarAssign,positive_minmax_positive_minmax_matrix)1363 TEST_F(VarAssign, positive_minmax_positive_minmax_matrix) {
1364   positive_minmax_positive_minmax_matrix_test<stan::math::var>();
1365   positive_minmax_positive_minmax_matrix_test<double>();
1366 }
1367 
1368 template <typename RhsScalar>
positive_minmax_negative_minmax_matrix_test()1369 void positive_minmax_negative_minmax_matrix_test() {
1370   using stan::math::sum;
1371   using stan::math::var_value;
1372   using stan::model::test::check_adjs;
1373   using std::vector;
1374   Eigen::Matrix<double, -1, -1> x_val(5, 5);
1375   Eigen::Matrix<double, -1, -1> x_rev_val(5, 5);
1376   for (int i = 0; i < x_val.size(); ++i) {
1377     x_val(i) = i;
1378     x_rev_val(i) = x_val.size() - i - 1;
1379   }
1380 
1381   for (int i = 0; i < x_val.rows(); ++i) {
1382     var_value<Eigen::MatrixXd> x(x_val);
1383     std::conditional_t<stan::is_var<RhsScalar>::value,
1384                        var_value<Eigen::MatrixXd>, Eigen::MatrixXd>
1385         x_rev(x_rev_val);
1386     const int ii = i + 1;
1387     assign(x, x_rev.block(0, 0, ii, ii), "", index_min_max(1, ii),
1388            index_min_max(ii, 1));
1389     auto x_val_check = x.val().block(0, 0, ii, ii);
1390     auto x_rev_val_check
1391         = stan::math::value_of(x_rev).block(0, 0, ii, ii).rowwise().reverse();
1392     EXPECT_MATRIX_EQ(x_val_check, x_rev_val_check);
1393     sum(x).grad();
1394     auto check_i = [i](int kk) { return kk <= i; };
1395     auto check_j = [i](int jj) { return jj <= i; };
1396     check_adjs(check_i, check_j, x, "lhs", 0);
1397     check_adjs(check_i, check_j, x_rev, "rhs", 1);
1398     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii), index_min_max(0, ii),
1399                             index_min_max(ii, 1));
1400     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii), index_min_max(1, ii),
1401                             index_min_max(ii, 0));
1402     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii),
1403                             index_min_max(1, x.rows() + 1),
1404                             index_min_max(1, ii));
1405     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii), index_min_max(1, ii),
1406                             index_min_max(1, x.rows() + 1));
1407     // We don't want to go out of bounds when making the eigen block.
1408     auto ii_range_high = ii == 5 ? 4 : ii + 1;
1409     test_throw_invalid_arg(x, x_rev.block(0, 0, ii - 1, ii),
1410                            index_min_max(1, ii), index_min_max(ii, 1));
1411     test_throw_invalid_arg(x, x_rev.block(0, 0, ii_range_high, ii),
1412                            index_min_max(1, ii), index_min_max(ii, 1));
1413     test_throw_invalid_arg(x, x_rev.block(0, 0, ii, ii - 1),
1414                            index_min_max(1, ii), index_min_max(ii, 1));
1415     test_throw_invalid_arg(x, x_rev.block(0, 0, ii, ii_range_high),
1416                            index_min_max(1, ii), index_min_max(ii, 1));
1417     stan::math::recover_memory();
1418   }
1419 }
1420 
TEST_F(VarAssign,positive_minmax_negative_minmax_matrix)1421 TEST_F(VarAssign, positive_minmax_negative_minmax_matrix) {
1422   positive_minmax_negative_minmax_matrix_test<stan::math::var>();
1423   positive_minmax_negative_minmax_matrix_test<double>();
1424 }
1425 
1426 template <typename RhsScalar>
negative_minmax_positive_minmax_matrix_test()1427 void negative_minmax_positive_minmax_matrix_test() {
1428   using stan::math::sum;
1429   using stan::math::var_value;
1430   using stan::model::test::check_adjs;
1431   using std::vector;
1432   Eigen::Matrix<double, -1, -1> x_val(5, 5);
1433   Eigen::Matrix<double, -1, -1> x_rev_val(5, 5);
1434   for (int i = 0; i < x_val.size(); ++i) {
1435     x_val(i) = i;
1436     x_rev_val(i) = x_val.size() - i - 1;
1437   }
1438 
1439   for (int i = 0; i < x_val.rows(); ++i) {
1440     var_value<Eigen::MatrixXd> x(x_val);
1441     std::conditional_t<stan::is_var<RhsScalar>::value,
1442                        var_value<Eigen::MatrixXd>, Eigen::MatrixXd>
1443         x_rev(x_rev_val);
1444     const int ii = i + 1;
1445     assign(x, x_rev.block(0, 0, ii, ii), "", index_min_max(ii, 1),
1446            index_min_max(1, ii));
1447     auto x_val_check = x.val().block(0, 0, ii, ii);
1448     auto x_rev_val_check
1449         = stan::math::value_of(x_rev).block(0, 0, ii, ii).colwise().reverse();
1450     EXPECT_MATRIX_EQ(x_val_check, x_rev_val_check);
1451     sum(x).grad();
1452     auto check_i = [i](int kk) { return kk <= i; };
1453     auto check_j = [i](int jj) { return jj <= i; };
1454     check_adjs(check_i, check_j, x, "lhs", 0);
1455     check_adjs(check_i, check_j, x_rev, "rhs", 1);
1456     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii), index_min_max(ii, 0),
1457                             index_min_max(1, ii));
1458     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii), index_min_max(ii, 1),
1459                             index_min_max(0, ii));
1460     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii),
1461                             index_min_max(x.rows() + 1, 1),
1462                             index_min_max(1, ii));
1463     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii), index_min_max(ii, 1),
1464                             index_min_max(1, x.rows() + 1));
1465     // We don't want to go out of bounds when making the eigen block.
1466     auto ii_range_high = ii == 5 ? 4 : ii + 1;
1467     test_throw_invalid_arg(x, x_rev.block(0, 0, ii - 1, ii),
1468                            index_min_max(ii, 1), index_min_max(1, ii));
1469     test_throw_invalid_arg(x, x_rev.block(0, 0, ii_range_high, ii),
1470                            index_min_max(ii, 1), index_min_max(1, ii));
1471     test_throw_invalid_arg(x, x_rev.block(0, 0, ii, ii - 1),
1472                            index_min_max(ii, 1), index_min_max(1, ii));
1473     test_throw_invalid_arg(x, x_rev.block(0, 0, ii, ii_range_high),
1474                            index_min_max(ii, 1), index_min_max(1, ii));
1475     stan::math::recover_memory();
1476   }
1477 }
1478 
TEST_F(VarAssign,negative_minmax_positive_minmax_matrix)1479 TEST_F(VarAssign, negative_minmax_positive_minmax_matrix) {
1480   negative_minmax_positive_minmax_matrix_test<stan::math::var>();
1481   negative_minmax_positive_minmax_matrix_test<double>();
1482 }
1483 
1484 template <typename RhsScalar>
negative_minmax_negative_minmax_matrix_test()1485 void negative_minmax_negative_minmax_matrix_test() {
1486   using stan::math::sum;
1487   using stan::math::var_value;
1488   using stan::model::test::check_adjs;
1489   using std::vector;
1490   Eigen::Matrix<double, -1, -1> x_val(5, 5);
1491   Eigen::Matrix<double, -1, -1> x_rev_val(5, 5);
1492   for (int i = 0; i < x_val.size(); ++i) {
1493     x_val(i) = i;
1494     x_rev_val(i) = x_val.size() - i - 1;
1495   }
1496 
1497   for (int i = 0; i < x_val.rows(); ++i) {
1498     var_value<Eigen::MatrixXd> x(x_val);
1499     std::conditional_t<stan::is_var<RhsScalar>::value,
1500                        var_value<Eigen::MatrixXd>, Eigen::MatrixXd>
1501         x_rev(x_rev_val);
1502     const int ii = i + 1;
1503     assign(x, x_rev.block(0, 0, ii, ii), "", index_min_max(ii, 1),
1504            index_min_max(ii, 1));
1505     auto x_val_check = x.val().block(0, 0, ii, ii);
1506     auto x_rev_val_check
1507         = stan::math::value_of(x_rev).block(0, 0, ii, ii).reverse();
1508     EXPECT_MATRIX_EQ(x_val_check, x_rev_val_check);
1509     sum(x).grad();
1510     auto check_i = [i](int kk) { return kk <= i; };
1511     auto check_j = [i](int jj) { return jj <= i; };
1512     check_adjs(check_i, check_j, x, "lhs", 0);
1513     check_adjs(check_i, check_j, x_rev, "rhs", 1);
1514     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii), index_min_max(ii, 0),
1515                             index_min_max(ii, 1));
1516     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii), index_min_max(ii, 1),
1517                             index_min_max(ii, 0));
1518     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii),
1519                             index_min_max(x.rows() + 1, 1),
1520                             index_min_max(ii, 1));
1521     test_throw_out_of_range(x, x_rev.block(0, 0, ii, ii), index_min_max(ii, 1),
1522                             index_min_max(x.rows() + 1, 1));
1523     // We don't want to go out of bounds when making the eigen block.
1524     auto ii_range_high = ii == 5 ? 4 : ii + 1;
1525     test_throw_invalid_arg(x, x_rev.block(0, 0, ii - 1, ii),
1526                            index_min_max(ii, 1), index_min_max(ii, 1));
1527     test_throw_invalid_arg(x, x_rev.block(0, 0, ii_range_high, ii),
1528                            index_min_max(ii, 1), index_min_max(ii, 1));
1529     test_throw_invalid_arg(x, x_rev.block(0, 0, ii, ii - 1),
1530                            index_min_max(ii, 1), index_min_max(ii, 1));
1531     test_throw_invalid_arg(x, x_rev.block(0, 0, ii, ii_range_high),
1532                            index_min_max(ii, 1), index_min_max(ii, 1));
1533     stan::math::recover_memory();
1534   }
1535 }
1536 
TEST_F(VarAssign,negative_minmax_negative_minmax_matrix)1537 TEST_F(VarAssign, negative_minmax_negative_minmax_matrix) {
1538   negative_minmax_negative_minmax_matrix_test<stan::math::var>();
1539   negative_minmax_negative_minmax_matrix_test<double>();
1540 }
1541 
1542 template <typename RhsScalar>
uni_minmax_matrix_test()1543 void uni_minmax_matrix_test() {
1544   using stan::math::sum;
1545   using stan::math::var_value;
1546   using stan::model::test::check_adjs;
1547   using stan::model::test::conditionally_generate_linear_var_matrix;
1548   using stan::model::test::conditionally_generate_linear_var_vector;
1549 
1550   auto x = conditionally_generate_linear_var_matrix(5, 5);
1551   Eigen::MatrixXd x_val = x.val();
1552   auto y
1553       = conditionally_generate_linear_var_vector<Eigen::RowVectorXd, RhsScalar>(
1554           3, 10);
1555   assign(x, y, "", index_uni(2), index_min_max(2, 4));
1556   EXPECT_MATRIX_EQ(stan::math::value_of(y).segment(0, 3),
1557                    x.val().row(1).segment(1, 3));
1558   sum(x).grad();
1559   EXPECT_MATRIX_EQ(x.val(), x_val);
1560   auto check_i = [](int i) { return i == 1; };
1561   auto check_j = [](int j) { return (j > 0 && j < 4); };
1562   check_adjs(check_i, check_j, x, "lhs", 0);
1563   check_adjs([](int /* */) { return true; }, y, "rhs");
1564   test_throw_out_of_range(x, y, index_uni(0), index_min_max(2, 4));
1565   test_throw_out_of_range(x, y, index_uni(6), index_min_max(2, 4));
1566   test_throw_out_of_range(x, y, index_uni(2), index_min_max(0, 2));
1567   test_throw_out_of_range(x, y, index_uni(2), index_min_max(1, 6));
1568   test_throw_invalid_arg(
1569       x, conditionally_generate_linear_var_vector<Eigen::RowVectorXd>(2, 10),
1570       index_uni(2), index_min_max(2, 4));
1571   test_throw_invalid_arg(
1572       x, conditionally_generate_linear_var_vector<Eigen::RowVectorXd>(4, 10),
1573       index_uni(2), index_min_max(2, 4));
1574 }
1575 
TEST_F(VarAssign,uni_minmax_matrix)1576 TEST_F(VarAssign, uni_minmax_matrix) {
1577   uni_minmax_matrix_test<stan::math::var>();
1578   uni_minmax_matrix_test<double>();
1579 }
1580 
1581 template <typename RhsScalar>
nil_matrix()1582 void nil_matrix() {
1583   using stan::math::var_value;
1584   using stan::model::test::check_adjs;
1585   using stan::model::test::conditionally_generate_linear_var_matrix;
1586   using stan::model::test::conditionally_generate_linear_var_vector;
1587 
1588   auto x = conditionally_generate_linear_var_matrix(5, 5);
1589   var_value<Eigen::MatrixXd> x_copy(x.vi_);
1590   Eigen::MatrixXd x_val = x.val();
1591   auto y = conditionally_generate_linear_var_matrix<RhsScalar>(5, 5, 10);
1592   assign(x, y, "");
1593   EXPECT_MATRIX_EQ(stan::math::value_of(y), x.val());
1594   sum(x).grad();
1595   auto check_all = [](int /* i */) { return true; };
1596   if (stan::is_var<RhsScalar>::value) {
1597     EXPECT_MATRIX_EQ(x.val(), stan::math::value_of(y));
1598     check_adjs(check_all, check_all, x, "lhs");
1599     check_adjs(check_all, check_all, y, "rhs");
1600   } else {
1601     check_adjs(check_all, check_all, x, "lhs", 0.0);
1602     EXPECT_MATRIX_EQ(x.val(), x_val);
1603   }
1604 }
1605 // nil only shows up as a single index
TEST_F(VarAssign,nil_matrix)1606 TEST_F(VarAssign, nil_matrix) {
1607   nil_matrix<stan::math::var>();
1608   nil_matrix<double>();
1609 }
1610 
1611 namespace stan {
1612 namespace model {
1613 namespace test {
1614 
1615 template <typename T1, typename I1, typename I2>
assign_tester(T1 && x,const I1 & idx1,const I2 & idx2)1616 inline void assign_tester(T1&& x, const I1& idx1, const I2& idx2) {
1617   using stan::math::var_value;
1618   using stan::model::test::generate_linear_matrix;
1619   auto multi1 = convert_to_multi(idx1, x, false);
1620   auto multi2 = convert_to_multi(idx2, x, true);
1621   var_value<std::decay_t<T1>> x1(x);
1622   var_value<std::decay_t<T1>> x2(x);
1623   Eigen::MatrixXd y_val
1624       = generate_linear_matrix(multi1.ns_.size(), multi2.ns_.size(), 10);
1625   var_value<Eigen::MatrixXd> y(y_val);
1626   assign(x1, y, "", idx1, idx2);
1627   assign(x2, y, "", multi1, multi2);
1628   EXPECT_MATRIX_EQ(x1.val(), x2.val());
1629   stan::math::sum(stan::math::add(x1, x2)).grad();
1630   // Since this just moves the pointer x1 omni is diff than
1631   // multi
1632   if (!std::is_same<I1, index_omni>::value
1633       && !std::is_same<I2, index_omni>::value) {
1634     EXPECT_MATRIX_EQ(x1.val(), x2.val());
1635     EXPECT_MATRIX_EQ(x1.adj(), x2.adj());
1636     EXPECT_MATRIX_EQ(y.adj(),
1637                      Eigen::MatrixXd::Constant(y.rows(), y.cols(), 2).eval());
1638   }
1639   stan::math::recover_memory();
1640 }
1641 
1642 template <typename T1, typename I1>
assign_tester(T1 && x,const I1 & idx1,index_uni idx2)1643 inline void assign_tester(T1&& x, const I1& idx1, index_uni idx2) {
1644   using stan::math::var_value;
1645   using stan::model::test::generate_linear_vector;
1646   auto multi1 = convert_to_multi(idx1, x, false);
1647   auto multi2 = convert_to_multi(idx2, x, true);
1648   var_value<std::decay_t<T1>> x1(x);
1649   var_value<std::decay_t<T1>> x2(x);
1650   Eigen::VectorXd y_val
1651       = generate_linear_vector<Eigen::VectorXd>(multi1.ns_.size(), 10);
1652   var_value<Eigen::VectorXd> y(y_val);
1653   assign(x1, y, "", idx1, idx2);
1654   assign(x2, y, "", multi1, multi2);
1655   EXPECT_MATRIX_EQ(x1.val(), x2.val());
1656   stan::math::sum(stan::math::add(x1, x2)).grad();
1657   EXPECT_MATRIX_EQ(x1.val(), x2.val());
1658   EXPECT_MATRIX_EQ(x1.adj(), x2.adj());
1659   EXPECT_MATRIX_EQ(y.adj(), Eigen::VectorXd::Constant(y.size(), 2).eval());
1660   stan::math::recover_memory();
1661 }
1662 
1663 template <typename T1, typename I2>
assign_tester(T1 && x,index_uni idx1,const I2 & idx2)1664 inline void assign_tester(T1&& x, index_uni idx1, const I2& idx2) {
1665   using stan::math::var_value;
1666   using stan::model::test::generate_linear_vector;
1667   auto multi1 = convert_to_multi(idx1, x, false);
1668   auto multi2 = convert_to_multi(idx2, x, true);
1669   var_value<std::decay_t<T1>> x1(x);
1670   var_value<std::decay_t<T1>> x2(x);
1671   Eigen::RowVectorXd y_val
1672       = generate_linear_vector<Eigen::RowVectorXd>(multi2.ns_.size(), 10);
1673   var_value<Eigen::RowVectorXd> y(y_val);
1674   assign(x1, y, "", idx1, idx2);
1675   assign(x2, y, "", multi1, multi2);
1676   EXPECT_MATRIX_EQ(x1.val(), x2.val());
1677   stan::math::sum(stan::math::add(x1, x2)).grad();
1678   EXPECT_MATRIX_EQ(x1.val(), x2.val());
1679   EXPECT_MATRIX_EQ(x1.adj(), x2.adj());
1680   EXPECT_MATRIX_EQ(y.adj(), Eigen::RowVectorXd::Constant(y.size(), 2).eval());
1681   stan::math::recover_memory();
1682 }
1683 
1684 template <typename T1>
all_assign_tests(T1 && x)1685 inline void all_assign_tests(T1&& x) {
1686   std::vector<int> multi_ns{1, 2, 3};
1687   // uni
1688   // uni uni is explicitly tested and would otherwise need a specialization
1689   assign_tester(x, index_multi(multi_ns), index_uni(1));
1690   assign_tester(x, index_omni(), index_uni(1));
1691   assign_tester(x, index_min(2), index_uni(1));
1692   assign_tester(x, index_max(2), index_uni(1));
1693   assign_tester(x, index_min_max(1, 2), index_uni(1));
1694 
1695   // multi
1696   assign_tester(x, index_uni(1), index_multi(multi_ns));
1697   assign_tester(x, index_multi(multi_ns), index_multi(multi_ns));
1698   assign_tester(x, index_omni(), index_multi(multi_ns));
1699   assign_tester(x, index_min(2), index_multi(multi_ns));
1700   assign_tester(x, index_max(2), index_multi(multi_ns));
1701   assign_tester(x, index_min_max(1, 2), index_multi(multi_ns));
1702 
1703   // omni
1704   assign_tester(x, index_uni(1), index_omni());
1705   assign_tester(x, index_multi(multi_ns), index_omni());
1706   assign_tester(x, index_omni(), index_omni());
1707   assign_tester(x, index_min(2), index_omni());
1708   assign_tester(x, index_max(2), index_omni());
1709   assign_tester(x, index_min_max(1, 2), index_omni());
1710 
1711   // min
1712   assign_tester(x, index_uni(1), index_min(2));
1713   assign_tester(x, index_multi(multi_ns), index_min(2));
1714   assign_tester(x, index_omni(), index_min(2));
1715   assign_tester(x, index_min(2), index_min(2));
1716   assign_tester(x, index_max(2), index_min(2));
1717   assign_tester(x, index_min_max(1, 2), index_min(2));
1718 
1719   // max
1720   assign_tester(x, index_uni(1), index_max(2));
1721   assign_tester(x, index_multi(multi_ns), index_max(2));
1722   assign_tester(x, index_omni(), index_max(2));
1723   assign_tester(x, index_min(2), index_max(2));
1724   assign_tester(x, index_max(2), index_max(2));
1725   assign_tester(x, index_min_max(1, 2), index_max(2));
1726 
1727   // min_max
1728   assign_tester(x, index_uni(1), index_min_max(1, 2));
1729   assign_tester(x, index_multi(multi_ns), index_min_max(1, 2));
1730   assign_tester(x, index_omni(), index_min_max(1, 2));
1731   assign_tester(x, index_min(2), index_min_max(1, 2));
1732   assign_tester(x, index_max(2), index_min_max(1, 2));
1733   assign_tester(x, index_min_max(1, 2), index_min_max(1, 2));
1734 }
1735 }  // namespace test
1736 }  // namespace model
1737 }  // namespace stan
1738 
TEST_F(VarAssign,all_types)1739 TEST_F(VarAssign, all_types) {
1740   using stan::model::test::all_assign_tests;
1741   using stan::model::test::generate_linear_matrix;
1742   Eigen::MatrixXd x = generate_linear_matrix(4, 4);
1743   all_assign_tests(x);
1744   Eigen::MatrixXd x_wide = generate_linear_matrix(5, 6);
1745   all_assign_tests(x_wide);
1746   Eigen::MatrixXd x_long = generate_linear_matrix(7, 4);
1747   all_assign_tests(x_long);
1748 }
1749