void DenseLinAlgPack::V_MtV(DVector* v_lhs, const DMatrixSliceTri& tri_rhs1, BLAS_Cpp::Transp trans_rhs1
  , const DVectorSlice& vs_rhs2)
{
  assert_gms_square(tri_rhs1.gms());
  MtV_assert_sizes(tri_rhs1.gms().rows(), tri_rhs1.gms().cols(), trans_rhs1, vs_rhs2.dim());
  v_lhs->resize(tri_rhs1.gms().rows());
  (*v_lhs) = vs_rhs2;
  BLAS_Cpp::trmv(tri_rhs1.uplo(),trans_rhs1,tri_rhs1.diag(),tri_rhs1.gms().rows()
    ,tri_rhs1.gms().col_ptr(1),tri_rhs1.gms().max_rows(), v_lhs->raw_ptr(),1);
}
void DenseLinAlgPack::Mp_StM(DMatrixSlice* gms_lhs, value_type alpha, const DMatrixSliceTri& tri_rhs
  , BLAS_Cpp::Transp trans_rhs)
{
  using BLAS_Cpp::trans;
  using BLAS_Cpp::no_trans;
  using BLAS_Cpp::lower;
  using BLAS_Cpp::upper;
  Mp_M_assert_sizes(gms_lhs->rows(), gms_lhs->cols(), BLAS_Cpp::no_trans
    , tri_rhs.rows(), tri_rhs.cols(), trans_rhs );
  // diagonal
  if( tri_rhs.diag() == BLAS_Cpp::nonunit )
    Vp_StV( &gms_lhs->diag(), alpha, tri_rhs.gms().diag() );
  else
    Vp_S( &gms_lhs->diag(), alpha );
  // upper or lower triangle
  const size_type n = gms_lhs->rows(); // same as cols
  if( n == 1 )
    return;	// There is not lower or upper triangular region
  const DMatrixSliceTriEle
    tri = ( tri_rhs.uplo() == lower
        ?		tri_ele(tri_rhs.gms()(2,n,1,n-1),lower)
           :  tri_ele(tri_rhs.gms()(1,n-1,2,n),upper) );
  const BLAS_Cpp::Uplo
    as_uplo = (		( tri_rhs.uplo() == lower && trans_rhs == no_trans )
          ||	( tri_rhs.uplo() == upper && trans_rhs == trans )
          ?	lower : upper											);
  switch(as_uplo) {
    case lower:
      Mp_StM( const_cast<DenseLinAlgPack::DMatrixSliceTriEle*>(
            &tri_ele((*gms_lhs)(2,n,1,n-1),lower) )
          , alpha, tri );
      break;
    case upper:
      Mp_StM( const_cast<DenseLinAlgPack::DMatrixSliceTriEle*>(
            &tri_ele((*gms_lhs)(1,n-1,2,n),upper) )
          , alpha, tri );
      break;
  }
}