Ejemplo n.º 1
0
Archivo: poly.c Proyecto: nclack/whisk
void polyfit( double *x, double *y, int n, int degree, double *coeffs, double *workspace )
{ int ncoeffs = degree + 1;
  double *u = workspace,   
         *w = u + n*ncoeffs,
         *v = w + ncoeffs;  
  double **iu = mat_index(u,     n,ncoeffs),
         **iv = mat_index(v,ncoeffs,ncoeffs);
  
  Vandermonde_Build(x,n,ncoeffs,u);
#ifdef DEBUG_POLYFIT
  printf("\nV:\n");
  mat_print( u, n, ncoeffs);
#endif
  svd( iu, n, ncoeffs, w, iv );  
  free(iu);
  free(iv);
  svd_threshold( POLYFIT_SINGULAR_THRESHOLD, w, ncoeffs );
#ifdef DEBUG_POLYFIT
  printf("\n---Got---\n");
  printf("\nU:\n");
  mat_print( u, n, ncoeffs);
  printf("\nS:\n");
  mat_print( w, ncoeffs, 1);
  printf("\nV:\n");
  mat_print( v, ncoeffs, ncoeffs);
  printf("\nU S V':\n");
  mat_print(
      matmul_right_transpose_static( 
            matmul_right_vec_as_diag_static( u, n, ncoeffs,
                                             w, ncoeffs),
               n, ncoeffs,
            v, ncoeffs, ncoeffs),
      n, ncoeffs);
#endif

  polyfit_reuse( y, n, degree, coeffs, workspace );
}
Stokhos::ProductLanczosPCEBasis<ordinal_type, value_type>::
ProductLanczosPCEBasis(
  ordinal_type p,
  const Teuchos::Array< Stokhos::OrthogPolyApprox<ordinal_type, value_type> >& pce,
  const Teuchos::RCP<const Stokhos::Quadrature<ordinal_type, value_type> >& quad,
  const Teuchos::RCP< const Stokhos::Sparse3Tensor<ordinal_type, value_type> >& Cijk,
  const Teuchos::ParameterList& params_) :
  name("Product Lanczos PCE Basis"),
  params(params_)
{
  Teuchos::RCP<const Stokhos::OrthogPolyBasis<ordinal_type,value_type> > pce_basis = pce[0].basis();
  ordinal_type pce_sz = pce_basis->size();

  // Check if basis is a product basis
  Teuchos::RCP<const Stokhos::ProductBasis<ordinal_type,value_type> > prod_basis = Teuchos::rcp_dynamic_cast<const Stokhos::ProductBasis<ordinal_type,value_type> >(pce_basis);
  Teuchos::Array< Teuchos::RCP<const OneDOrthogPolyBasis<ordinal_type,value_type> > > coord_bases;
  if (prod_basis != Teuchos::null)
    coord_bases = prod_basis->getCoordinateBases();

  // Build Lanczos basis for each pce
  bool project = params.get("Project", true);
  bool normalize = params.get("Normalize", true);
  bool limit_integration_order = params.get("Limit Integration Order", false);
  bool use_stieltjes = params.get("Use Old Stieltjes Method", false);
  Teuchos::Array< Teuchos::RCP<const Stokhos::OneDOrthogPolyBasis<int,double > > > coordinate_bases;
  Teuchos::Array<int> is_invariant(pce.size(),-2);
  for (ordinal_type i=0; i<pce.size(); i++) {

    // Check for pce's lying in invariant subspaces, which are pce's that
    // depend on only a single dimension.  In this case use the corresponding
    // original coordinate basis.  Convention is:  -2 -- not invariant, -1 --
    // constant, i >= 0 pce depends only on dimension i
    if (prod_basis != Teuchos::null)
      is_invariant[i] = isInvariant(pce[i]);
    if (is_invariant[i] >= 0) {
      coordinate_bases.push_back(coord_bases[is_invariant[i]]);
    }

    // Exclude constant pce's from the basis since they don't represent
    // stochastic dimensions
    else if (is_invariant[i] != -1) {
      if (use_stieltjes) {
	coordinate_bases.push_back(
	  Teuchos::rcp(
	    new Stokhos::StieltjesPCEBasis<ordinal_type,value_type>(
	      p, Teuchos::rcp(&(pce[i]),false), quad, false,
	      normalize, project, Cijk)));
      }
      else {
	if (project) 
	  coordinate_bases.push_back(
	    Teuchos::rcp(
	      new Stokhos::LanczosProjPCEBasis<ordinal_type,value_type>(
		p, Teuchos::rcp(&(pce[i]),false), Cijk,
		normalize, limit_integration_order)));
	else
	  coordinate_bases.push_back(
	    Teuchos::rcp(
	      new Stokhos::LanczosPCEBasis<ordinal_type,value_type>(
		p, Teuchos::rcp(&(pce[i]),false), quad,
		normalize, limit_integration_order)));
      }
    }
  }
  ordinal_type d = coordinate_bases.size();

  // Build tensor product basis
  tensor_lanczos_basis = 
    Teuchos::rcp(
      new Stokhos::CompletePolynomialBasis<ordinal_type,value_type>(
	coordinate_bases,
	params.get("Cijk Drop Tolerance", 1.0e-15),
	params.get("Use Old Cijk Algorithm", false)));

  // Build reduced quadrature
  Teuchos::ParameterList sg_params;
  sg_params.sublist("Basis").set< Teuchos::RCP< const Stokhos::OrthogPolyBasis<ordinal_type,value_type> > >("Stochastic Galerkin Basis", tensor_lanczos_basis);
  sg_params.sublist("Quadrature") = params.sublist("Reduced Quadrature");
  reduced_quad = 
    Stokhos::QuadratureFactory<ordinal_type,value_type>::create(sg_params);

  // Build Psi matrix -- Psi_ij = Psi_i(x^j)*w_j/<Psi_i^2>
  const Teuchos::Array<value_type>& weights = quad->getQuadWeights();
  const Teuchos::Array< Teuchos::Array<value_type> >& points = 
    quad->getQuadPoints(); 
  const Teuchos::Array< Teuchos::Array<value_type> >& basis_vals = 
    quad->getBasisAtQuadPoints();
  ordinal_type nqp = weights.size();
  SDM Psi(pce_sz, nqp);
  for (ordinal_type i=0; i<pce_sz; i++)
    for (ordinal_type k=0; k<nqp; k++)
      Psi(i,k) = basis_vals[k][i]*weights[k]/pce_basis->norm_squared(i);

  // Build Phi matrix -- Phi_ij = Phi_i(y(x^j))
  ordinal_type sz = tensor_lanczos_basis->size();
  Teuchos::Array<value_type> red_basis_vals(sz);
  Teuchos::Array<value_type> pce_vals(d);
  Phi.shape(sz, nqp);
  for (int k=0; k<nqp; k++) {
    ordinal_type jdx = 0;
    for (int j=0; j<pce.size(); j++) {

      // Exclude constant pce's
      if (is_invariant[j] != -1) {

	// Use the identity mapping for invariant subspaces
	if (is_invariant[j] >= 0)
	  pce_vals[jdx] = points[k][is_invariant[j]];
	else
	  pce_vals[jdx] = pce[j].evaluate(points[k], basis_vals[k]);
	jdx++;

      }

    }
    tensor_lanczos_basis->evaluateBases(pce_vals, red_basis_vals);
    for (int i=0; i<sz; i++)
      Phi(i,k) = red_basis_vals[i];
  }

  bool verbose = params.get("Verbose", false);
 
  // Compute matrix A mapping reduced space to original
  A.shape(pce_sz, sz);
  ordinal_type ret = 
    A.multiply(Teuchos::NO_TRANS, Teuchos::TRANS, 1.0, Psi, Phi, 0.0);
  TEUCHOS_ASSERT(ret == 0);
  //print_matlab(std::cout << "A = " << std::endl, A);

  // Compute pseudo-inverse of A mapping original space to reduced
  // A = U*S*V^T -> A^+ = V*S^+*U^T = (S^+*V^T)^T*U^T where 
  // S^+ is a diagonal matrix comprised of the inverse of the diagonal of S
  // for each nonzero, and zero otherwise
  Teuchos::Array<value_type> sigma;
  SDM U, Vt;
  value_type rank_threshold = params.get("Rank Threshold", 1.0e-12);
  ordinal_type rank = svd_threshold(rank_threshold, A, sigma, U, Vt);
  Ainv.shape(sz, pce_sz);
  TEUCHOS_ASSERT(rank == Vt.numRows());
  for (ordinal_type i=0; i<Vt.numRows(); i++)
    for (ordinal_type j=0; j<Vt.numCols(); j++)
      Vt(i,j) = Vt(i,j) / sigma[i];
  ret = Ainv.multiply(Teuchos::TRANS, Teuchos::TRANS, 1.0, Vt, U, 0.0);
  TEUCHOS_ASSERT(ret == 0);
  //print_matlab(std::cout << "Ainv = " << std::endl, Ainv);

  if (verbose) {
    std::cout << "rank = " << rank << std::endl;
    
    std::cout << "diag(S) = [";
    for (ordinal_type i=0; i<rank; i++)
      std::cout << sigma[i] << " ";
    std::cout << "]" << std::endl;

    // Check A = U*S*V^T
    SDM SVt(rank, Vt.numCols());
    for (ordinal_type i=0; i<Vt.numRows(); i++)
      for (ordinal_type j=0; j<Vt.numCols(); j++)
	SVt(i,j) = Vt(i,j) * sigma[i] * sigma[i];  // since we divide by sigma 
                                                   // above
    SDM err_A(pce_sz,sz);
    err_A.assign(A);
    ret = err_A.multiply(Teuchos::NO_TRANS, Teuchos::NO_TRANS, -1.0, U, SVt, 
			 1.0);
    TEUCHOS_ASSERT(ret == 0);
    std::cout << "||A - U*S*V^T||_infty = " << err_A.normInf() << std::endl;
    //print_matlab(std::cout << "A - U*S*V^T = " << std::endl, err_A);
 
    // Check Ainv*A == I
    SDM err(sz,sz);
    err.putScalar(0.0);
    for (ordinal_type i=0; i<sz; i++)
      err(i,i) = 1.0;
    ret = err.multiply(Teuchos::NO_TRANS, Teuchos::NO_TRANS, 1.0, Ainv, A, 
		       -1.0);
    TEUCHOS_ASSERT(ret == 0);
    std::cout << "||Ainv*A - I||_infty = " << err.normInf() << std::endl;
    //print_matlab(std::cout << "Ainv*A-I = " << std::endl, err);

    // Check A*Ainv == I
    SDM err2(pce_sz,pce_sz);
    err2.putScalar(0.0);
    for (ordinal_type i=0; i<pce_sz; i++)
      err2(i,i) = 1.0;
    ret = err2.multiply(Teuchos::NO_TRANS, Teuchos::NO_TRANS, 1.0, A, Ainv, -1.0);
    TEUCHOS_ASSERT(ret == 0);
    std::cout << "||A*Ainv - I||_infty = " << err2.normInf() << std::endl;
    //print_matlab(std::cout << "A*Ainv-I = " << std::endl, err2);
  }
}