Skip to content

Commit

Permalink
Fix Array operations (#663)
Browse files Browse the repository at this point in the history
  • Loading branch information
lballabio committed Jul 26, 2024
2 parents a65a11e + 0c41f14 commit 43a400b
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 38 deletions.
20 changes: 10 additions & 10 deletions Python/test/test_fdm.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ def test1dMesher(self):
self.assertAlmostEqual(m.location(0), 0.0, 14)
self.assertAlmostEqual(m.location(9), 1.0, 14)

p = list(x for x in m.locations() if ql.close_enough(x, 0.5))
p = [x for x in m.locations() if ql.close_enough(x, 0.5)]
self.assertEqual(len(p), 1)
p = list(x for x in m.locations() if ql.close_enough(x, 0.75))
p = [x for x in m.locations() if ql.close_enough(x, 0.75)]
self.assertEqual(len(p), 0)

m = ql.Predefined1dMesher([0,2,4])
Expand Down Expand Up @@ -111,10 +111,10 @@ def testFdmMesherComposite(self):
locations = m.locations(0)
self.assertEqual(len(locations), 6)

self.assertEqual(list(map(lambda x: int(x+0.5), locations)), [0, 1, 0, 1, 0, 1])
self.assertEqual(list(map(round, locations)), [0, 1, 0, 1, 0, 1])

locations = m.locations(1)
self.assertEqual(list(map(lambda x: int(x+0.5), locations)), [0, 0, 1, 1, 2, 2])
self.assertEqual(list(map(round, locations)), [0, 0, 1, 1, 2, 2])

def testFdmLinearOpComposite(self):
"""Testing linear operator composites"""
Expand Down Expand Up @@ -163,16 +163,16 @@ def preconditioner(self, r, s):
self.assertAlmostEqual(foo.t2, 2.0, 14)

r = ql.Array([1,2,3,4])
self.assertEqual(list(c.apply(r)), list(2*r))
self.assertEqual(list(c.apply_mixed(r)), list(3*r))
self.assertEqual(list(c.apply_direction(7, r)), list(7*r))
self.assertEqual(c.apply(r), 2*r)
self.assertEqual(c.apply_mixed(r), 3*r)
self.assertEqual(c.apply_direction(7, r), 7*r)

s = list(c.solve_splitting(7, r, 0.5))
s = c.solve_splitting(7, r, 0.5)
self.assertEqual(len(s), len(r))
for i, x in enumerate(s):
self.assertAlmostEqual(x, 3.5*r[i], 14)

self.assertEqual(list(c.preconditioner(r, 4)), list(4*r))
self.assertEqual(c.preconditioner(r, 4), 4*r)

class Bar:
@classmethod
Expand Down Expand Up @@ -224,7 +224,7 @@ def testFdmBlackScholesOp(self):

op.setTime(0, 0.1)

c = list(map(lambda x: payoff(math.exp(x)), mesher.locations(0)))
c = [payoff(math.exp(x)) for x in mesher.locations(0)]
p = op.apply(c)

e = [ 0.0, 0.0, 0.0, 0.0, 0.0,
Expand Down
35 changes: 35 additions & 0 deletions Python/test/test_linear_algebra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import QuantLib as ql
import unittest


class ArrayTest(unittest.TestCase):
def test_math(self):
a = ql.Array([1, 2, 3])
b = ql.Array([4, 5, 6])
self.assertEqual(-a, ql.Array([-1, -2, -3]))
self.assertEqual(a + 1, ql.Array([2, 3, 4]))
self.assertEqual(a + b, ql.Array([5, 7, 9]))
self.assertEqual(b - 1, ql.Array([3, 4, 5]))
self.assertEqual(b - a, ql.Array([3, 3, 3]))
self.assertEqual(a * 2, ql.Array([2, 4, 6]))
self.assertEqual(3 * a, ql.Array([3, 6, 9]))
self.assertEqual(a * b, ql.Array([4, 10, 18]))
self.assertEqual(
a * ql.Matrix([[1, 2], [3, 4], [5, 6]]),
ql.Array([22, 28])
)
self.assertEqual(b / 2, ql.Array([2, 2.5, 3]))
self.assertEqual(b / a, ql.Array([4, 2.5, 2]))
self.assertEqual(a @ b, 32)

def test_compare(self):
for v1 in ([1, 2], [1, 2, 3], [2, 3, 4]):
for v2 in ([1, 2], [1, 2, 3], [2, 3, 4]):
self.assertEqual(ql.Array(v1) == ql.Array(v2), v1 == v2)
self.assertEqual(ql.Array(v1) != ql.Array(v2), v1 != v2)


if __name__ == "__main__":
print("testing QuantLib", ql.__version__)
unittest.main(verbosity=2)

62 changes: 34 additions & 28 deletions SWIG/linearalgebra.i
Original file line number Diff line number Diff line change
Expand Up @@ -326,21 +326,6 @@ function(x,y) plot(as.data.frame(x)))
%}
#endif

#if defined(SWIGR)
%Rruntime %{
setMethod("+", c("_p_Array", "_p_Array"),
function(e1,e2) Array___add__(e1,e2))
setMethod("-", c("_p_Array", "_p_Array"),
function(e1,e2) Array___sub__(e1,e2))
setMethod("*", c("_p_Array", "_p_Array"),
function(e1,e2) Array___mul__(e1,e2))
setMethod("*", c("_p_Array", "numeric"),
function(e1,e2) Array___mul__(e1,e2))
setMethod("/", c("_p_Array", "numeric"),
function(e1,e2) Array___div__(e1,e2))
%}
#endif


#if defined(SWIGCSHARP)
%rename(QlArray) Array;
Expand All @@ -360,30 +345,53 @@ class Array {
out << *self;
return out.str();
}
#if defined(SWIGPYTHON) || defined(SWIGJAVA)
bool operator==(const Array& other) {
return (*self) == other;
}
bool operator!=(const Array& other) {
return (*self) != other;
}
#endif
#if defined(SWIGPYTHON) || defined(SWIGR)
Array __add__(const Array& a) {
return Array(*self+a);
Array operator-() {
return -*self;
}
Array __sub__(const Array& a) {
return Array(*self-a);
Array operator+(Real a) {
return *self+a;
}
Array __mul__(Real a) {
return Array(*self*a);
Array operator+(const Array& a) {
return *self+a;
}
Real __mul__(const Array& a) {
return QuantLib::DotProduct(*self,a);
Array operator-(Real a) {
return *self-a;
}
Array __mul__(const Matrix& a) {
Array operator-(const Array& a) {
return *self-a;
}
Array operator*(Real a) {
return *self*a;
}
Array operator*(const Array& a) {
return *self*a;
}
Array operator*(const Matrix& a) {
return *self*a;
}
Array __div__(Real a) {
return Array(*self/a);
Array operator/(Real a) {
return *self/a;
}
Array operator/(const Array& a) {
return *self/a;
}
#endif
#if defined(SWIGPYTHON)
Array __rmul__(Real a) {
return Array(*self*a);
}
Real __matmul__(const Array& a) {
return QuantLib::DotProduct(*self,a);
}
Array __getslice__(Integer i, Integer j) {
Integer size_ = static_cast<Integer>(self->size());
if (i<0)
Expand Down Expand Up @@ -411,8 +419,6 @@ class Array {
bool __bool__() {
return (self->size() != 0);
}
#endif
#if defined(SWIGPYTHON)
Real __getitem__(Integer i) {
Integer size_ = static_cast<Integer>(self->size());
if (i>=0 && i<size_) {
Expand Down

0 comments on commit 43a400b

Please sign in to comment.