const ExprChi& ExprChi::new_(const ExprNode& a, const ExprNode& b, const ExprNode& c) { if (!(a.type() == Dim::SCALAR)) throw DimException("\"chi\" expects scalar arguments"); if (!(b.type() == Dim::SCALAR)) throw DimException("\"chi\" expects scalar arguments"); if (!(c.type() == Dim::SCALAR)) throw DimException("\"chi\" expects scalar arguments"); const ExprNode* args2[3] = {&a,&b,&c}; return *new ExprChi(args2); }
const ExprChi& ExprChi::new_(const ExprNode& a, const ExprNode& b, const ExprNode& c) { if (!(a.type() == Dim::SCALAR)) throw DimException("\"chi\" expects scalar arguments"); if (!(b.type() == Dim::SCALAR)) throw DimException("\"chi\" expects scalar arguments"); if (!(c.type() == Dim::SCALAR)) throw DimException("\"chi\" expects scalar arguments"); return *new ExprChi(Array<const ExprNode>(a,b,c)); }
Dim mul_dim(const Dim& l, const Dim& r) { if (l.dim1!=1 || r.dim1!=1) throw DimException("cannot multiply a matrix array"); if (l.type()==Dim::SCALAR) // scalar multiplication. return r; else { if (l.dim3!=r.dim2) { if (l.dim2==r.dim2) { if (r.dim3==1) // dot product return Dim::scalar(); else // vector-matrix product return Dim::row_vec(r.dim3); } throw DimException("mismatched dimensions in matrix multiplication"); } else { if (l.dim2==1) if (r.dim3==1) return Dim::scalar(); else return Dim::row_vec(r.dim3); else if (r.dim3==1) return Dim::col_vec(l.dim2); else return Dim::matrix(l.dim2,r.dim3); } } }
Dim vec_dim(const Array<const Dim>& comp, bool in_a_row) { int n=comp.size(); if (n==0) throw DimException("a 0-sized vector has no dimension"); const Dim& d=comp[0]; if (d.is_scalar()) { if (in_a_row) { for (int i=0; i<n; i++) // we could allow concatenation of // row vectors of different size // in a single row vector; // (but not implemented yet) if (comp[i].type()!=Dim::SCALAR) goto error; return Dim::row_vec(n); } else { for (int i=0; i<n; i++) // we could allow concatenation of // column vectors of different size // in a single column vector; // (but not implemented yet) if (comp[i].type()!=Dim::SCALAR) goto error; return Dim::col_vec(n); } } else if (d.is_vector()) { if (in_a_row) { for (int i=0; i<n; i++) // same comment as above: we could also // put matrices with different number of columns // in a row. Not implemented. Only column vectors are accepted if (comp[i].type()!=Dim::COL_VECTOR || comp[i].dim2!=d.dim2) goto error; return Dim::matrix(d.dim2,n); } else { for (int i=0; i<n; i++) { // same comment as above: we could also // put matrices with different number of rows // in column. Not implemented. Only row vectors are accepted if (comp[i].type()!=Dim::ROW_VECTOR || comp[i].dim3!=d.dim3) goto error; } return Dim::matrix(n,d.dim3); } } // notice: array of matrix expressions are only used // so far in unvectorizing (for symbols corresponding to matrix arrays) else if (d.type()==Dim::MATRIX) { for (int i=0; i<n; i++) if (comp[i].type()!=Dim::MATRIX || comp[i].dim2!=d.dim2 || comp[i].dim3!=d.dim3) goto error; return Dim::matrix_array(n,d.dim2,d.dim3); } error: throw DimException("impossible to form a vector with heterogeneous components"); }
Dim Dim::transpose_dim() const { switch (type()) { case SCALAR: return *this; case ROW_VECTOR: return col_vec(vec_size()); case COL_VECTOR: return row_vec(vec_size()); case MATRIX: return matrix(dim3,dim2); case MATRIX_ARRAY: default: throw DimException("cannot transpose an array of matrices"); return *this; } }
ExprApply::ExprApply(const Function& f, const ExprNode** args) : ExprNAryOp(args,f.nb_arg(),f.expr().dim), func(f) { for (int i=0; i<f.nb_arg(); i++) { if (args[i]->dim.is_vector()) { // we allow automatic transposition of vector arguments if (f.arg(i).dim.is_vector() && (args[i]->dim.vec_size()==f.arg(i).dim.vec_size())) continue; } else { // otherwise, dimensions must match exactly. if (args[i]->dim == f.arg(i).dim) continue; } stringstream s; s << "dimension of the " << (i+1) << "th argument passed to \"" << f.name << "\" "; s << "do not match that of the formal argument \"" << f.arg_name(i) << "\""; throw DimException(s.str()); } }
ExprIndex::ExprIndex(const ExprNode& subexpr, int index) : ExprNode(subexpr.height+1, subexpr.size+1, subexpr.dim.index_dim()), expr(subexpr), index(index) { if (index<0 || index>subexpr.dim.max_index()) throw DimException("index out of bounds"); ((ExprNode&) (subexpr)).fathers.add(*this); }
ExprAtanh::ExprAtanh(const ExprNode& expr) : ExprUnaryOp(expr,expr.dim) { if (!expr.dim.is_scalar()) throw DimException("\"atanh\" expects a scalar argument"); }
ExprSin::ExprSin(const ExprNode& expr) : ExprUnaryOp(expr,expr.dim) { if (!expr.dim.is_scalar()) throw DimException("\"sin\" expects a scalar argument"); }
ExprAtan2::ExprAtan2(const ExprNode& left, const ExprNode& right) : ExprBinaryOp(left,right,Dim()) { if (!(left.type() == Dim::SCALAR)) throw DimException("\"atan2\" expects scalar arguments"); if (!(right.type() == Dim::SCALAR)) throw DimException("\"atan2\" expects scalar arguments"); }
ExprDiv::ExprDiv(const ExprNode& left, const ExprNode& right) : ExprBinaryOp(left,right,Dim()) { if (!(left.type() == Dim::SCALAR)) throw DimException("cannot divide a non-scalar expression"); if (!(right.type() == Dim::SCALAR)) throw DimException("cannot divide by a non-scalar expression"); }
ExprSub::ExprSub(const ExprNode& left, const ExprNode& right) : ExprBinaryOp(left,right,left.dim) { if (!(left.dim == right.dim)) throw DimException("mismatched dimensions in subtraction"); }
ExprAdd::ExprAdd(const ExprNode& left, const ExprNode& right) : ExprBinaryOp(left,right,left.dim) { if (!(left.dim == right.dim)) throw DimException("mismatched dimensions in addition"); }
const ExprChi& ExprChi::new_(const ExprNode** args) { if (!(args[0]->type() == Dim::SCALAR)) throw DimException("\"chi\" expects scalar arguments"); if (!(args[1]->type() == Dim::SCALAR)) throw DimException("\"chi\" expects scalar arguments"); if (!(args[2]->type() == Dim::SCALAR)) throw DimException("\"chi\" expects scalar arguments"); return *new ExprChi(args); }