Thư viện C ++ để tích hợp số (cầu phương)


10

Tôi có chương trình con nhỏ của riêng mình để tích hợp số (bậc hai), đó là bản chuyển thể C ++ của chương trình ALGOL do Bulirsch & Stoer xuất bản năm 1967 (Numerische Mathematik, 9, 271-278).

Tôi muốn nâng cấp lên một thuật toán (thích ứng) hiện đại hơn và tự hỏi liệu có thư viện C ++ nào (miễn phí) cung cấp như vậy không. Tôi đã có một cái nhìn như GSL (là C), nhưng nó đi kèm với một API khủng khiếp (mặc dù số có thể tốt). Có gì khác?

Một API hữu ích sẽ trông như thế này:

double quadrature(double lower_integration_limit,
                  double upper_integration_limit,
                  std::function<double(double)> const&func,
                  double desired_error_bound_relative=1.e-12,
                  double desired_error_bound_absolute=0,
                  double*error_estimate=nullptr);

7
Chỉ là một bên, bạn sẽ thấy rằng nhiều triển khai tốt nhất trong khoa học tính toán có API "xấu" đơn giản vì chúng đã được phát triển qua nhiều thập kỷ, thay vì nhiều tháng hoặc nhiều năm của phần mềm khác. Tôi nghĩ rằng nó có thể được chấp nhận và có thể rất hữu ích cho bạn để viết API trình bao bọc và gọi nội bộ API ít sạch hơn. Điều này mang lại cho bạn lợi thế của một API đẹp trong các mã chính của bạn và cũng cho phép bạn dễ dàng chuyển đổi giữa các thư viện bậc hai khác nhau chỉ bằng cách viết lại một hàm duy nhất.
Godric Seer

1
@GodricSeer Nếu nó đơn giản, tôi sẽ làm điều đó. Tuy nhiên, nó không phải là. API GSL yêu cầu bộ đệm được phân bổ trước, trong đó có thể không sử dụng được gì, nhưng có khả năng có thể quá nhỏ (yêu cầu một cuộc gọi khác có nhiều bộ nhớ hơn). Việc triển khai đúng sẽ được đệ quy, không cần phân bổ, giữ tất cả dữ liệu trên ngăn xếp và cung cấp API sạch.
Walter

1
@GodricSeer Một vấn đề nghiêm trọng khác với API GSL là nó chỉ chấp nhận các chức năng mà không có trạng thái (vì nó sử dụng một con trỏ hàm đơn giản). Tạo API chủ đề an toàn cho các hàm có trạng thái từ đây là không hiệu quả.
Walter

2
Tôi đồng ý với Godric Seer, viết một trình bao bọc là lựa chọn tốt nhất. Tôi không nghĩ đúng là "GSL chỉ chấp nhận các hàm không có trạng thái": ở đây trong các tài liệu có ghi gsl_functionlà một con trỏ hàm cùng với một số con trỏ dữ liệu mờ, có thể chứa trạng thái của bạn. Thứ hai, có một số lo ngại về hiệu quả về việc (phân bổ lại) bộ đệm công việc lớn tùy ý, do đó phần đó có ít nhất một số biện minh hợp lệ cho nó.
Kirill

1
Một nhận xét khác về bộ đệm được phân bổ trước của GSL. Kích thước của không gian làm việc được xác định theo số lượng khoảng thời gian tối đa - vì dù sao bạn cũng muốn thói quen cầu phương không thành công nếu cần quá nhiều phép chia thích ứng, chỉ cần đặt kích thước của không gian làm việc ở một số giới hạn trên cho số lần chia. Khi bạn nói về việc triển khai "đúng", GSL thực hiện điều "đúng" ở đây, nó chia đôi khoảng với lỗi lớn nhất hiện tại, nghĩa là nó phải theo dõi tất cả các khoảng thời gian cho đến nay. Nếu bạn giữ tất cả dữ liệu trên ngăn xếp, bạn có thể hết bộ nhớ ngăn xếp, điều đó không thực sự tốt hơn.
Kirill

Câu trả lời:


3

Hãy nhìn vào Odeint . Nó hiện là một phần của Boost và nó bao gồm thuật toán Bulirsch-Stoer trong số các thuật toán khác. Để bắt đầu, bạn có thể thấy ở đây một ví dụ rất đơn giản.


