void CubatureSparse<Scalar,dimension_,ArrayPoint,ArrayWeight>::getCubature(ArrayPoint  & cubPoints,
                                                                           ArrayWeight & cubWeights) const{
  Teuchos::Array<Scalar> dummy_point(1);
  dummy_point[0] = 0.0;
  Scalar dummy_weight = 1.0;
  SGNodes<Scalar, dimension_> grid;

  iterateThroughDimensions(level_, dimension_, grid, dummy_point, dummy_weight);
  
  grid.copyToArrays(cubPoints, cubWeights);
} // end getCubature
void iterateThroughDimensions(int level,
                              int dims_left,
                              SGNodes<Scalar,DIM> & cubPointsND,
                              Teuchos::Array<Scalar> & partial_node,
                              Scalar partial_weight)
{
  int l = level;
  int d = DIM;
  int add_on = d - dims_left;
  int start = dims_left > 1 ? 1 : (int)std::max(1, l);
  int end = l + add_on;

  for(int k_i = start; k_i <= end; k_i++)
  {
    /*******************
    **  Slow-Gauss
    ********************/
    int order1D = 2*k_i-1;

    /*******************
    **  Fast-Gauss
    ********************/
    //int order1D = (int)pow(2,k_i) - 1;

    int cubDegree1D = 2*order1D - 1;
    CubatureDirectLineGauss<Scalar> Cub1D(cubDegree1D);
    FieldContainer<Scalar> cubPoints1D(order1D, 1);
    FieldContainer<Scalar> cubWeights1D(order1D);

    Cub1D.getCubature(cubPoints1D, cubWeights1D);

    for(int node1D = 0; node1D < order1D; node1D++)
    {
      Teuchos::Array<Scalar> node(d-dims_left+1);
      node[d-dims_left] = cubPoints1D(node1D,0);
      for(int m = 0; m < d-dims_left; m++)
        node[m] = partial_node[m];

      Scalar weight = cubWeights1D(node1D)*partial_weight;

      if(dims_left != 1)
      {
        iterateThroughDimensions(l - k_i, dims_left-1, cubPointsND, node, weight);
      }
      else
      {
        weight = pow(-1.0, end - k_i)*combination(d-1, k_i - l)*weight;
        cubPointsND.addNode(&node[0], weight);
      }
    }
  }
}
CubatureGenSparse<Scalar,dimension_,ArrayPoint,ArrayWeight>::CubatureGenSparse(const int degree) :
    degree_(degree) {

    SGNodes<int, dimension_> list;
    SGNodes<int,dimension_> bigger_rules;

    bool continue_making_first_list = true;
    bool more_bigger_rules = true;

    int poly_exp[dimension_];
    int level[dimension_];
    int temp_big_rule[dimension_];

    for(int i = 0; i<dimension_; i++) {
        poly_exp[i] = 0;
        temp_big_rule[i] = 0;
    }

    while(continue_making_first_list) {
        for(int i = 0; i < dimension_; i++)
        {
            int max_exp = 0;
            if(i == 0)
                max_exp = std::max(degree_,1) - Sum(poly_exp,1,dimension_-1);
            else if(i == dimension_ -1)
                max_exp = std::max(degree_,1) - Sum(poly_exp,0,dimension_-2);
            else
                max_exp = std::max(degree_,1) - Sum(poly_exp,0,dimension_-1) + poly_exp[i];

            if(poly_exp[i] < max_exp)
            {
                poly_exp[i]++;
                break;
            }
            else
            {
                if(i == dimension_-1)
                    continue_making_first_list = false;
                else
                    poly_exp[i] = 0;

            }
        }

        if(continue_making_first_list)
        {
            for(int j = 0; j < dimension_; j++)
            {
                /*******************
                **  Slow-Gauss
                ********************/
                level[j] = (int)std::ceil((((Scalar)poly_exp[j])+3.0)/4.0);
                /*******************
                **  Fast-Gauss
                ********************/
                //level[j] = intstd::ceil(std::log(poly_exp[j]+3)/std::log(2) - 1);
            }
            list.addNode(level,1);

        }
    }


    while(more_bigger_rules)
    {
        bigger_rules.addNode(temp_big_rule,1);

        for(int i = 0; i < dimension_; i++)
        {
            if(temp_big_rule[i] == 0) {
                temp_big_rule[i] = 1;
                break;
            }
            else {
                if(i == dimension_-1)
                    more_bigger_rules = false;
                else
                    temp_big_rule[i] = 0;
            }
        }
    }

    for(int x = 0; x < list.size(); x++) {
        for(int y = 0; y < bigger_rules.size(); y++)
        {
            SGPoint<int, dimension_> next_rule;
            for(int t = 0; t < dimension_; t++)
                next_rule.coords[t] = list.nodes[x].coords[t] + bigger_rules.nodes[y].coords[t];

            bool is_in_set = false;
            for(int z = 0; z < list.size(); z++)
            {
                if(next_rule == list.nodes[z]) {
                    is_in_set = true;
                    break;
                }
            }

            if(is_in_set)
            {
                int big_sum[dimension_];
                for(int i = 0; i < dimension_; i++)
                    big_sum[i] = bigger_rules.nodes[y].coords[i];
                Scalar coeff = std::pow(-1.0, Sum(big_sum, 0, dimension_-1));

                Scalar point[dimension_];
                int point_record[dimension_];

                for(int j = 0; j<dimension_; j++)
                    point_record[j] = 1;

                bool more_points = true;

                while(more_points)
                {
                    Scalar weight = 1.0;

                    for(int w = 0; w < dimension_; w++) {
                        /*******************
                        **  Slow-Gauss
                        ********************/
                        int order1D = 2*list.nodes[x].coords[w]-1;
                        /*******************
                        **  Fast-Gauss
                        ********************/
                        //int order1D = (int)std::pow(2.0,next_rule.coords[w]) - 1;

                        int cubDegree1D = 2*order1D - 1;
                        CubatureDirectLineGauss<Scalar> Cub1D(cubDegree1D);
                        FieldContainer<Scalar> cubPoints1D(order1D, 1);
                        FieldContainer<Scalar> cubWeights1D(order1D);

                        Cub1D.getCubature(cubPoints1D, cubWeights1D);

                        point[w] =  cubPoints1D(point_record[w]-1, 0);
                        weight = weight * cubWeights1D(point_record[w]-1);
                    }
                    weight = weight*coeff;
                    grid.addNode(point, weight);

                    for(int v = 0; v < dimension_; v++)
                    {
                        if(point_record[v] < 2*list.nodes[x].coords[v]-1) {
                            (point_record[v])++;
                            break;
                        }
                        else {
                            if(v == dimension_-1)
                                more_points = false;
                            else
                                point_record[v] = 1;
                        }
                    }
                }
            }
        }
    }

    numPoints_ = grid.size();
}