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