3
Câu đầu tiên của tổng quan về odeint là: "odeint là một thư viện để giải các bài toán giá trị ban đầu (IVP) của các phương trình vi phân thông thường." Theo như tôi biết, thư viện này không thể được sử dụng cho phương trình bậc hai của một hàm đã biết. Bạn có một ví dụ về nơi nó đã được sử dụng cho cầu phương không?
Bill Greene

1
Tôi nghĩ (bản thân tôi không sử dụng thư viện) rằng nó không bao gồm các thuật toán cho các ô vuông như trong phương pháp bậc hai Newton-Cotes, Romberg hay Gaussian nhưng cho rằng câu hỏi đã đề cập đến phương pháp Gragg-Bulirsch-Stoer là một sự tích hợp ODE.
Zythos

2

MFEM [1] có các hàm bậc hai dễ sử dụng (cả cho các yếu tố bề mặt và thể tích). Chúng tôi đã có thể sử dụng chúng cho các nhiệm vụ khác nhau.

[1] http://mfem.org/


2

Bạn có thể dễ dàng viết một trình bao bọc C ++ mỏng xung quanh các hàm bậc hai GSL. Các nhu cầu sau C ++ 11.

#include <iostream>
#include <cmath>

#include <functional>
#include <memory>
#include <utility>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_integration.h>

template < typename F >
class gsl_quad
{
  F f;
  int limit;
  std::unique_ptr < gsl_integration_workspace,
                    std::function < void(gsl_integration_workspace*) >
                    > workspace;

  static double gsl_wrapper(double x, void * p)
  {
    gsl_quad * t = reinterpret_cast<gsl_quad*>(p);
    return t->f(x);
  }

public:
  gsl_quad(F f, int limit)
    : f(f)
    , limit(limit)
    , workspace(gsl_integration_workspace_alloc(limit), gsl_integration_workspace_free)
  {}

  double integrate(double min, double max, double epsabs, double epsrel)
  {
    gsl_function gsl_f;
    gsl_f.function = &gsl_wrapper;
    gsl_f.params = this;

    double result, error;
    if ( !std::isinf(min) && !std::isinf(max) )
    {
      gsl_integration_qags ( &gsl_f, min, max,
                             epsabs, epsrel, limit,
                             workspace.get(), &result, &error );
    }
    else if ( std::isinf(min) && !std::isinf(max) )
    {
      gsl_integration_qagil( &gsl_f, max,
                             epsabs, epsrel, limit,
                             workspace.get(), &result, &error );
    }
    else if ( !std::isinf(min) && std::isinf(max) )
    {
      gsl_integration_qagiu( &gsl_f, min,
                             epsabs, epsrel, limit,
                             workspace.get(), &result, &error );
    }
    else
    {
      gsl_integration_qagi ( &gsl_f,
                             epsabs, epsrel, limit,
                             workspace.get(), &result, &error );
    }

    return result;
  }
};

template < typename F >
double quad(F func,
            std::pair<double,double> const& range,
            double epsabs = 1.49e-8, double epsrel = 1.49e-8,
            int limit = 50)
{
  return gsl_quad<F>(func, limit).integrate(range.first, range.second, epsabs, epsrel);
}

int main()
{
  std::cout << "\\int_0^1 x^2 dx = "
            << quad([](double x) { return x*x; }, {0,1}) << '\n'
            << "\\int_1^\\infty x^{-2} dx = "
            << quad([](double x) { return 1/(x*x); }, {1,INFINITY}) << '\n'
            << "\\int_{-\\infty}^\\infty \\exp(-x^2) dx = "
            << quad([](double x) { return std::exp(-x*x); }, {-INFINITY,INFINITY}) << '\n';
}

Đầu ra

\int_0^1 x^2 dx = 0.333333
\int_1^\infty x^{-2} dx = 1
\int_{-\infty}^\infty \exp(-x^2) dx = 1.77245

1

Tôi đã thành công với thư viện Cubature (mặc dù nó được viết bằng C). Nó nhằm mục đích tích hợp đa chiều với số lượng kích thước tương đối thấp.

Các thư viện HIntLib được viết bằng C ++ và nó có thói quen cho cầu phương thích nghi (cubature).


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.