ไลบรารี C ++ สำหรับการรวมตัวเลข (การสร้างพื้นที่สี่เหลี่ยมจัตุรัส)


10

ฉันมีรูทีนย่อยเล็ก ๆ ของตัวเองสำหรับการรวมเชิงตัวเลข (การสร้างพื้นที่สี่เหลี่ยมจัตุรัส) ซึ่งเป็นการดัดแปลง C ++ ของโปรแกรม ALGOL ที่เผยแพร่โดย Bulirsch & Stoer ในปี 1967 (Numerische Mathematik, 9, 271-278)

ฉันต้องการอัปเกรดเป็นอัลกอริทึม (ปรับตัว) ที่ทันสมัยกว่าและสงสัยว่ามีไลบรารี่ C ++ ใด ๆ ที่ให้บริการดังกล่าวหรือไม่ ฉันดูเป็น GSL (ซึ่งเป็น C) แต่นั่นมาพร้อมกับ API ที่น่ากลัว (แม้ว่าตัวเลขอาจจะดี) มีอะไรอีกไหม?

API ที่มีประโยชน์จะมีลักษณะดังนี้:

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
นอกเหนือจากนี้คุณจะพบว่าการใช้งานที่ดีที่สุดในด้านวิทยาศาสตร์การคำนวณมี API "ไม่ดี" เพียงเพราะพวกเขาได้รับการพัฒนามานานหลายทศวรรษมากกว่าที่จะเป็นเดือนหรือปีของซอฟต์แวร์อื่น ๆ ฉันคิดว่ามันจะเป็นที่ยอมรับและน่าจะมีประโยชน์มากสำหรับคุณในการเขียน wrapper API และเรียกภายใน API ที่ไม่สะอาด สิ่งนี้จะช่วยให้คุณได้ประโยชน์จาก API ที่ดีในรหัสหลักของคุณและยังช่วยให้คุณสามารถสลับระหว่างไลบรารีการสร้างพื้นที่สี่เหลี่ยมที่แตกต่างกันได้อย่างง่ายดาย
Godric Seer

1
@GodricSeer ถ้ามันง่ายขนาดนั้น อย่างไรก็ตามมันไม่ได้เป็น GSL API ต้องการบัฟเฟอร์ที่จัดสรรล่วงหน้าซึ่งอาจไม่มีอะไรใช้ แต่อาจมีขนาดเล็กเกินไป (ต้องการการโทรอีกครั้งที่มีหน่วยความจำมากกว่า) การใช้งานที่เหมาะสมจะเกิดขึ้นซ้ำไม่ต้องมีการจัดสรรเก็บข้อมูลทั้งหมดบนสแต็กและจัดเตรียม API แบบใหม่ทั้งหมด
Walter

1
@GodricSeer ปัญหาร้ายแรงอีกประการหนึ่งของ GSL API คือการยอมรับฟังก์ชั่นที่ไม่มีสถานะ (เพราะใช้ตัวชี้ฟังก์ชั่นง่าย ๆ ) การสร้าง threadsafe API สำหรับฟังก์ชั่นที่มีสถานะจากสิ่งนี้ไม่จำเป็นต้องมีประสิทธิภาพ
Walter

2
ฉันเห็นด้วยกับ Godric Seer การเขียนเสื้อคลุมเป็นตัวเลือกที่ดีที่สุด ฉันไม่คิดว่ามันถูกต้องที่ "GSL ยอมรับเฉพาะฟังก์ชั่นที่ไม่มีสถานะ": ที่นี่ในเอกสารมันบอกว่าgsl_functionเป็นตัวชี้ฟังก์ชั่นร่วมกับตัวชี้ข้อมูลทึบบางซึ่งสามารถมีรัฐของคุณ ประการที่สองมีความกังวลเกี่ยวกับประสิทธิภาพเกี่ยวกับ (อีกครั้ง) การจัดสรรบัฟเฟอร์งานขนาดใหญ่โดยพลการดังนั้นส่วนนั้นจึงมีเหตุผลที่ถูกต้องบางอย่าง
คิริลล์

