From 1db8c8a1fa2ecb90236d1b27dbc9805c448869e2 Mon Sep 17 00:00:00 2001 From: Guillaume Horel Date: Wed, 1 Feb 2023 12:52:40 -0500 Subject: take advantage of fam --- pyisda/credit_index.pyx | 7 +--- pyisda/curve.pxd | 4 +- pyisda/curve.pyx | 106 ++++++++++++++++++------------------------------ 3 files changed, 44 insertions(+), 73 deletions(-) diff --git a/pyisda/credit_index.pyx b/pyisda/credit_index.pyx index cfc0b2e..5797f45 100644 --- a/pyisda/credit_index.pyx +++ b/pyisda/credit_index.pyx @@ -53,7 +53,6 @@ cdef CurveList_copy(CurveList orig, CurveList copy): new_buf = malloc(size) memcpy(new_buf, buf, size) curve = new_buf - curve.fArray = (new_buf + sizeof(TCurve)) cn = CurveName(new_buf + offset) copy._curves[p.second] = shared_ptr[char](new_buf, char_free) copy.names[cn] = p.second @@ -611,7 +610,6 @@ cdef class CreditIndex(CurveList): memcpy(new_buf, buf, buf_size) sc_orig = buf sc_copy = new_buf - sc_copy.fArray = (new_buf + sizeof(TCurve)) tweak_curve(sc_orig, sc_copy, epsilon, mask) self._curves[i].reset(new_buf, char_free) self.names[CurveName(new_buf + offset)] = i @@ -812,7 +810,6 @@ cdef unsigned long fill_mask(const TDate maturity, const vector[TDate]& maturiti TDate prev_maturity = 0 TDate next_maturity = maturity size_t i - TRatePt* it = sc.fArray unsigned long mask = 0 for i in range(maturities.size()): @@ -824,10 +821,10 @@ cdef unsigned long fill_mask(const TDate maturity, const vector[TDate]& maturiti if i > 0: prev_maturity = maturities[i-1] i = 0 - while it[i].fDate < prev_maturity: + while sc.fArray[i].fDate < prev_maturity: i += 1 i += 1 - while it[i].fDate < maturity: + while sc.fArray[i].fDate < maturity: mask |= 1 << i i += 1 mask |= 1 << i diff --git a/pyisda/curve.pxd b/pyisda/curve.pxd index 5d597b3..696a05d 100644 --- a/pyisda/curve.pxd +++ b/pyisda/curve.pxd @@ -30,11 +30,11 @@ cdef extern from "isda/zerocurve.h" nogil: char* holidayFile) cdef extern from "isda/bastypes.h": ctypedef struct TCurve: - TRatePt* fArray int fNumItems int fDayCountConv TDate fBaseDate double fBasis + TRatePt* fArray # TRatePt[] in C (flexible array member) ctypedef struct TRatePt: TDate fDate @@ -298,7 +298,7 @@ cdef class SpreadCurve(Curve): cdef inline double* recovery_rates_ptr(self) nogil cdef inline char* name(self) nogil -cdef fArray_to_list(TRatePt* fArray, int fNumItems) +cdef fArray_to_list(const TRatePt* fArray, int fNumItems) cdef void tweak_curve(const TCurve* sc, TCurve* sc_tweaked, double epsilon, unsigned long mask) nogil diff --git a/pyisda/curve.pyx b/pyisda/curve.pyx index 182b7a7..b2b9747 100644 --- a/pyisda/curve.pyx +++ b/pyisda/curve.pyx @@ -74,16 +74,16 @@ cdef class Curve(object): bytes r int dst_capacity, compressed_size char* dst - int size = self.buf_size - sizeof(TRatePt*) + int size = self.buf_size if compressed: dst_capacity = LZ4_compressBound(size) dst = malloc(dst_capacity) - compressed_size = LZ4_compress_default(self.buf.get() + sizeof(TRatePt*), dst, size, dst_capacity) + compressed_size = LZ4_compress_default(self.buf.get(), dst, size, dst_capacity) r = dst[:compressed_size] free(dst) else: - r = self.buf.get()[sizeof(TRatePt*):self.buf_size] + r = self.buf.get()[:self.buf_size] return r def __getstate__(self): @@ -102,7 +102,7 @@ cdef class Curve(object): with nogil: while True: curve = realloc(curve, decomp_size) - state_size = LZ4_decompress_safe(src, curve + sizeof(TRatePt*), size, decomp_size) + state_size = LZ4_decompress_safe(src, curve, size, decomp_size) if state_size < 0: retry += 1 if retry == 2: @@ -112,8 +112,7 @@ cdef class Curve(object): decomp_size *= 2 else: break - self.buf_size = state_size + sizeof(TRatePt*) - (curve).fArray = (curve + sizeof(TCurve)) + self.buf_size = state_size self.buf.reset(curve, char_free) @classmethod @@ -141,7 +140,7 @@ cdef class Curve(object): if compressed: while True: curve = realloc(curve, decomp_size) - state_size = LZ4_decompress_safe(src, curve + sizeof(TRatePt*), size, decomp_size) + state_size = LZ4_decompress_safe(src, curve, size, decomp_size) if state_size < 0: retry += 1 if retry == 2: @@ -152,18 +151,17 @@ cdef class Curve(object): else: break else: - curve = malloc(size + sizeof(TRatePt*)) - memcpy(curve + sizeof(TRatePt*), src, size) + curve = malloc(size) + memcpy(curve, src, size) state_size = size - (curve).fArray = (curve + sizeof(TCurve)) - instance.buf_size = state_size + sizeof(TRatePt*) + instance.buf_size = state_size instance.buf.reset(curve, char_free) return instance def __hash__(self): cdef: - size_t curve_size = self.buf_size - sizeof(TRatePt*) - cdef uint64_t r = Hash64((self.buf.get() + sizeof(TRatePt*)), curve_size) + size_t curve_size = self.buf_size + cdef uint64_t r = Hash64(self.buf.get(), curve_size) return r def inspect(self): @@ -188,23 +186,22 @@ cdef class Curve(object): cdef np.ndarray[np.float64_t,ndim=1] h = np.PyArray_EMPTY(1, &n, np.NPY_DOUBLE, 0) cdef np.ndarray[np.int64_t,ndim=1] d = np.PyArray_EMPTY(1, &n, np.NPY_INT64, 0) cdef size_t i - cdef TRatePt* it = curve.fArray cdef double t1, h1, t2, h2 t1 = 0 h1 = 0 cdef int base_date = curve.fBaseDate if forward: for i in range(n): - h2 = it[i].fRate - t2 = (it[i].fDate - base_date)/365. + h2 = curve.fArray[i].fRate + t2 = (curve.fArray[i].fDate - base_date)/365. h[i] = (h2 * t2 - h1 * t1) / (t2 - t1) - d[i] = it[i].fDate - 134774 + d[i] = curve.fArray[i].fDate - 134774 h1 = h2 t1 = t2 else: for i in range(n): - h[i] = it[i].fRate - d[i] = it[i].fDate - 134774 + h[i] = curve.fArray[i].fRate + d[i] = curve.fArray[i].fDate - 134774 if isinstance(self, YieldCurve): name = 'forward_rates' elif isinstance(self, SpreadCurve): @@ -216,9 +213,9 @@ cdef class Curve(object): def __iter__(self): cdef: size_t i = 0 - TRatePt* it = self.get_TCurve().fArray - for i in range(self.get_TCurve().fNumItems): - yield (TDate_to_pydate(it[i].fDate), it[i].fRate) + const TCurve* c = self.get_TCurve() + for i in range(c.fNumItems): + yield (TDate_to_pydate(c.fArray[i].fDate), c.fArray[i].fRate) def __len__(self): return self.get_TCurve().fNumItems @@ -227,7 +224,6 @@ cdef class Curve(object): cdef Curve sc = type(self).__new__(type(self)) cdef char* curve = malloc(self.buf_size) memcpy(curve, self.buf.get(), self.buf_size) - (curve).fArray = (curve + sizeof(TCurve)) sc.buf_size = self.buf_size sc.buf.reset(curve, char_free) memo[id(self)] = sc @@ -310,7 +306,7 @@ cdef class Curve(object): const TCurve* curve = self.get_TCurve() return JpmcdsZeroRate(curve, pydate_to_TDate(d)) -cdef fArray_to_list(TRatePt* fArray, int fNumItems): +cdef fArray_to_list(const TRatePt* fArray, int fNumItems): cdef size_t i cdef list l = [] for i in range(fNumItems): @@ -412,12 +408,8 @@ cdef class YieldCurve(Curve): free(dates) raise ValueError("Curve didn't build") else: - # we copy curve into a continuous buffer self.buf_size = sizeof(TCurve) + curve.fNumItems * sizeof(TRatePt) - buf = malloc(self.buf_size) - memcpy(buf, curve, sizeof(TCurve)) - (buf).fArray = (buf + sizeof(TCurve)) - memcpy(buf + sizeof(TCurve), curve.fArray, curve.fNumItems * sizeof(TRatePt)) + buf = curve self.buf.reset(buf, char_free) free(dates) @@ -427,11 +419,9 @@ cdef class YieldCurve(Curve): """ build a yield curve from a list of discount factors """ cdef YieldCurve yc = YieldCurve.__new__(YieldCurve) yc.buf_size = sizeof(TCurve) + len(dates) * sizeof(TRatePt) - cdef char* buf = malloc(yc.buf_size) - cdef TCurve* curve = buf + cdef TCurve* curve = malloc(yc.buf_size) curve.fBaseDate = pydate_to_TDate(base_date) curve.fNumItems = len(dates) - curve.fArray = (buf + sizeof(TCurve)) curve.fBasis = basis curve.fDayCountConv = dcc(day_count_conv) @@ -441,7 +431,7 @@ cdef class YieldCurve(Curve): JpmcdsDiscountToRateYearFrac(dfs[i], (curve.fArray[i].fDate-curve.fBaseDate)/365., basis, &curve.fArray[i].fRate) - yc.buf.reset(buf, char_free) + yc.buf.reset(curve, char_free) return yc @classmethod @@ -449,11 +439,10 @@ cdef class YieldCurve(Curve): """ build a yield curve from a list of discount factors """ cdef YieldCurve yc = YieldCurve.__new__(YieldCurve) yc.buf_size = sizeof(TCurve) + len(dates) * sizeof(TRatePt) - cdef char* buf = malloc(yc.buf_size) - cdef TCurve* curve = buf + cdef TCurve* curve = malloc(yc.buf_size) + curve.fBaseDate = pydate_to_TDate(base_date) curve.fNumItems = len(dates) - curve.fArray = (buf + sizeof(TCurve)) curve.fBasis = basis curve.fDayCountConv = dcc(day_count_conv) @@ -461,34 +450,26 @@ cdef class YieldCurve(Curve): for i, d in enumerate(dates): curve.fArray[i].fDate = pydate_to_TDate(d) curve.fArray[i].fRate = rates[i] - yc.buf.reset(buf, char_free) + yc.buf.reset(curve, char_free) return yc def bump(self, epsilon): cdef: YieldCurve yc = YieldCurve.__new__(YieldCurve) - char* buf = malloc(self.buf_size) - const TCurve* curve = self.get_TCurve() - TCurve* new_curve = buf - TRatePt *ptr1, *ptr2 - int N = curve.fNumItems + const TCurve* c1 = self.get_TCurve() + TCurve* c2 = malloc(self.buf_size) int i yc.buf_size = self.buf_size - new_curve.fNumItems = N - new_curve.fBaseDate = curve.fBaseDate - new_curve.fBasis = curve.fBasis - new_curve.fArray = (buf + sizeof(TCurve)) - new_curve.fDayCountConv = curve.fDayCountConv - ptr1 = curve.fArray - ptr2 = new_curve.fArray - for i in range(N): - ptr2.fDate = ptr1.fDate - ptr2.fRate = ptr1.fRate + epsilon - preinc(ptr1) - preinc(ptr2) - - yc.buf.reset(buf, char_free) + c2.fNumItems = c1.fNumItems + c2.fBaseDate = c1.fBaseDate + c2.fBasis = c1.fBasis + c2.fDayCountConv = c1.fDayCountConv + for i in range(c1.fNumItems): + c2.fArray[i].fDate = c1.fArray[i].fDate + c2.fArray[i].fRate = c1.fArray[i].fRate + epsilon + + yc.buf.reset(c2, char_free) return yc def discount_factor(self, d2, d1=None): @@ -547,13 +528,11 @@ cdef class YieldCurve(Curve): while curve.fArray[i].fDate < forward_date_c: i += 1 yc.buf_size = sizeof(TCurve) + (n - i) * sizeof(TRatePt) - yc.buf.reset(malloc(yc.buf_size), char_free) - cdef TCurve* forward_curve = yc.buf.get() + cdef TCurve* forward_curve = malloc(yc.buf_size) forward_curve.fNumItems = n - i forward_curve.fDayCountConv = curve.fDayCountConv forward_curve.fBaseDate = forward_date_c forward_curve.fBasis = 1.0 - forward_curve.fArray = (yc.buf.get() + sizeof(TCurve)) cdef double df cdef TRatePt* arr = forward_curve.fArray while i < n: @@ -564,6 +543,7 @@ cdef class YieldCurve(Curve): 1, &arr.fRate) i += 1 preinc(arr) + yc.buf.reset(forward_curve, char_free) return yc @cython.cdivision(True) @@ -735,10 +715,7 @@ cdef class SpreadCurve(Curve): else: self.buf_size = buf_size(curve.fNumItems, ticker_len) buf = malloc(self.buf_size) - memcpy(buf, curve, sizeof(TCurve)) - memcpy(buf + sizeof(TCurve), curve.fArray, curve.fNumItems * sizeof(TRatePt)) - (buf).fArray = (buf + sizeof(TCurve)) - free(curve.fArray) + memcpy(buf, curve, sizeof(TCurve) + curve.fNumItems * sizeof(TRatePt)) free(curve) curve = buf else: @@ -750,7 +727,6 @@ cdef class SpreadCurve(Curve): buf = malloc(self.buf_size) curve = buf curve.fNumItems = n_dates - curve.fArray = (buf + sizeof(TCurve)) curve.fBaseDate = today_c curve.fBasis = CONTINUOUS curve.fDayCountConv = ACT_360 @@ -826,7 +802,6 @@ cdef class SpreadCurve(Curve): cdef char* buf = malloc(self.buf_size) cdef int n = self.get_TCurve().fNumItems memcpy(buf, self.buf.get(), self.buf_size) - (buf).fArray = (buf + sizeof(TCurve)) sc.buf_size = self.buf_size sc.buf.reset(buf, char_free) sc.offset_recovery_rates = sizeof(TCurve) + n * sizeof(TRatePt) @@ -1039,7 +1014,6 @@ cdef void _fill_curve(const TCurve* sc, const TDate* end_dates, int n_dates, cha TDate base_date = sc.fBaseDate double t TCurve* curve = buf - curve.fArray = (buf + sizeof(TCurve)) curve.fNumItems = n_dates curve.fBaseDate = base_date curve.fBasis = CONTINUOUS -- cgit v1.2.3-70-g09d2