1 #ifndef STAN_MODEL_INDEXING_LVALUE_HPP
2 #define STAN_MODEL_INDEXING_LVALUE_HPP
3 
4 #include <boost/utility/enable_if.hpp>
5 #include <boost/type_traits/is_same.hpp>
6 #include <Eigen/Dense>
7 #include <stan/math/prim/mat.hpp>
8 #include <stan/model/indexing/index.hpp>
9 #include <stan/model/indexing/index_list.hpp>
10 #include <stan/model/indexing/rvalue_at.hpp>
11 #include <stan/model/indexing/rvalue_index_size.hpp>
12 #include <vector>
13 
14 namespace stan {
15 
16   namespace model {
17 
18     /**
19      * Assign the specified scalar reference under the specified
20      * indexing to the specified scalar value.
21      *
22      * Types:  x[] <- y
23      *
24      * @tparam T Assigned variable type.
25      * @tparam U Value type (must be assignable to T).
26      * @param[in] x Variable to be assigned.
27      * @param[in] y Value.
28      * @param[in] name Name of variable (default "ANON").
29      * @param[in] depth Indexing depth (default 0).
30      */
31     template <typename T, typename U>
assign(T & x,const nil_index_list &,const U & y,const char * name="ANON",int depth=0)32     inline void assign(T& x, const nil_index_list& /* idxs */, const U& y,
33                        const char* name = "ANON", int depth = 0) {
34       x = y;
35     }
36 
37     template <typename T, typename U, int R, int C>
assign(Eigen::Matrix<T,R,C> & x,const nil_index_list &,const Eigen::Matrix<U,R,C> & y,const char * name="ANON",int depth=0)38     inline void assign(Eigen::Matrix<T, R, C>& x,
39                        const nil_index_list& /* idxs */,
40                        const Eigen::Matrix<U, R, C>& y,
41                        const char* name = "ANON",
42                        int depth = 0) {
43       x.resize(y.rows(), y.cols());
44       for (int i = 0; i < y.size(); ++i)
45         assign(x(i), nil_index_list(), y(i), name, depth + 1);
46     }
47 
48 
49     template <typename T, typename U>
assign(std::vector<T> & x,const nil_index_list &,const std::vector<U> & y,const char * name="ANON",int depth=0)50     inline void assign(std::vector<T>& x, const nil_index_list& /* idxs */,
51                        const std::vector<U>& y, const char* name = "ANON",
52                        int depth = 0) {
53       x.resize(y.size());
54       for (size_t i = 0; i < y.size(); ++i)
55         assign(x[i], nil_index_list(), y[i], name, depth + 1);
56     }
57 
58 
59     /**
60      * Assign the specified Eigen vector at the specified single index
61      * to the specified value.
62      *
63      * Types: vec[uni] <- scalar
64      *
65      * @tparam T Type of assigned vector scalar.
66      * @tparam U Type of value (must be assignable to T).
67      * @param[in] x Vector variable to be assigned.
68      * @param[in] idxs Sequence of one single index (from 1).
69      * @param[in] y Value scalar.
70      * @param[in] name Name of variable (default "ANON").
71      * @param[in] depth Indexing depth (default 0).
72      * @throw std::out_of_range If the index is out of bounds.
73      */
74     template <typename T, typename U>
assign(Eigen::Matrix<T,Eigen::Dynamic,1> & x,const cons_index_list<index_uni,nil_index_list> & idxs,const U & y,const char * name="ANON",int depth=0)75     inline void assign(Eigen::Matrix<T, Eigen::Dynamic, 1>& x,
76                        const cons_index_list<index_uni, nil_index_list>& idxs,
77                        const U& y,
78                        const char* name = "ANON", int depth = 0) {
79       int i = idxs.head_.n_;
80       math::check_range("vector[uni] assign range", name, x.size(), i);
81       x(i - 1) = y;
82     }
83 
84     /**
85      * Assign the specified Eigen vector at the specified single index
86      * to the specified value.
87      *
88      * Types:  row_vec[uni] <- scalar
89      *
90      * @tparam T Type of assigned row vector scalar.
91      * @tparam U Type of value (must be assignable to T).
92      * @param[in] x Row vector variable to be assigned.
93      * @param[in] idxs Sequence of one single index (from 1).
94      * @param[in] y Value scalar.
95      * @param[in] name Name of variable (default "ANON").
96      * @param[in] depth Indexing depth (default 0).
97      * @throw std::out_of_range Index is out of bounds.
98      */
99     template <typename T, typename U>
assign(Eigen::Matrix<T,1,Eigen::Dynamic> & x,const cons_index_list<index_uni,nil_index_list> & idxs,const U & y,const char * name="ANON",int depth=0)100     inline void assign(Eigen::Matrix<T, 1, Eigen::Dynamic>& x,
101                        const cons_index_list<index_uni, nil_index_list>& idxs,
102                        const U& y,
103                        const char* name = "ANON", int depth = 0) {
104       int i = idxs.head_.n_;
105       math::check_range("row_vector[uni] assign range", name, x.size(), i);
106       x(i - 1) = y;
107     }
108 
109     /**
110      * Assign the specified Eigen vector at the specified multiple
111      * index to the specified value.
112      *
113      * Types:  vec[multi] <- vec
114      *
115      * @tparam T Type of assigned vector scalar.
116      * @tparam I Type of multiple index.
117      * @tparam U Type of vector value scalar (must be assignable to T).
118      * @param[in] x Row vector variable to be assigned.
119      * @param[in] idxs Sequence of one single index (from 1).
120      * @param[in] y Value vector.
121      * @param[in] name Name of variable (default "ANON").
122      * @param[in] depth Indexing depth (default 0).
123      * @throw std::out_of_range If any of the indices are out of bounds.
124      * @throw std::invalid_argument If the value size isn't the same as
125      * the indexed size.
126      */
127     template <typename T, typename I, typename U>
128     inline typename boost::disable_if<boost::is_same<I, index_uni>, void>::type
assign(Eigen::Matrix<T,Eigen::Dynamic,1> & x,const cons_index_list<I,nil_index_list> & idxs,const Eigen::Matrix<U,Eigen::Dynamic,1> & y,const char * name="ANON",int depth=0)129     assign(Eigen::Matrix<T, Eigen::Dynamic, 1>& x,
130            const cons_index_list<I, nil_index_list>& idxs,
131            const Eigen::Matrix<U, Eigen::Dynamic, 1>& y,
132            const char* name = "ANON", int depth = 0) {
133       math::check_size_match("vector[multi] assign sizes",
134                              "lhs", rvalue_index_size(idxs.head_, x.size()),
135                              name, y.size());
136       for (int n = 0; n < y.size(); ++n) {
137         int i = rvalue_at(n, idxs.head_);
138         math::check_range("vector[multi] assign range", name, x.size(), i);
139         x(i - 1) = y(n);
140       }
141     }
142 
143     /**
144      * Assign the specified Eigen row vector at the specified multiple
145      * index to the specified value.
146      *
147      * Types:   row_vec[multi] <- row_vec
148      *
149      * @tparam T Scalar type for assigned row vector.
150      * @tparam I Type of multiple index.
151      * @tparam U Type of value row vector scalar (must be assignable
152      * to T).
153      * @param[in] x Row vector variable to be assigned.
154      * @param[in] idxs Sequence of one multiple index (from 1).
155      * @param[in] y Value vector.
156      * @param[in] name Name of variable (default "ANON").
157      * @param[in] depth Indexing depth (default 0).
158      * @throw std::out_of_range If any of the indices are out of bounds.
159      * @throw std::invalid_argument If the value size isn't the same as
160      * the indexed size.
161      */
162     template <typename T, typename I, typename U>
163     inline typename boost::disable_if<boost::is_same<I, index_uni>, void>::type
assign(Eigen::Matrix<T,1,Eigen::Dynamic> & x,const cons_index_list<I,nil_index_list> & idxs,const Eigen::Matrix<U,1,Eigen::Dynamic> & y,const char * name="ANON",int depth=0)164     assign(Eigen::Matrix<T, 1, Eigen::Dynamic>& x,
165            const cons_index_list<I, nil_index_list>& idxs,
166            const Eigen::Matrix<U, 1, Eigen::Dynamic>& y,
167            const char* name = "ANON", int depth = 0) {
168       math::check_size_match("row_vector[multi] assign sizes",
169                              "lhs", rvalue_index_size(idxs.head_, x.size()),
170                              name, y.size());
171       for (int n = 0; n < y.size(); ++n) {
172         int i = rvalue_at(n, idxs.head_);
173         math::check_range("row_vector[multi] assign range", name, x.size(), i);
174         x(i - 1) = y(n);
175       }
176     }
177 
178     /**
179      * Assign the specified Eigen matrix at the specified single index
180      * to the specified row vector value.
181      *
182      * Types:  mat[uni] = rowvec
183      *
184      * @tparam T Assigned matrix scalar type.
185      * @tparam U Type of value scalar for row vector (must be
186      * assignable to T).
187      * @param[in] x Matrix variable to be assigned.
188      * @param[in] idxs Sequence of one single index (from 1).
189      * @param[in] y Value row vector.
190      * @param[in] name Name of variable (default "ANON").
191      * @param[in] depth Indexing depth (default 0).
192      * @throw std::out_of_range If any of the indices are out of bounds.
193      * @throw std::invalid_argument If the number of columns in the row
194      * vector and matrix do not match.
195      */
196     template <typename T, typename U>
assign(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & x,const cons_index_list<index_uni,nil_index_list> & idxs,const Eigen::Matrix<U,1,Eigen::Dynamic> & y,const char * name="ANON",int depth=0)197     void assign(Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& x,
198                 const cons_index_list<index_uni, nil_index_list>& idxs,
199                 const Eigen::Matrix<U, 1, Eigen::Dynamic>& y,
200                 const char* name = "ANON", int depth = 0) {
201       math::check_size_match("matrix[uni] assign sizes",
202                              "lhs", x.cols(),
203                              name, y.cols());
204       int i = idxs.head_.n_;
205       math::check_range("matrix[uni] assign range", name, x.rows(), i);
206       for (int j = 0; j < x.cols(); ++j)  // loop allows double to var assgn
207         x(i - 1, j) = y(j);
208     }
209 
210     /**
211      * Assign the specified Eigen matrix at the specified multiple
212      * index to the specified matrix value.
213      *
214      * Types:  mat[multi] = mat
215      *
216      * @tparam T Assigned matrix scalar type.
217      * @tparam I Multiple index type.
218      * @tparam U Value matrix scalar type (must be assignable to T).
219      * @param[in] x Matrix variable to be assigned.
220      * @param[in] idxs Sequence of one multiple index (from 1).
221      * @param[in] y Value matrix.
222      * @param[in] name Name of variable (default "ANON").
223      * @param[in] depth Indexing depth (default 0).
224      * @throw std::out_of_range If any of the indices are out of bounds.
225      * @throw std::invalid_argument If the dimensions of the indexed
226      * matrix and right-hand side matrix do not match.
227      */
228     template <typename T, typename I, typename U>
229     inline typename boost::disable_if<boost::is_same<I, index_uni>, void>::type
assign(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & x,const cons_index_list<I,nil_index_list> & idxs,const Eigen::Matrix<U,Eigen::Dynamic,Eigen::Dynamic> & y,const char * name="ANON",int depth=0)230     assign(Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& x,
231            const cons_index_list<I, nil_index_list>& idxs,
232            const Eigen::Matrix<U, Eigen::Dynamic, Eigen::Dynamic>& y,
233            const char* name = "ANON", int depth = 0) {
234       int x_idx_rows = rvalue_index_size(idxs.head_, x.rows());
235       math::check_size_match("matrix[multi] assign row sizes",
236                              "lhs", x_idx_rows,
237                              name, y.rows());
238       math::check_size_match("matrix[multi] assign col sizes",
239                              "lhs", x.cols(),
240                              name, y.cols());
241       for (int i = 0; i < y.rows(); ++i) {
242         int m = rvalue_at(i, idxs.head_);
243         math::check_range("matrix[multi] assign range", name, x.rows(), m);
244         // recurse to allow double to var assign
245         for (int j = 0; j < x.cols(); ++j)
246           x(m - 1, j) = y(i, j);
247       }
248     }
249 
250     /**
251      * Assign the specified Eigen matrix at the specified pair of
252      * single indexes to the specified scalar value.
253      *
254      * Types:  mat[single, single] = scalar
255      *
256      * @tparam T Matrix scalar type.
257      * @tparam U Scalar type.
258      * @param[in] x Matrix variable to be assigned.
259      * @param[in] idxs Sequence of two single indexes (from 1).
260      * @param[in] y Value scalar.
261      * @param[in] name Name of variable (default "ANON").
262      * @param[in] depth Indexing depth (default 0).
263      * @throw std::out_of_range If either of the indices are out of bounds.
264      */
265     template <typename T, typename U>
assign(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & x,const cons_index_list<index_uni,cons_index_list<index_uni,nil_index_list>> & idxs,const U & y,const char * name="ANON",int depth=0)266     void assign(Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& x,
267                 const cons_index_list<index_uni,
268                                       cons_index_list<index_uni,
269                                                       nil_index_list> >& idxs,
270                 const U& y,
271                 const char* name = "ANON", int depth = 0) {
272       int m = idxs.head_.n_;
273       int n = idxs.tail_.head_.n_;
274       math::check_range("matrix[uni,uni] assign range", name, x.rows(), m);
275       math::check_range("matrix[uni,uni] assign range", name, x.cols(), n);
276       x(m - 1, n - 1) = y;
277     }
278 
279     /**
280      * Assign the specified Eigen matrix at the specified single and
281      * multiple index to the specified row vector.
282      *
283      * Types:  mat[uni, multi] = rowvec
284      *
285      * @tparam T Assigned matrix scalar type.
286      * @tparam I Multi-index type.
287      * @tparam U Value row vector scalar type (must be assignable to
288      * T).
289      * @param[in] x Matrix variable to be assigned.
290      * @param[in] idxs Sequence of single and multiple index (from 1).
291      * @param[in] y Value row vector.
292      * @param[in] name Name of variable (default "ANON").
293      * @param[in] depth Indexing depth (default 0).
294      * @throw std::out_of_range If any of the indices are out of bounds.
295      * @throw std::invalid_argument If the dimensions of the indexed
296      * matrix and right-hand side row vector do not match.
297      */
298     template <typename T, typename I, typename U>
299     inline typename boost::disable_if<boost::is_same<I, index_uni>, void>::type
assign(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & x,const cons_index_list<index_uni,cons_index_list<I,nil_index_list>> & idxs,const Eigen::Matrix<U,1,Eigen::Dynamic> & y,const char * name="ANON",int depth=0)300     assign(Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& x,
301            const cons_index_list<index_uni,
302                                  cons_index_list<I, nil_index_list> >& idxs,
303            const Eigen::Matrix<U, 1, Eigen::Dynamic>& y,
304            const char* name = "ANON", int depth = 0) {
305       int x_idxs_cols = rvalue_index_size(idxs.tail_.head_, x.cols());
306       math::check_size_match("matrix[uni,multi] assign sizes",
307                              "lhs", x_idxs_cols,
308                              name, y.cols());
309       int m = idxs.head_.n_;
310       math::check_range("matrix[uni,multi] assign range", name, x.rows(), m);
311       for (int i = 0; i < y.size(); ++i) {
312         int n = rvalue_at(i, idxs.tail_.head_);
313         math::check_range("matrix[uni,multi] assign range", name, x.cols(), n);
314         x(m - 1, n - 1) = y(i);
315       }
316     }
317 
318     /**
319      * Assign the specified Eigen matrix at the specified multiple and
320      * single index to the specified vector.
321      *
322      * Types:  mat[multi, uni] = vec
323      *
324      * @tparam T Assigned matrix scalar type.
325      * @tparam I Multi-index type.
326      * @tparam U Value vector scalar type (must be assignable to T).
327      * @param[in] x Matrix variable to be assigned.
328      * @param[in] idxs Sequence of multiple and single index (from 1).
329      * @param[in] y Value vector.
330      * @param[in] name Name of variable (default "ANON").
331      * @param[in] depth Indexing depth (default 0).
332      * @throw std::out_of_range If any of the indices are out of bounds.
333      * @throw std::invalid_argument If the dimensions of the indexed
334      * matrix and right-hand side vector do not match.
335      */
336     template <typename T, typename I, typename U>
337     inline typename boost::disable_if<boost::is_same<I, index_uni>, void>::type
assign(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & x,const cons_index_list<I,cons_index_list<index_uni,nil_index_list>> & idxs,const Eigen::Matrix<U,Eigen::Dynamic,1> & y,const char * name="ANON",int depth=0)338     assign(Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& x,
339            const cons_index_list<I,
340                                  cons_index_list<index_uni,
341                                                  nil_index_list> >& idxs,
342            const Eigen::Matrix<U, Eigen::Dynamic, 1>& y,
343            const char* name = "ANON", int depth = 0) {
344       int x_idxs_rows = rvalue_index_size(idxs.head_, x.rows());
345       math::check_size_match("matrix[multi,uni] assign sizes",
346                              "lhs", x_idxs_rows,
347                              name, y.rows());
348       int n = idxs.tail_.head_.n_;
349       math::check_range("matrix[multi,uni] assign range", name, x.cols(), n);
350       for (int i = 0; i < y.size(); ++i) {
351         int m = rvalue_at(i, idxs.head_);
352         math::check_range("matrix[multi,uni] assign range", name, x.rows(), m);
353         x(m - 1, n - 1) = y(i);
354       }
355     }
356 
357     /**
358      * Assign the specified Eigen matrix at the specified pair of
359      * multiple indexes to the specified matrix.
360      *
361      * Types:  mat[multi, multi] = mat
362      *
363      * @tparam T Assigned matrix scalar type.
364      * @tparam I1 First multiple index type.
365      * @tparam I2 Second multiple index type.
366      * @tparam U Value matrix scalar type (must be assignable to T).
367      * @param[in] x Matrix variable to be assigned.
368      * @param[in] idxs Pair of multiple indexes (from 1).
369      * @param[in] y Value matrix.
370      * @param[in] name Name of variable (default "ANON").
371      * @param[in] depth Indexing depth (default 0).
372      * @throw std::out_of_range If any of the indices are out of bounds.
373      * @throw std::invalid_argument If the dimensions of the indexed
374      * matrix and value matrix do not match.
375      */
376     template <typename T, typename I1, typename I2, typename U>
377     inline typename
378     boost::disable_if_c<boost::is_same<I1, index_uni>::value
379                         || boost::is_same<I2, index_uni>::value, void>::type
assign(Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & x,const cons_index_list<I1,cons_index_list<I2,nil_index_list>> & idxs,const Eigen::Matrix<U,Eigen::Dynamic,Eigen::Dynamic> & y,const char * name="ANON",int depth=0)380     assign(Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& x,
381            const cons_index_list<I1,
382                                  cons_index_list<I2, nil_index_list> >& idxs,
383            const Eigen::Matrix<U, Eigen::Dynamic, Eigen::Dynamic>& y,
384            const char* name = "ANON", int depth = 0) {
385       int x_idxs_rows = rvalue_index_size(idxs.head_, x.rows());
386       int x_idxs_cols = rvalue_index_size(idxs.tail_.head_, x.cols());
387       math::check_size_match("matrix[multi,multi] assign sizes",
388                              "lhs", x_idxs_rows,
389                              name, y.rows());
390       math::check_size_match("matrix[multi,multi] assign sizes",
391                              "lhs", x_idxs_cols,
392                              name, y.cols());
393       for (int j = 0; j < y.cols(); ++j) {
394         int n = rvalue_at(j, idxs.tail_.head_);
395         math::check_range("matrix[multi,multi] assign range", name,
396                           x.cols(), n);
397         for (int i = 0; i < y.rows(); ++i) {
398           int m = rvalue_at(i, idxs.head_);
399           math::check_range("matrix[multi,multi] assign range", name,
400                             x.rows(), m);
401           x(m - 1, n - 1) = y(i, j);
402         }
403       }
404     }
405 
406     /**
407      * Assign the specified array (standard vector) at the specified
408      * index list beginning with a single index to the specified value.
409      *
410      * This function operates recursively to carry out the tail
411      * indexing.
412      *
413      * Types:  x[uni | L] = y
414      *
415      * @tparam T Assigned vector member type.
416      * @tparam L Type of tail of index list.
417      * @tparam U Value scalar type (must be assignable to indexed
418      * variable).
419      * @param[in] x Array variable to be assigned.
420      * @param[in] idxs List of indexes beginning with single index
421      * (from 1).
422      * @param[in] y Value.
423      * @param[in] name Name of variable (default "ANON").
424      * @param[in] depth Indexing depth (default 0).
425      * @throw std::out_of_range If any of the indices are out of bounds.
426      * @throw std::invalid_argument If the dimensions do not match in the
427      * tail assignment.
428      */
429     template <typename T, typename L, typename U>
assign(std::vector<T> & x,const cons_index_list<index_uni,L> & idxs,const U & y,const char * name="ANON",int depth=0)430     inline void assign(std::vector<T>& x,
431                        const cons_index_list<index_uni, L>& idxs, const U& y,
432                        const char* name = "ANON", int depth = 0) {
433       int i = idxs.head_.n_;
434       math::check_range("vector[uni,...] assign range", name, x.size(), i);
435       assign(x[i - 1], idxs.tail_, y, name, depth + 1);
436     }
437 
438     /**
439      * Assign the specified array (standard vector) at the specified
440      * index list beginning with a multiple index to the specified value.
441      *
442      * This function operates recursively to carry out the tail
443      * indexing.
444      *
445      * Types:  x[multi | L] = y
446      *
447      * @tparam T Assigned vector member type.
448      * @tparam I Type of multiple index heading index list.
449      * @tparam L Type of tail of index list.
450      * @tparam U Value scalar type (must be assignable to indexed
451      * variable).
452      * @param[in] x Array variable to be assigned.
453      * @param[in] idxs List of indexes beginning with multiple index
454      * (from 1).
455      * @param[in] y Value.
456      * @param[in] name Name of variable (default "ANON").
457      * @param[in] depth Indexing depth (default 0).
458      * @throw std::out_of_range If any of the indices are out of bounds.
459      * @throw std::invalid_argument If the size of the multiple indexing
460      * and size of first dimension of value do not match, or any of
461      * the recursive tail assignment dimensions do not match.
462      */
463     template <typename T, typename I, typename L, typename U>
464     typename boost::disable_if<boost::is_same<I, index_uni>, void>::type
assign(std::vector<T> & x,const cons_index_list<I,L> & idxs,const std::vector<U> & y,const char * name="ANON",int depth=0)465     inline assign(std::vector<T>& x, const cons_index_list<I, L>& idxs,
466                   const std::vector<U>& y,
467                   const char* name = "ANON", int depth = 0) {
468       int x_idx_size = rvalue_index_size(idxs.head_, x.size());
469       math::check_size_match("vector[multi,...] assign sizes",
470                              "lhs", x_idx_size,
471                              name, y.size());
472       for (size_t n = 0; n < y.size(); ++n) {
473         int i = rvalue_at(n, idxs.head_);
474         math::check_range("vector[multi,...] assign range", name, x.size(), i);
475         assign(x[i - 1], idxs.tail_, y[n], name, depth + 1);
476       }
477     }
478 
479   }
480 }
481 #endif
482