1
ความคิดเห็นอื่นเกี่ยวกับบัฟเฟอร์ที่จัดสรรไว้ล่วงหน้าของ GSL ขนาดของเวิร์กสเปซถูกกำหนดในแง่ของจำนวนช่วงเวลาสูงสุด - เนื่องจากคุณต้องการให้รูทีนการสร้างพื้นที่สี่เหลี่ยมจัตุรัสจะล้มเหลวต่อไปถ้ามันใช้การแบ่งส่วนแบบปรับได้มากเกินไปเพียงแค่ตั้งขนาดของเวิร์กสเปซ เมื่อคุณพูดถึงการใช้งาน "ถูกต้อง" GSL จะทำสิ่งที่ "ถูกต้อง" ที่นี่มันแบ่งช่วงเวลาด้วยข้อผิดพลาดที่ใหญ่ที่สุดในปัจจุบันซึ่งหมายความว่าจะต้องติดตามช่วงเวลาทั้งหมด หากคุณเก็บข้อมูลทั้งหมดไว้ในสแต็กคุณอาจเรียกใช้หน่วยความจำสแต็กไม่ดีขึ้นจริงๆ
คิริลล์

คำตอบ:


3

ลองดูที่Odeint ตอนนี้เป็นส่วนหนึ่งของ Boost และมีอัลกอริทึม Bulirsch-Stoer ในการเริ่มต้นที่คุณสามารถดูที่นี่เป็นตัวอย่างที่ง่ายมาก


3
ประโยคแรกของภาพรวมสำหรับ odeint คือ: "odeint เป็นห้องสมุดสำหรับการแก้ปัญหาค่าเริ่มต้น (IVP) ของสมการเชิงอนุพันธ์สามัญ" เท่าที่ฉันทราบไลบรารีนี้ไม่สามารถใช้สำหรับการสร้างพื้นที่สี่เหลี่ยมของฟังก์ชันที่รู้จัก คุณมีตัวอย่างที่ใช้เป็นพื้นที่สี่เหลี่ยมหรือไม่?
Bill Greene

1
ฉันคิดว่า (ฉันไม่ได้ใช้ห้องสมุดของตัวเอง) ว่ามันไม่ได้รวมอัลกอริทึมสำหรับการสร้างพื้นที่สี่เหลี่ยมเช่นใน Newton-Cotes, Romberg หรือการสร้างพื้นที่สี่เหลี่ยมจัตุรัส Gaussian แต่เนื่องจากคำถามที่กล่าวถึงวิธีการ Gragg-Bulirsch-Stoer เป็นการรวม ODE
Zythos

2

MFEM [1] มีฟังก์ชั่นการสร้างพื้นที่สี่เหลี่ยมจัตุรัสที่ง่ายต่อการใช้งาน (ทั้งสำหรับองค์ประกอบการโต้คลื่นและปริมาตร) เราสามารถใช้พวกเขาสำหรับงานต่างๆ

[1] http://mfem.org/


2

คุณสามารถเขียน wrapper C ++ แบบบาง ๆ รอบ ๆ ฟังก์ชันการสร้างพื้นที่สี่เหลี่ยมจัตุรัส GSL ได้อย่างง่ายดาย ความต้องการต่อไปนี้ของ 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';
}

เอาท์พุต

\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

ฉันประสบความสำเร็จกับห้องสมุด Cubature (เขียนด้วยภาษา C) มันมีจุดมุ่งหมายเพื่อบูรณาการหลายมิติที่มีจำนวนค่อนข้างต่ำ

ห้องสมุด HIntLibถูกเขียนใน C ++ และมีการปฏิบัติสำหรับการสร้างพื้นที่สี่เหลี่ยมจัตุรัสการปรับตัว (cubature)


1

ตรวจสอบhttps://github.com/tbs1980/NumericalIntegration มันขึ้นอยู่กับ QUADPACK (ซึ่ง GSL ยังเป็นไปตาม) และมีคุณสมบัติที่ทันสมัยบางอย่างเช่นบนพื้นฐานของ Eigen, การสนับสนุนหลายที่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.