[TOC]html
QuantLib 已經開始在 PyPi 上發佈封裝好的 Python 接口,安裝和使用很是方便,與普通的包別無二致。而且更新及時,保持對應最新版本的 QuantLib。python
官方發佈的 Python 接口,其優勢是廣度和全面,缺點是深度不足。有時候用戶須要的功能剛好沒有被封裝(《收益率曲線之構建曲線(3)》一文中曾經提到過),但願從新封裝接口,添加本身須要的功能;亦或是用戶已經在 C++ 源代碼層面上擴展或修復了 QuantLib,但願包裝擴展的新功能,並與官方的 Python 接口聯合使用。linux
不管是上述哪一種狀況,都須要用戶本身動手封裝 Python 接口。c++
QuantLib 使用 swig 來封裝 Python 接口(其餘語言的接口也是用 swig 封裝的),因此,要動手封裝本身的 Python 接口須要瞭解一點 swig 的用法(看這裏,或這裏)。git
swig 封裝 C++ 的流程大致以下:github
.i
),告知 swig 如何封裝 C++ 源代碼;.py
文件(描述封裝好的 Python 接口,包含了若干函數或類的定義),以及一個 .cpp
文件(接口背後的計算引擎將由該文件生成);setup.py
,這將編譯 .cpp
文件,並將編譯獲得的 .so
文件(動態庫)與 .py
文件綁定起來,貫通表面的 Python 接口和背後的 C++ 計算引擎;不一樣版本 QuantLib 的 swig 接口文件能夠在這裏得到。全部接口文件能夠分爲三部分:app
quantlib.i
是最頂端的接口文件,swig 將依據此文件生成接口代碼(.py
和 .cpp
);ql.i
是中間層文件,用來聚集其餘接口文件;bonds.i
、date.i
等等是封裝具體接口的文件。瞭解一點 swig 的原理以後會發現,swig 在封裝好的 Python 接口背後隱藏了一個個真實的 C++ 對象,實際的計算任務、類型檢查和異常處理等等實際上是委託給這些 C++ 對象。svn
所以能夠猜想,將同一段 C++ 代碼封裝成兩個不一樣的 Python 接口,這兩個接口應該能夠混用,由於這僅僅是「同一我的穿了不一樣的衣服」。函數
下面用實驗驗證這種想法。學習
Array
和 Matrix
類以 QuantLib 中的兩個類 Array
和 Matrix
爲例,將它們獨立出來,封裝成名爲 QuantLibEx 的包。具體的接口文件沒有必要本身寫,直接沿用官方發佈的版本(個人名言:學習,從模仿開始)。
在官方發佈的 swig 接口文件中,Array
和 Matrix
對應的文件是 linearalgebra.i
,該文件同時包含(%include
)了 common.i
和 types.i
兩個文件。
將上述三個文件連同 quantlib.i
(重命名爲 quantlibex.i
)和 ql.i
獨立出來,刪除掉一些和封裝 Python 接口無關的代碼,做爲構建 QuantLibEx 的接口文件。
在包含這五個接口文件的目錄下建立一個 QuantLibEx
目錄,而後運行 swig 命令,生成必需的 .py
和 .cpp
文件:
swig -c++ -python -outdir QuantLibEx -o QuantLibEx/qlx_wrap.cpp quantlibex.i
QuantLibEx
目錄下將出現兩個文件:QuantLibEx.py
和 qlx_wrap.cpp
。爲了使 QuantLibEx 成爲一個 Python 包,須要添加一個 __init__.py
文件(內容見附錄)。
QuantLibEx.py
和 qlx_wrap.cpp
準備就緒以後就能夠運行事先編寫好的 setup.py
文件(內容見附錄),編譯 .cpp
文件,並打包進 Python 的系統目錄。
首先,構建(build
命令)QuantLibEx 包:
python3 setup.py build
running build running build_py creating build creating build/lib.linux-x86_64-3.6 creating build/lib.linux-x86_64-3.6/QuantLibEx copying QuantLibEx/__init__.py -> build/lib.linux-x86_64-3.6/QuantLibEx copying QuantLibEx/QuantLibEx.py -> build/lib.linux-x86_64-3.6/QuantLibEx running build_ext building 'QuantLibEx._QuantLibEx' extension creating build/temp.linux-x86_64-3.6 creating build/temp.linux-x86_64-3.6/QuantLibEx x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/usr/include/ql -I/usr/include/python3.6m -c QuantLibEx/qlx_wrap.cpp -o build/temp.linux-x86_64-3.6/QuantLibEx/qlx_wrap.o x86_64-linux-gnu-g++ -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-Bsymbolic-functions -Wl,-z,relro -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 build/temp.linux-x86_64-3.6/QuantLibEx/qlx_wrap.o -L/usr/lib/ -lQuantLib -o build/lib.linux-x86_64-3.6/QuantLibEx/_QuantLibEx.cpython-36m-x86_64-linux-gnu.so
構建成功以後會出現一個 build
目錄,裏面包含了若干文件,包括已經構建好的 QuantLibEx 包。而後,進入安裝(install
命令)環節,打包進 Python 的系統目錄(須要 sudo 權限)。
sudo python3 setup.py install
running install running build running build_py running build_ext running install_lib copying build/lib.linux-x86_64-3.6/QuantLibEx/QuantLibEx.py -> /usr/local/lib/python3.6/dist-packages/QuantLibEx copying build/lib.linux-x86_64-3.6/QuantLibEx/_QuantLibEx.cpython-36m-x86_64-linux-gnu.so -> /usr/local/lib/python3.6/dist-packages/QuantLibEx byte-compiling /usr/local/lib/python3.6/dist-packages/QuantLibEx/QuantLibEx.py to QuantLibEx.cpython-36.pyc running install_egg_info Writing /usr/local/lib/python3.6/dist-packages/QuantLibEx-0.1.egg-info
運行 pip3 list
就能夠看到 QuantLibEx 了。
... QuantLib 1.17 QuantLibEx 0.1 ...
下面簡單驗證一下 QuantLibEx(基於 QuantLib-1.15)和官方包(基於 QuantLib-1.17)是否能夠混合使用:
import QuantLib as ql import QuantLibEx as qlx array = ql.Array(5,0.2) print(type(array)) print(array) arrayX = qlx.Array(5,0.3) print(type(arrayX)) print(arrayX) print(array + arrayX)
<class 'QuantLib.QuantLib.Array'> [ 0.2; 0.2; 0.2; 0.2; 0.2 ] <class 'QuantLibEx.QuantLibEx.Array'> [ 0.3; 0.3; 0.3; 0.3; 0.3 ] [ 0.5; 0.5; 0.5; 0.5; 0.5 ]
更復雜一點的例子——二維插值:
xVec = [float(i) for i in range(10)] yVec = [float(i) for i in range(10)] m = ql.Matrix(len(xVec), len(yVec)) mX = qlx.Matrix(len(xVec), len(yVec)) for rowIt in range(len(xVec)): for colIt in range(len(yVec)): m[rowIt][colIt] = scipy.sin(xVec[rowIt]) + scipy.sin(yVec[colIt]) mX[rowIt][colIt] = scipy.sin(xVec[rowIt]) + scipy.sin(yVec[colIt]) print(type(m)) print(m) print(type(mX)) print(mX) bicubIntp = ql.BicubicSpline( xVec, yVec, m) bicubIntpX = ql.BicubicSpline( xVec, yVec, mX) x = 0.5 y = 4.5 print("Analytical Value: ", scipy.sin(x) + scipy.sin(y)) print("Bicubic Value(base on ql): ", bicubIntp(x, y)) print("Bicubic Value(base on qlx): ", bicubIntpX(x, y))
<class 'QuantLib.QuantLib.Matrix'> | 0 0.841471 0.909297 0.14112 -0.756802 -0.958924 -0.279415 0.656987 0.989358 0.412118 | | 0.841471 1.68294 1.75077 0.982591 0.0846685 -0.117453 0.562055 1.49846 1.83083 1.25359 | | 0.909297 1.75077 1.81859 1.05042 0.152495 -0.0496268 0.629882 1.56628 1.89866 1.32142 | | 0.14112 0.982591 1.05042 0.28224 -0.615682 -0.817804 -0.138295 0.798107 1.13048 0.553238 | | -0.756802 0.0846685 0.152495 -0.615682 -1.5136 -1.71573 -1.03622 -0.0998159 0.232556 -0.344684 | | -0.958924 -0.117453 -0.0496268 -0.817804 -1.71573 -1.91785 -1.23834 -0.301938 0.030434 -0.546806 | | -0.279415 0.562055 0.629882 -0.138295 -1.03622 -1.23834 -0.558831 0.377571 0.709943 0.132703 | | 0.656987 1.49846 1.56628 0.798107 -0.0998159 -0.301938 0.377571 1.31397 1.64634 1.06911 | | 0.989358 1.83083 1.89866 1.13048 0.232556 0.030434 0.709943 1.64634 1.97872 1.40148 | | 0.412118 1.25359 1.32142 0.553238 -0.344684 -0.546806 0.132703 1.06911 1.40148 0.824237 | <class 'QuantLibEx.QuantLibEx.Matrix'> | 0 0.841471 0.909297 0.14112 -0.756802 -0.958924 -0.279415 0.656987 0.989358 0.412118 | | 0.841471 1.68294 1.75077 0.982591 0.0846685 -0.117453 0.562055 1.49846 1.83083 1.25359 | | 0.909297 1.75077 1.81859 1.05042 0.152495 -0.0496268 0.629882 1.56628 1.89866 1.32142 | | 0.14112 0.982591 1.05042 0.28224 -0.615682 -0.817804 -0.138295 0.798107 1.13048 0.553238 | | -0.756802 0.0846685 0.152495 -0.615682 -1.5136 -1.71573 -1.03622 -0.0998159 0.232556 -0.344684 | | -0.958924 -0.117453 -0.0496268 -0.817804 -1.71573 -1.91785 -1.23834 -0.301938 0.030434 -0.546806 | | -0.279415 0.562055 0.629882 -0.138295 -1.03622 -1.23834 -0.558831 0.377571 0.709943 0.132703 | | 0.656987 1.49846 1.56628 0.798107 -0.0998159 -0.301938 0.377571 1.31397 1.64634 1.06911 | | 0.989358 1.83083 1.89866 1.13048 0.232556 0.030434 0.709943 1.64634 1.97872 1.40148 | | 0.412118 1.25359 1.32142 0.553238 -0.344684 -0.546806 0.132703 1.06911 1.40148 0.824237 | Analytical Value: -0.498104579060894 Bicubic Value(base on ql): -0.49656170664824184 Bicubic Value(base on qlx): -0.49656170664824184
到目前爲止,一切都能按照預期運行,自定義的封裝確實可以和官方發佈的包混合使用。不過,類型斷定有些詭異:
b = array + arrayX c = arrayX + array print(type(b)) print(type(c))
<class 'QuantLibEx.QuantLibEx.Array'> <class 'QuantLibEx.QuantLibEx.Array'>
爲何 b
和 c
都被斷定爲 QuantLibEx 中的 Array
?
setup.py
和 __init__.py
quantlibex.i
%module QuantLibEx %include exception.i %exception { try { $action } catch (std::out_of_range& e) { SWIG_exception(SWIG_IndexError,const_cast<char*>(e.what())); } catch (std::exception& e) { SWIG_exception(SWIG_RuntimeError,const_cast<char*>(e.what())); } catch (...) { SWIG_exception(SWIG_UnknownError,"unknown error"); } } //#if defined(SWIGPYTHON) %{ #include <ql/version.hpp> const int __hexversion__ = QL_HEX_VERSION; const char* __version__ = QL_VERSION; %} const int __hexversion__; %immutable; const char* __version__; %mutable; //#endif %include ql.i
ql.i
//#if defined(SWIGPYTHON) %{ #ifdef barrier #undef barrier #endif %} //#endif %{ #include <ql/quantlib.hpp> #if QL_HEX_VERSION < 0x011400f0 #error using an old version of QuantLib, please update #endif #ifdef BOOST_MSVC #ifdef QL_ENABLE_THREAD_SAFE_OBSERVER_PATTERN #define BOOST_LIB_NAME boost_thread #include <boost/config/auto_link.hpp> #undef BOOST_LIB_NAME #define BOOST_LIB_NAME boost_system #include <boost/config/auto_link.hpp> #undef BOOST_LIB_NAME #endif #endif // add here SWIG version check %} //#ifdef SWIGPYTHON %{ #if PY_VERSION_HEX < 0x02010000 #error Python version 2.1.0 or later is required #endif %} //#endif // common name mappings %include common.i %include linearalgebra.i %include types.i
types.i
#ifndef quantlib_types_i #define quantlib_types_i %include common.i %include std_common.i %{ using QuantLib::Integer; using QuantLib::BigInteger; using QuantLib::Natural; using QuantLib::BigNatural; using QuantLib::Real; using QuantLib::Decimal; using QuantLib::Time; using QuantLib::Rate; using QuantLib::Spread; using QuantLib::DiscountFactor; using QuantLib::Volatility; using QuantLib::Probability; using QuantLib::Size; %} typedef int Integer; typedef long BigInteger; typedef unsigned int Natural; typedef unsigned long BigNatural; typedef double Real; typedef Real Decimal; typedef Real Time; typedef Real Rate; typedef Real Spread; typedef Real DiscountFactor; typedef Real Volatility; typedef Real Probability; //#if defined(SWIGPYTHON) // needed for those using SWIG 1.3.21 in order to compile with VC++6 %typecheck(SWIG_TYPECHECK_INTEGER) std::size_t { $1 = (PyInt_Check($input) || PyLong_Check($input)) ? 1 : 0; } //#endif typedef std::size_t Size; #endif
common.i
#ifndef quantlib_common_i #define quantlib_common_i %include stl.i %include exception.i %define QL_TYPECHECK_BOOL 7210 %enddef %{ // This is necessary to avoid compile failures on // GCC 4 // see http://svn.boost.org/trac/boost/ticket/1793 #if defined(NDEBUG) #define BOOST_DISABLE_ASSERTS 1 #endif #include <boost/algorithm/string/case_conv.hpp> %} //#if defined(SWIGPYTHON) %typemap(in) boost::optional<bool> %{ if($input == Py_None) $1 = boost::none; else if ($input == Py_True) $1 = true; else $1 = false; %} %typecheck (QL_TYPECHECK_BOOL) boost::optional<bool> { if (PyBool_Check($input) || Py_None == $input) $1 = 1; else $1 = 0; } //#endif %{ // generally useful classes using QuantLib::Error; using QuantLib::Handle; using QuantLib::RelinkableHandle; %} namespace boost { template <class T> class shared_ptr { public: T* operator->(); //#if defined(SWIGPYTHON) %extend { bool __nonzero__() { return !!(*self); } bool __bool__() { return !!(*self); } } //#endif }; } template <class T> class Handle { public: Handle(const boost::shared_ptr<T>& = boost::shared_ptr<T>()); boost::shared_ptr<T> operator->(); //#if defined(SWIGPYTHON) %extend { bool __nonzero__() { return !self->empty(); } bool __bool__() { return !self->empty(); } } //#endif }; template <class T> class RelinkableHandle : public Handle<T> { public: RelinkableHandle(const boost::shared_ptr<T>& = boost::shared_ptr<T>()); void linkTo(const boost::shared_ptr<T>&); }; %define swigr_list_converter(ContainerRType, ContainerCType, ElemCType) %enddef %define deprecate_feature(OldName, NewName) //#if defined(SWIGPYTHON) %pythoncode %{ def OldName(*args, **kwargs): from warnings import warn warn('%s is deprecated; use %s' % (OldName.__name__, NewName.__name__)) return NewName(*args, **kwargs) %} //#endif %enddef #endif
linearalgebra.i
#ifndef quantlib_linear_algebra_i #define quantlib_linear_algebra_i %include common.i %include types.i %include stl.i %{ using QuantLib::Array; using QuantLib::Matrix; %} %define QL_TYPECHECK_ARRAY 4210 %enddef %define QL_TYPECHECK_MATRIX 4220 %enddef //#if defined(SWIGPYTHON) %{ bool extractArray(PyObject* source, Array* target) { if (PyTuple_Check(source) || PyList_Check(source)) { Size size = (PyTuple_Check(source) ? PyTuple_Size(source) : PyList_Size(source)); *target = Array(size); for (Size i=0; i<size; i++) { PyObject* o = PySequence_GetItem(source,i); if (PyFloat_Check(o)) { (*target)[i] = PyFloat_AsDouble(o); Py_DECREF(o); } else if (PyInt_Check(o)) { (*target)[i] = Real(PyInt_AsLong(o)); Py_DECREF(o); } else { Py_DECREF(o); return false; } } return true; } else { return false; } } %} %typemap(in) Array (Array* v) { if (extractArray($input,&$1)) { ; } else { SWIG_ConvertPtr($input,(void **) &v, $&1_descriptor,1); $1 = *v; } }; %typemap(in) const Array& (Array temp) { if (extractArray($input,&temp)) { $1 = &temp; } else { SWIG_ConvertPtr($input,(void **) &$1,$1_descriptor,1); } }; %typecheck(QL_TYPECHECK_ARRAY) Array { /* native sequence? */ if (PyTuple_Check($input) || PyList_Check($input)) { Size size = PySequence_Size($input); if (size == 0) { $1 = 1; } else { PyObject* o = PySequence_GetItem($input,0); if (PyNumber_Check(o)) $1 = 1; else $1 = 0; Py_DECREF(o); } } else { /* wrapped Array? */ Array* v; if (SWIG_ConvertPtr($input,(void **) &v, $&1_descriptor,0) != -1) $1 = 1; else $1 = 0; } } %typecheck(QL_TYPECHECK_ARRAY) const Array & { /* native sequence? */ if (PyTuple_Check($input) || PyList_Check($input)) { Size size = PySequence_Size($input); if (size == 0) { $1 = 1; } else { PyObject* o = PySequence_GetItem($input,0); if (PyNumber_Check(o)) $1 = 1; else $1 = 0; Py_DECREF(o); } } else { /* wrapped Array? */ Array* v; if (SWIG_ConvertPtr($input,(void **) &v, $1_descriptor,0) != -1) $1 = 1; else $1 = 0; } } %typemap(in) Matrix (Matrix* m) { if (PyTuple_Check($input) || PyList_Check($input)) { Size rows, cols; rows = (PyTuple_Check($input) ? PyTuple_Size($input) : PyList_Size($input)); if (rows > 0) { // look ahead PyObject* o = PySequence_GetItem($input,0); if (PyTuple_Check(o) || PyList_Check(o)) { cols = (PyTuple_Check(o) ? PyTuple_Size(o) : PyList_Size(o)); Py_DECREF(o); } else { PyErr_SetString(PyExc_TypeError, "Matrix expected"); Py_DECREF(o); return NULL; } } else { cols = 0; } $1 = Matrix(rows,cols); for (Size i=0; i<rows; i++) { PyObject* o = PySequence_GetItem($input,i); if (PyTuple_Check(o) || PyList_Check(o)) { Size items = (PyTuple_Check(o) ? PyTuple_Size(o) : PyList_Size(o)); if (items != cols) { PyErr_SetString(PyExc_TypeError, "Matrix must have equal-length rows"); Py_DECREF(o); return NULL; } for (Size j=0; j<cols; j++) { PyObject* d = PySequence_GetItem(o,j); if (PyFloat_Check(d)) { $1[i][j] = PyFloat_AsDouble(d); Py_DECREF(d); } else if (PyInt_Check(d)) { $1[i][j] = Real(PyInt_AsLong(d)); Py_DECREF(d); } else { PyErr_SetString(PyExc_TypeError,"doubles expected"); Py_DECREF(d); Py_DECREF(o); return NULL; } } Py_DECREF(o); } else { PyErr_SetString(PyExc_TypeError, "Matrix expected"); Py_DECREF(o); return NULL; } } } else { SWIG_ConvertPtr($input,(void **) &m,$&1_descriptor,1); $1 = *m; } }; %typemap(in) const Matrix & (Matrix temp) { if (PyTuple_Check($input) || PyList_Check($input)) { Size rows, cols; rows = (PyTuple_Check($input) ? PyTuple_Size($input) : PyList_Size($input)); if (rows > 0) { // look ahead PyObject* o = PySequence_GetItem($input,0); if (PyTuple_Check(o) || PyList_Check(o)) { cols = (PyTuple_Check(o) ? PyTuple_Size(o) : PyList_Size(o)); Py_DECREF(o); } else { PyErr_SetString(PyExc_TypeError, "Matrix expected"); Py_DECREF(o); return NULL; } } else { cols = 0; } temp = Matrix(rows,cols); for (Size i=0; i<rows; i++) { PyObject* o = PySequence_GetItem($input,i); if (PyTuple_Check(o) || PyList_Check(o)) { Size items = (PyTuple_Check(o) ? PyTuple_Size(o) : PyList_Size(o)); if (items != cols) { PyErr_SetString(PyExc_TypeError, "Matrix must have equal-length rows"); Py_DECREF(o); return NULL; } for (Size j=0; j<cols; j++) { PyObject* d = PySequence_GetItem(o,j); if (PyFloat_Check(d)) { temp[i][j] = PyFloat_AsDouble(d); Py_DECREF(d); } else if (PyInt_Check(d)) { temp[i][j] = Real(PyInt_AsLong(d)); Py_DECREF(d); } else { PyErr_SetString(PyExc_TypeError,"doubles expected"); Py_DECREF(d); Py_DECREF(o); return NULL; } } Py_DECREF(o); } else { PyErr_SetString(PyExc_TypeError, "Matrix expected"); Py_DECREF(o); return NULL; } } $1 = &temp; } else { SWIG_ConvertPtr($input,(void **) &$1,$1_descriptor,1); } }; %typecheck(QL_TYPECHECK_MATRIX) Matrix { /* native sequence? */ if (PyTuple_Check($input) || PyList_Check($input)) { $1 = 1; /* wrapped Matrix? */ } else { Matrix* m; if (SWIG_ConvertPtr($input,(void **) &m, $&1_descriptor,0) != -1) $1 = 1; else $1 = 0; } } %typecheck(QL_TYPECHECK_MATRIX) const Matrix & { /* native sequence? */ if (PyTuple_Check($input) || PyList_Check($input)) { $1 = 1; /* wrapped Matrix? */ } else { Matrix* m; if (SWIG_ConvertPtr($input,(void **) &m, $1_descriptor,0) != -1) $1 = 1; else $1 = 0; } } //#endif class Array { //#if defined(SWIGPYTHON) || defined(SWIGRUBY) %rename(__len__) size; //#endif public: Array(); Array(Size n, Real fill = 0.0); Array(const Array&); Size size() const; %extend { std::string __str__() { std::ostringstream out; out << *self; return out.str(); } //#if defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGR) Array __add__(const Array& a) { return Array(*self+a); } Array __sub__(const Array& a) { return Array(*self-a); } Array __mul__(Real a) { return Array(*self*a); } Real __mul__(const Array& a) { return QuantLib::DotProduct(*self,a); } Array __mul__(const Matrix& a) { return *self*a; } Array __div__(Real a) { return Array(*self/a); } //#endif //#if defined(SWIGPYTHON) Array __rmul__(Real a) { return Array(*self*a); } Array __getslice__(Integer i, Integer j) { Integer size_ = static_cast<Integer>(self->size()); if (i<0) i = size_+i; if (j<0) j = size_+j; i = std::max(0,i); j = std::min(size_,j); Array tmp(j-i); std::copy(self->begin()+i,self->begin()+j,tmp.begin()); return tmp; } void __setslice__(Integer i, Integer j, const Array& rhs) { Integer size_ = static_cast<Integer>(self->size()); if (i<0) i = size_+i; if (j<0) j = size_+j; i = std::max(0,i); j = std::min(size_,j); QL_ENSURE(static_cast<Integer>(rhs.size()) == j-i, "arrays are not resizable"); std::copy(rhs.begin(),rhs.end(),self->begin()+i); } bool __nonzero__() { return (self->size() != 0); } bool __bool__() { return (self->size() != 0); } //#endif //#if defined(SWIGPYTHON) || defined(SWIGRUBY) Real __getitem__(Integer i) { Integer size_ = static_cast<Integer>(self->size()); if (i>=0 && i<size_) { return (*self)[i]; } else if (i<0 && -i<=size_) { return (*self)[size_+i]; } else { throw std::out_of_range("array index out of range"); } } void __setitem__(Integer i, Real x) { Integer size_ = static_cast<Integer>(self->size()); if (i>=0 && i<size_) { (*self)[i] = x; } else if (i<0 && -i<=size_) { (*self)[size_+i] = x; } else { throw std::out_of_range("array index out of range"); } } //#endif } }; // 2-D view %{ typedef QuantLib::LexicographicalView<Array::iterator> DefaultLexicographicalView; typedef QuantLib::LexicographicalView<Array::iterator>::y_iterator DefaultLexicographicalViewColumn; %} //#if defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGR) class DefaultLexicographicalViewColumn { private: // access control - no constructor exported DefaultLexicographicalViewColumn(); public: %extend { Real __getitem__(Size i) { return (*self)[i]; } void __setitem__(Size i, Real x) { (*self)[i] = x; } } }; //#endif %rename(LexicographicalView) DefaultLexicographicalView; class DefaultLexicographicalView { public: Size xSize() const; Size ySize() const; %extend { DefaultLexicographicalView(Array& a, Size xSize) { return new DefaultLexicographicalView(a.begin(),a.end(),xSize); } std::string __str__() { std::ostringstream s; for (Size j=0; j<self->ySize(); j++) { s << "\n"; for (Size i=0; i<self->xSize(); i++) { if (i != 0) s << ","; Array::value_type value = (*self)[i][j]; s << value; } } s << "\n"; return s.str(); } //#if defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGR) DefaultLexicographicalViewColumn __getitem__(Size i) { return (*self)[i]; } //#endif } }; %{ typedef QuantLib::Matrix::row_iterator MatrixRow; using QuantLib::outerProduct; using QuantLib::transpose; using QuantLib::SVD; %} //#if defined(SWIGPYTHON) || defined(SWIGRUBY) class MatrixRow { private: MatrixRow(); public: %extend { Real __getitem__(Size i) { return (*self)[i]; } void __setitem__(Size i, Real x) { (*self)[i] = x; } } }; //#endif class Matrix { public: Matrix(); Matrix(Size rows, Size columns, Real fill = 0.0); Matrix(const Matrix&); Size rows() const; Size columns() const; %extend { std::string __str__() { std::ostringstream out; out << *self; return out.str(); } //#if defined(SWIGPYTHON) || defined(SWIGRUBY) Matrix __add__(const Matrix& m) { return *self+m; } Matrix __sub__(const Matrix& m) { return *self-m; } Matrix __mul__(Real x) { return *self*x; } Array __mul__(const Array& x) { return *self*x; } Matrix __mul__(const Matrix& x) { return *self*x; } Matrix __div__(Real x) { return *self/x; } //#endif //#if defined(SWIGPYTHON) || defined(SWIGRUBY) MatrixRow __getitem__(Size i) { return (*self)[i]; } //#endif //#if defined(SWIGPYTHON) Matrix __rmul__(Real x) { return x*(*self); } Array __rmul__(const Array& x) { return x*(*self); } Matrix __rmul__(const Matrix& x) { return x*(*self); } //#endif } }; // functions %{ using QuantLib::pseudoSqrt; using QuantLib::SalvagingAlgorithm; %} struct SalvagingAlgorithm { //#if defined(SWIGPYTHON) %rename(NoAlgorithm) None; //#endif enum Type { None, Spectral }; }; Matrix transpose(const Matrix& m); Matrix outerProduct(const Array& v1, const Array& v2); Matrix pseudoSqrt(const Matrix& m, SalvagingAlgorithm::Type a); class SVD { public: SVD(const Matrix&); const Matrix& U() const; const Matrix& V() const; Matrix S() const; const Array& singularValues() const; }; #endif
setup.py
""" setup.py file for QuantLibEx """ from distutils.core import setup, Extension qlx_module = Extension( name='QuantLibEx._QuantLibEx', sources=['QuantLibEx/qlx_wrap.cpp'], include_dirs=['/usr/include/ql'], # QuantLib 頭文件所在的目錄 library_dirs=['/usr/lib/'], # QuantLib 庫所在的目錄 libraries=['QuantLib'] # QuantLib 庫的名字 ) setup( name = 'QuantLibEx', version = '0.1', author = "xrl", description = "Python bindings for the QuantLibEx library", ext_modules = [qlx_module], py_modules = ['QuantLibEx.__init__','QuantLibEx.QuantLibEx'])
__init__.py
import sys if sys.version_info.major >= 3: from .QuantLibEx import * from .QuantLibEx import _QuantLibEx else: from QuantLibEx import * from QuantLibEx import _QuantLibEx del sys __author__ = 'xrl' if hasattr(_QuantLibEx,'__version__'): __version__ = _QuantLibEx.__version__ elif hasattr(_QuantLibEx.cvar,'__version__'): __version__ = _QuantLibEx.cvar.__version__ else: print('Could not find __version__ attribute') if hasattr(_QuantLibEx,'__hexversion__'): __hexversion__ = _QuantLibEx.__hexversion__ elif hasattr(_QuantLibEx.cvar,'__hexversion__'): __hexversion__ = _QuantLibEx.cvar.__hexversion__ else: print('Could not find __hexversion__ attribute') __license__ = """ QuantLibEx ... """