From 93be5e47ec745631c4306eaa3b653fe0e64019f2 Mon Sep 17 00:00:00 2001 From: Mayya Bondarevskaya Date: Tue, 28 Feb 2017 15:03:51 +0000 Subject: [PATCH 001/106] added new html_str property to quantity to provide html formatting --- pyqn/quantity.py | 11 +++++++++++ pyqn/tests/test_quantity.py | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/pyqn/quantity.py b/pyqn/quantity.py index 61d38ce..18a4155 100644 --- a/pyqn/quantity.py +++ b/pyqn/quantity.py @@ -327,3 +327,14 @@ def parse(self, s_quantity, name=None, units=None, sd=None, ndp = 0 sd = float(s_sd) * 10**(exp-ndp) return Quantity(name=name, value=value, units=units, sd=sd) + + @property + def html_str(self): + html_chunks = [] + if self.name: + html_chunks.append('{:s} ='.format(self.name)) + html_chunks.append('{:}'.format(self.value)) + if self.sd: + html_chunks.append('± {:}'.format(self.sd)) + html_chunks.append(self.units.html) + return ' '.join(html_chunks) diff --git a/pyqn/tests/test_quantity.py b/pyqn/tests/test_quantity.py index c0111b4..453b169 100644 --- a/pyqn/tests/test_quantity.py +++ b/pyqn/tests/test_quantity.py @@ -76,5 +76,16 @@ def test_quantity_conversion(self): #self.assertAlmostEqual(q2.value,1.2483019242e+21,places=2) pass + def test_quantity_html(self): + q1 = Quantity(name = 'E', value = 1.2, units = 'J') + q2 = Quantity(value = -5, units = 's', sd = 0.3) + q3 = Quantity(value = 30.7, units = 'kg.m2.s-2') + q4 = Quantity(value = 22.4,units = 'm/s') + + self.assertEqual(q1.html_str, 'E = 1.2 J') + self.assertEqual(q2.html_str, '-5 ± 0.3 s') + self.assertEqual(q3.html_str, '30.7 kg m2 s-2') + self.assertEqual(q4.html_str, '22.4 m s-1') + if __name__ == '__main__': unittest.main() \ No newline at end of file From d28840ab7f6a32dc8f1dc16d71d51c13105a328c Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 27 Jun 2017 10:38:08 +0100 Subject: [PATCH 002/106] resolve encoding issues --- pyqn/dimensions.py | 7 +++++-- pyqn/quantity.py | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pyqn/dimensions.py b/pyqn/dimensions.py index 168c250..884e260 100644 --- a/pyqn/dimensions.py +++ b/pyqn/dimensions.py @@ -1,3 +1,6 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + # dimensions.py # A class representing the dimensions of a physical quantity's units, in # terms of powers of length (L), mass (M), time (T), temperature (Theta), @@ -24,7 +27,7 @@ class Dimensions(object): # these are the abbreviations for Length, Mass, Time, Temperature, - # Quantity (amount of substance), Current, and Luminous Intensity: + # Quantity (amount of substance), Current, and Luminous Intensity dim_names = ['L', 'M', 'T', 'Theta', 'Q', 'C', 'I'] dim_desc = ['length', 'mass', 'time', 'temperature', 'amount', 'current', 'luminous intensity'] @@ -104,4 +107,4 @@ def __ne__(self, other): d_voltage = d_energy / d_charge # 1 V = 1 J/C d_magfield_strength = d_voltage * d_time / d_area # 1 T = 1 V.s/m^2 d_magnetic_flux = d_voltage * d_time # 1 Wb = 1 V.s -d_temperature = Dimensions(Theta=1) \ No newline at end of file +d_temperature = Dimensions(Theta=1) diff --git a/pyqn/quantity.py b/pyqn/quantity.py index 18a4155..d6d24b1 100644 --- a/pyqn/quantity.py +++ b/pyqn/quantity.py @@ -1,3 +1,6 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + # quantity.py # A class representing physical quantity, with name, units and uncertainty. # From 016fb3388bc483ccfe51e60d4627dcf9a901e420 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 27 Jun 2017 13:10:33 +0100 Subject: [PATCH 003/106] add basic initialisation of qnArray class --- pyqn/qn_array.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/pyqn/qn_array.py b/pyqn/qn_array.py index a14b43b..8de33b5 100644 --- a/pyqn/qn_array.py +++ b/pyqn/qn_array.py @@ -1,5 +1,6 @@ from .symbol import Symbol import numpy as np +from .quantity import Quantity class qnArrayError(Exception): def __init__(self, error_str): @@ -8,12 +9,25 @@ def __str__(self): return self.error_str class qnArray(Symbol): - def __init__(self, name=None, latex=None, html=None, values=None, - units=None, sd=None, definition=None) + def __init__(self, name=None, latex=None, html=None, values=None, units=None, sd=None, definition=None): Symbol.__init__(self, name, latex, html, definition) - if type(values)==list: - self.values = np.array(values) - elif type(values)==numpy.ndarray: - self.values = values - else: - raise qnArrayError \ No newline at end of file + #if type(values)==list: + # self.values = np.array(values) + #elif type(values)==numpy.ndarray: + # self.values = values + #else: + # raise qnArrayError + self.nparr = np.array([]) + self.units = units + self.values = values + for v in values: + self.nparr = np.append(self.nparr, Quantity(value=v, units = units)) + + def __mul__(self, other): + return self.nparr * other + + def values(self): + return self.values + + def units(self): + return self.units From 8f097a2394ec1dcab1a50fcd9ce280164db14ac7 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 27 Jun 2017 13:11:17 +0100 Subject: [PATCH 004/106] minor qnArray compatibility resolvement --- pyqn/quantity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyqn/quantity.py b/pyqn/quantity.py index d6d24b1..37d0b45 100644 --- a/pyqn/quantity.py +++ b/pyqn/quantity.py @@ -242,7 +242,7 @@ def __mul__(self, other): sd = abs(other) * self.sd return Quantity(value=self.value*other, units=self.unit, sd=sd) else: - if type(other) != Quantity: + if (type(other) is not Quantity) and (type(other) is not qnArray): raise TypeError if other.value is None: raise ValueError From b7f3a36e349b2fe41234dc7d5f555fd97d22c369 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 27 Jun 2017 16:17:58 +0100 Subject: [PATCH 005/106] allow division with qnArray as well --- pyqn/qn_array.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pyqn/qn_array.py b/pyqn/qn_array.py index 8de33b5..b2a954d 100644 --- a/pyqn/qn_array.py +++ b/pyqn/qn_array.py @@ -25,9 +25,5 @@ def __init__(self, name=None, latex=None, html=None, values=None, units=None, sd def __mul__(self, other): return self.nparr * other - - def values(self): - return self.values - - def units(self): - return self.units + def __truediv__(self, other): + return self.nparr / other From 1af4204e8f168e08f27a51ca1d489ae6559d6add Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 27 Jun 2017 16:19:53 +0100 Subject: [PATCH 006/106] add division function to qnArray class --- pyqn/quantity.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyqn/quantity.py b/pyqn/quantity.py index 37d0b45..1e4fbe9 100644 --- a/pyqn/quantity.py +++ b/pyqn/quantity.py @@ -271,8 +271,8 @@ def __truediv__(self, other): sd = abs(other) / self.sd return Quantity(value=self.value/other, units=self.units, sd=sd) else: - if type(other) != Quantity: - raise TypeError + #if type(other) != Quantity: + # raise TypeError if other.value is None: raise ValueError value = self.value / other.value From bf424f9d99df21b987c9e2ebed3891c95432d10c Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 27 Jun 2017 16:26:49 +0100 Subject: [PATCH 007/106] begin testing of qnArray class --- pyqn/tests/test_qn_array.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 pyqn/tests/test_qn_array.py diff --git a/pyqn/tests/test_qn_array.py b/pyqn/tests/test_qn_array.py new file mode 100644 index 0000000..42edb28 --- /dev/null +++ b/pyqn/tests/test_qn_array.py @@ -0,0 +1,12 @@ +import unittest +from ..qn_array import qnArray +from ..quantity import Quantity + +class qnArrayTest(unittest.TestCase): + def test_qnarray_init(self): + qnarr1 = qnArray(values = [1,2,3,4,5], units = 'm') + qnarr2 = qnArray(values = np.array([-5,-10], units = 'J') + + with self.assertRaises(SOMETHINGERROR) as e: + qnarr = qnArray(values = "string") + From 9759a6de1589e1087567adb089aa0e70d57e8923 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 27 Jun 2017 16:39:29 +0100 Subject: [PATCH 008/106] add new error-raising features --- pyqn/qn_array.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pyqn/qn_array.py b/pyqn/qn_array.py index b2a954d..d493041 100644 --- a/pyqn/qn_array.py +++ b/pyqn/qn_array.py @@ -11,12 +11,6 @@ def __str__(self): class qnArray(Symbol): def __init__(self, name=None, latex=None, html=None, values=None, units=None, sd=None, definition=None): Symbol.__init__(self, name, latex, html, definition) - #if type(values)==list: - # self.values = np.array(values) - #elif type(values)==numpy.ndarray: - # self.values = values - #else: - # raise qnArrayError self.nparr = np.array([]) self.units = units self.values = values From fa68171f2196afbaf9e137478603ad830aa327f1 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 27 Jun 2017 16:39:58 +0100 Subject: [PATCH 009/106] add more qnArray initialisation tests --- pyqn/tests/test_qn_array.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/pyqn/tests/test_qn_array.py b/pyqn/tests/test_qn_array.py index 42edb28..2b16153 100644 --- a/pyqn/tests/test_qn_array.py +++ b/pyqn/tests/test_qn_array.py @@ -1,12 +1,27 @@ import unittest from ..qn_array import qnArray from ..quantity import Quantity +import numpy as np class qnArrayTest(unittest.TestCase): - def test_qnarray_init(self): - qnarr1 = qnArray(values = [1,2,3,4,5], units = 'm') - qnarr2 = qnArray(values = np.array([-5,-10], units = 'J') - - with self.assertRaises(SOMETHINGERROR) as e: - qnarr = qnArray(values = "string") - + def test_qnarray_init(self): + qnarr1 = qnArray(values = [1,2,3,4,5], units = 'm') + self.assertEqual(qnarr1.values = [1,2,3,4,5]) + self.assertEqual(qnarr1.units = 'm') + self.assertEqual(qnarr1.nparr = np.array([Quantity(value=1,units='m'), + Quantity(value=2,units='m'), + Quantity(value=3,units='m'), + Quantity(value=4,units='m'), + Quantity(value=5,units='m')]) + + qnarr2 = qnArray(values = np.array([-5,-10], units = 'J') + self.assertEqual(qnarr2.values = [-5,-10]) + self.assertEqual(qnarr2.units = 'J') + self.assertEqual(qnarr2.nparr = np.array([Quantity(value=-5,units='J'), + Quantity(value=-10,units='J')]) + + with self.assertRaises(SOMETHINGERROR) as e1: + qnarr = qnArray(values = "string") + with self.assertRaises(SOMETHINGERROR) as e2: + qnarr = qnArray(values = ["a", "b", "c"]) + From 84d8cebaec41f6255455ac6886b701988dcbe27f Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 28 Jun 2017 12:17:33 +0100 Subject: [PATCH 010/106] add check for arrays of strings as input values --- pyqn/qn_array.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pyqn/qn_array.py b/pyqn/qn_array.py index d493041..8e93e62 100644 --- a/pyqn/qn_array.py +++ b/pyqn/qn_array.py @@ -13,7 +13,14 @@ def __init__(self, name=None, latex=None, html=None, values=None, units=None, sd Symbol.__init__(self, name, latex, html, definition) self.nparr = np.array([]) self.units = units - self.values = values + if len(values) is not 0: + if type(values) is list or type(values) is np.ndarray: + if type(values[0]) is not str: + self.values = values + else: + raise qnArrayError("Values must be numbers") + else: + raise qnArrayError("Values only an array/list of values") for v in values: self.nparr = np.append(self.nparr, Quantity(value=v, units = units)) From d4a999f2d5a22ef355c7eae79bfc9c4bc8762c63 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 28 Jun 2017 12:17:54 +0100 Subject: [PATCH 011/106] add compatibility with qn_array --- pyqn/quantity.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pyqn/quantity.py b/pyqn/quantity.py index 1e4fbe9..d5dbe5e 100644 --- a/pyqn/quantity.py +++ b/pyqn/quantity.py @@ -185,6 +185,12 @@ def draw_from_dist(self, shape=None): ' deviation.'.format(self.name)) return np.random.normal(loc=self.value, scale=self.sd, size=shape) + + def __eq__(self, other): + if (self.value == other.value) and (self.units == other.units): + return True + else: + return False def __add__(self, other): """ From 02298fc03a7a70e7978decb7963c341474638d69 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 28 Jun 2017 12:18:12 +0100 Subject: [PATCH 012/106] add tests --- pyqn/tests/test_qn_array.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/pyqn/tests/test_qn_array.py b/pyqn/tests/test_qn_array.py index 2b16153..5ac9782 100644 --- a/pyqn/tests/test_qn_array.py +++ b/pyqn/tests/test_qn_array.py @@ -1,27 +1,28 @@ import unittest -from ..qn_array import qnArray +from ..qn_array import qnArray, qnArrayError from ..quantity import Quantity import numpy as np class qnArrayTest(unittest.TestCase): def test_qnarray_init(self): - qnarr1 = qnArray(values = [1,2,3,4,5], units = 'm') - self.assertEqual(qnarr1.values = [1,2,3,4,5]) - self.assertEqual(qnarr1.units = 'm') - self.assertEqual(qnarr1.nparr = np.array([Quantity(value=1,units='m'), - Quantity(value=2,units='m'), - Quantity(value=3,units='m'), - Quantity(value=4,units='m'), - Quantity(value=5,units='m')]) + a1 = [1,2,3,4,5] + qnarr1 = qnArray(values = a1, units = 'm') + for i in range(len(a1)): + self.assertEqual(qnarr1.values[i], a1[i]) + self.assertEqual(qnarr1.nparr[i], Quantity(value=a1[i], units='m')) + self.assertEqual(qnarr1.units, 'm') - qnarr2 = qnArray(values = np.array([-5,-10], units = 'J') - self.assertEqual(qnarr2.values = [-5,-10]) - self.assertEqual(qnarr2.units = 'J') - self.assertEqual(qnarr2.nparr = np.array([Quantity(value=-5,units='J'), - Quantity(value=-10,units='J')]) + a2 = [-5,-10] + qnarr2 = qnArray(values = np.array(a2), units = 'J') + for i in range(len(a2)): + self.assertEqual(qnarr2.values[i], a2[i]) + self.assertEqual(qnarr2.nparr[i], Quantity(value=a2[i], units='J')) + self.assertEqual(qnarr2.units, 'J') - with self.assertRaises(SOMETHINGERROR) as e1: + with self.assertRaises(qnArrayError) as e1: qnarr = qnArray(values = "string") - with self.assertRaises(SOMETHINGERROR) as e2: + with self.assertRaises(qnArrayError) as e2: qnarr = qnArray(values = ["a", "b", "c"]) +if __name__ == '__main__': + unittest.main() From 14604519b53e54d2ed1bb038b4a5d4bcf8b27b6e Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 3 Jul 2017 10:34:40 +0100 Subject: [PATCH 013/106] change numpy array from containing Quantity objects to containing an array of values and having a separate Units variable --- pyqn/qn_array.py | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/pyqn/qn_array.py b/pyqn/qn_array.py index 8e93e62..f9577c9 100644 --- a/pyqn/qn_array.py +++ b/pyqn/qn_array.py @@ -1,6 +1,7 @@ from .symbol import Symbol import numpy as np from .quantity import Quantity +from .units import Units class qnArrayError(Exception): def __init__(self, error_str): @@ -9,10 +10,19 @@ def __str__(self): return self.error_str class qnArray(Symbol): - def __init__(self, name=None, latex=None, html=None, values=None, units=None, sd=None, definition=None): + def __init__(self, name=None, latex=None, html=None, values=None, + units=None, sd=None, definition=None): Symbol.__init__(self, name, latex, html, definition) - self.nparr = np.array([]) - self.units = units + + #validates units + if type(units) is str: + self.units = Units(units) + elif type(units) is Units: + self.units = units + else: + raise qnArrayError("Units accepted only in str or Units class form") + + #validates values array if len(values) is not 0: if type(values) is list or type(values) is np.ndarray: if type(values[0]) is not str: @@ -21,10 +31,20 @@ def __init__(self, name=None, latex=None, html=None, values=None, units=None, sd raise qnArrayError("Values must be numbers") else: raise qnArrayError("Values only an array/list of values") - for v in values: - self.nparr = np.append(self.nparr, Quantity(value=v, units = units)) + + if type(values) is list: + self.nparr = np.array(values) + elif type(values) is np.ndarray: + self.nparr = values def __mul__(self, other): - return self.nparr * other + if type(other) is not Quantity: + raise qnArrayError("qnArrays can obly be multiplied by Quantity objects") + return qnArray(values = self.nparr*other.value, units = self.units*other.units) + def __truediv__(self, other): return self.nparr / other + + @property + def units_str(self): + return str(self.units) From d35519522d3ca824f786807e688564f1f57e036e Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 3 Jul 2017 10:35:06 +0100 Subject: [PATCH 014/106] add multiplication test --- pyqn/tests/test_qn_array.py | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/pyqn/tests/test_qn_array.py b/pyqn/tests/test_qn_array.py index 5ac9782..0c96adc 100644 --- a/pyqn/tests/test_qn_array.py +++ b/pyqn/tests/test_qn_array.py @@ -5,24 +5,41 @@ class qnArrayTest(unittest.TestCase): def test_qnarray_init(self): - a1 = [1,2,3,4,5] + a1 = [-1,-2,-3,-4,-5] qnarr1 = qnArray(values = a1, units = 'm') for i in range(len(a1)): self.assertEqual(qnarr1.values[i], a1[i]) - self.assertEqual(qnarr1.nparr[i], Quantity(value=a1[i], units='m')) - self.assertEqual(qnarr1.units, 'm') + self.assertEqual(qnarr1.nparr[i], a1[i]) + self.assertEqual(qnarr1.units_str, 'm') - a2 = [-5,-10] + a2 = [5,10] qnarr2 = qnArray(values = np.array(a2), units = 'J') for i in range(len(a2)): self.assertEqual(qnarr2.values[i], a2[i]) - self.assertEqual(qnarr2.nparr[i], Quantity(value=a2[i], units='J')) - self.assertEqual(qnarr2.units, 'J') + self.assertEqual(qnarr2.nparr[i], a2[i]) + self.assertEqual(qnarr2.units_str, 'J') with self.assertRaises(qnArrayError) as e1: qnarr = qnArray(values = "string") with self.assertRaises(qnArrayError) as e2: qnarr = qnArray(values = ["a", "b", "c"]) + def test_qnarray_mult(self): + a1 = [-1,-2,-3,-4,-5] + qnarr1 = qnArray(values = a1, units = 'm') + q1 = Quantity(value = 2, units = 's') + result1 = qnarr1*q1 + self.assertEqual(result1.units_str, 'm.s') + for i in range(len(a1)): + self.assertEqual(result1.values[i], 2*a1[i]) + + #a2 = [5,10] + #qnarr2 = qnArray(values = np.array(a2), units = 'J') + #q2 = Quantity(value=0.2, units = 'm-1') + #result2 = qnarr2*q2 + #self.assertEqual(result2.units, 'J.m-1') + #for i in range(len(result2)): + # self.assertEqual(result2.values[i], 0.2*a2[i]) + if __name__ == '__main__': unittest.main() From d2f94c99e0a5a87c47507715f4783c9f6143076a Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 3 Jul 2017 11:36:15 +0100 Subject: [PATCH 015/106] add more qnArray multiplication tests --- pyqn/tests/test_qn_array.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pyqn/tests/test_qn_array.py b/pyqn/tests/test_qn_array.py index 0c96adc..def460e 100644 --- a/pyqn/tests/test_qn_array.py +++ b/pyqn/tests/test_qn_array.py @@ -31,15 +31,15 @@ def test_qnarray_mult(self): result1 = qnarr1*q1 self.assertEqual(result1.units_str, 'm.s') for i in range(len(a1)): - self.assertEqual(result1.values[i], 2*a1[i]) + self.assertEqual(result1.nparr[i], 2*a1[i]) - #a2 = [5,10] - #qnarr2 = qnArray(values = np.array(a2), units = 'J') - #q2 = Quantity(value=0.2, units = 'm-1') - #result2 = qnarr2*q2 - #self.assertEqual(result2.units, 'J.m-1') - #for i in range(len(result2)): - # self.assertEqual(result2.values[i], 0.2*a2[i]) + a2 = [5,10] + qnarr2 = qnArray(values = np.array(a2), units = 'J') + q2 = Quantity(value=0.2, units = 'm-1') + result2 = qnarr2*q2 + self.assertEqual(result2.units_str, 'J.m-1') + for i in range(len(a2)): + self.assertEqual(result2.nparr[i], 0.2*a2[i]) if __name__ == '__main__': unittest.main() From bb32317de47b1d7b7d3cd2d1d6d945c7c8cffdb7 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 3 Jul 2017 11:39:40 +0100 Subject: [PATCH 016/106] add test for other object type to be only Quantity --- pyqn/qn_array.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyqn/qn_array.py b/pyqn/qn_array.py index f9577c9..823fbab 100644 --- a/pyqn/qn_array.py +++ b/pyqn/qn_array.py @@ -39,11 +39,13 @@ def __init__(self, name=None, latex=None, html=None, values=None, def __mul__(self, other): if type(other) is not Quantity: - raise qnArrayError("qnArrays can obly be multiplied by Quantity objects") + raise qnArrayError("qnArrays can only be multiplied by Quantity objects") return qnArray(values = self.nparr*other.value, units = self.units*other.units) def __truediv__(self, other): - return self.nparr / other + if type(other) is not Quantity: + raise qnArrayError("qnArrays can only be divided by Quantity objects") + return qnArray(values = self.nparr/other.value, units = self.units/other.units) @property def units_str(self): From 22f622480e9b170fca2bc268653c9e35453c108d Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 3 Jul 2017 11:39:53 +0100 Subject: [PATCH 017/106] add qnArray division test --- pyqn/tests/test_qn_array.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pyqn/tests/test_qn_array.py b/pyqn/tests/test_qn_array.py index def460e..a7f1582 100644 --- a/pyqn/tests/test_qn_array.py +++ b/pyqn/tests/test_qn_array.py @@ -41,5 +41,14 @@ def test_qnarray_mult(self): for i in range(len(a2)): self.assertEqual(result2.nparr[i], 0.2*a2[i]) + def test_qnarray_div(self): + a1 = [-1,-2,-3,-4,-5] + qnarr1 = qnArray(values = a1, units = 'm') + q1 = Quantity(value = 2, units = 's') + result1 = qnarr1/q1 + self.assertEqual(result1.units_str, 'm.s-1') + for i in range(len(a1)): + self.assertEqual(result1.nparr[i], a1[i]/2) + if __name__ == '__main__': unittest.main() From 14168e408b7483be7ddd9e69ac6ecbfd2104ab64 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 3 Jul 2017 11:43:40 +0100 Subject: [PATCH 018/106] add more comprehensive error testing --- pyqn/tests/test_qn_array.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/pyqn/tests/test_qn_array.py b/pyqn/tests/test_qn_array.py index a7f1582..6c27131 100644 --- a/pyqn/tests/test_qn_array.py +++ b/pyqn/tests/test_qn_array.py @@ -21,8 +21,7 @@ def test_qnarray_init(self): with self.assertRaises(qnArrayError) as e1: qnarr = qnArray(values = "string") - with self.assertRaises(qnArrayError) as e2: - qnarr = qnArray(values = ["a", "b", "c"]) + qnarr = qnArray(values = ["a", "b", "c"]) def test_qnarray_mult(self): a1 = [-1,-2,-3,-4,-5] @@ -41,6 +40,12 @@ def test_qnarray_mult(self): for i in range(len(a2)): self.assertEqual(result2.nparr[i], 0.2*a2[i]) + with self.assertRaises(qnArrayError) as e1: + result = qnarr1*2 + result = qnarr1*"str" + result = qnarr1*np.array([1,2,3]) + result = qnarr1*qnarr2 + def test_qnarray_div(self): a1 = [-1,-2,-3,-4,-5] qnarr1 = qnArray(values = a1, units = 'm') @@ -50,5 +55,11 @@ def test_qnarray_div(self): for i in range(len(a1)): self.assertEqual(result1.nparr[i], a1[i]/2) + with self.assertRaises(qnArrayError) as e1: + result = qnarr1/2 + result = qnarr1/"str" + result = qnarr1/np.array([1,2,3]) + result = qnarr1/qnarr2 + if __name__ == '__main__': unittest.main() From ef495897c0882a690cca2d3f6195c8813f84f56c Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 3 Jul 2017 12:21:29 +0100 Subject: [PATCH 019/106] separate exception raising situations into separate tests --- pyqn/tests/test_qn_array.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pyqn/tests/test_qn_array.py b/pyqn/tests/test_qn_array.py index 6c27131..e140502 100644 --- a/pyqn/tests/test_qn_array.py +++ b/pyqn/tests/test_qn_array.py @@ -42,8 +42,11 @@ def test_qnarray_mult(self): with self.assertRaises(qnArrayError) as e1: result = qnarr1*2 + with self.assertRaises(qnArrayError) as e2: result = qnarr1*"str" + with self.assertRaises(qnArrayError) as e3: result = qnarr1*np.array([1,2,3]) + with self.assertRaises(qnArrayError) as e4: result = qnarr1*qnarr2 def test_qnarray_div(self): @@ -55,10 +58,21 @@ def test_qnarray_div(self): for i in range(len(a1)): self.assertEqual(result1.nparr[i], a1[i]/2) + a2 = [5,10] + qnarr2 = qnArray(values = np.array(a2), units = 'J') + q2 = Quantity(value=0.2, units = 'm-1') + result2 = qnarr2/q2 + self.assertEqual(result2.units_str, 'J.m') + for i in range(len(a2)): + self.assertEqual(result2.nparr[i], a2[i]/0.2) + with self.assertRaises(qnArrayError) as e1: result = qnarr1/2 + with self.assertRaises(qnArrayError) as e2: result = qnarr1/"str" + with self.assertRaises(qnArrayError) as e3: result = qnarr1/np.array([1,2,3]) + with self.assertRaises(qnArrayError) as e4: result = qnarr1/qnarr2 if __name__ == '__main__': From 3f4fd2a9ad1f9e930f643a7cae05017b77572997 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 10:22:43 +0100 Subject: [PATCH 020/106] another variation of qn_array --- pyqn/qn_array_two.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 pyqn/qn_array_two.py diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py new file mode 100644 index 0000000..03c6db7 --- /dev/null +++ b/pyqn/qn_array_two.py @@ -0,0 +1,29 @@ +import numpy as np +from .units import Units +from .quantity import Quantity + +class qnArrayTwoError(Exception): + def __init__(self, error_str): + self.error_str = error_str + def __str__(self): + return self.error_str + +class qnArrayTwo(np.ndarray): + def __new__(cls, input_array, info=None, units=None, sd_arr=None): + obj = np.asarray(input_array).view(cls) + obj.info = info + obj.units = Units(units) + if sd_arr is not None: + if len(input_array) != len(input_array): + raise qnArrayTwoError("Standard deviation array must be of the same length as values array") + obj.sd = sd_arr + return obj + + def __array_finalize__(self, obj): + if obj is None: return + self.info = getattr(obj, 'info', None) + + def __mul__(self, other): + if type(other) is not Quantity: + raise qnArrayTwoError("Multiplication operation can be done only using Quantity objects") + From 236411daf513da283248d0da3bca3981f4202346 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 10:33:01 +0100 Subject: [PATCH 021/106] add tests to qnArrayTwo class --- pyqn/tests/test_qn_array_two.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 pyqn/tests/test_qn_array_two.py diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py new file mode 100644 index 0000000..ce769c6 --- /dev/null +++ b/pyqn/tests/test_qn_array_two.py @@ -0,0 +1,14 @@ +import unittest +from ..qn_array_two import qnArrayTwo +from ..units import Units + +class qnArrayTwoTest(unittest.TestCase): + def qn_array_two_init(self): + vals1 = [1,2,3,4] + qnarr = qnArrayTwo(vals1,units='m') + self.assertEqual(qnarr.units, Units('m')) + for i in range(len(vals1)): + self.assertEqual(qnarr.values[i], vals1[i]) + +if __name__ == '__main__': + unittest.main() From 98d39d2e85642bc92be086d89d5224883ebfb71f Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 10:37:50 +0100 Subject: [PATCH 022/106] add testing of standard deviation initialisation in qnArrayTwo --- pyqn/tests/test_qn_array_two.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index ce769c6..c091c7b 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -5,10 +5,18 @@ class qnArrayTwoTest(unittest.TestCase): def qn_array_two_init(self): vals1 = [1,2,3,4] - qnarr = qnArrayTwo(vals1,units='m') - self.assertEqual(qnarr.units, Units('m')) + qnarr1 = qnArrayTwo(vals1,units='m') + self.assertEqual(qnarr1.units, Units('m')) for i in range(len(vals1)): - self.assertEqual(qnarr.values[i], vals1[i]) + self.assertEqual(qnarr1.values[i], vals1[i]) + + vals2 = [-10,-20,-30,0,5] + sd2 = [0.1,0.2,0.3,0.4,0.1] + qnarr2 = qnArrayTwo(vals2, units = 'J', sd = sd2) + self.assertEqual(qnarr2.units, Units('J')) + for i in range(len(vals2)): + self.assertEqual(qnarr2.values[i], vals2[i]) + self.assertEqual(qnarr2.sd[i], sd2[i]) if __name__ == '__main__': unittest.main() From 2a9b766252459e7c08934d22d699f2aabf1d134e Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 11:29:41 +0100 Subject: [PATCH 023/106] add function created --- pyqn/qn_array_two.py | 50 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index 03c6db7..ed76192 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -3,27 +3,55 @@ from .quantity import Quantity class qnArrayTwoError(Exception): - def __init__(self, error_str): + def __init__(self, error_str): self.error_str = error_str def __str__(self): return self.error_str class qnArrayTwo(np.ndarray): - def __new__(cls, input_array, info=None, units=None, sd_arr=None): + def __new__(cls, input_array, info=None, units=None, sd=None): + """ Initialises a qnArray as a child class derived from the + numpy ndarray. + """ obj = np.asarray(input_array).view(cls) obj.info = info - obj.units = Units(units) - if sd_arr is not None: - if len(input_array) != len(input_array): - raise qnArrayTwoError("Standard deviation array must be of the same length as values array") - obj.sd = sd_arr + + if type(units) is str: + obj.units = Units(units) #records units as Unit class + elif type(units) is Units: + obj.units = units + + # checks for length of standard deviation array + if sd is not None: + if len(sd) != len(input_array): + raise qnArrayTwoError("Standard deviation array must be of the same length as values array") + obj.sd = sd + return obj def __array_finalize__(self, obj): if obj is None: return self.info = getattr(obj, 'info', None) - def __mul__(self, other): - if type(other) is not Quantity: - raise qnArrayTwoError("Multiplication operation can be done only using Quantity objects") - + #def __mul__(self, other): + # if type(other) is not Quantity: + # raise qnArrayTwoError("Multiplication operation can be done only using Quantity objects") + + def __add__(self, other): + """ Function for adding a Quantity value to all values in + qnArrayTwo or adding another anArrayTwo to the current array + """ + if type(other) is qnArrayTwo: + if len(other) != len(self): + raise qnArrayTwoError("Inconsistent array lengths") + v = [] + for i in range(len(self)): + temp_q = Quantity(value = self[i], units = self.units) + Quantity(value = other[i], units = other.units) + v.append(temp_q.value) + return qnArrayTwo(v, units = temp_q.units) + if type(other) is Quantity: + v = [] + for i in range(len(self)): + temp_q = Quantity(value=self[i], units=self.units) + other + v.append(temp_q.value) + return qnArrayTwo(v, units = temp_q.units) From 33868f3010c998d495028f69139a2abf1460a4c7 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 11:30:03 +0100 Subject: [PATCH 024/106] add function in qnArrayTwo tested --- pyqn/tests/test_qn_array_two.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index c091c7b..78c7a15 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -1,22 +1,36 @@ import unittest -from ..qn_array_two import qnArrayTwo +from ..qn_array_two import qnArrayTwo, qnArrayTwoError from ..units import Units class qnArrayTwoTest(unittest.TestCase): - def qn_array_two_init(self): + def test_qn_array_two_init(self): vals1 = [1,2,3,4] qnarr1 = qnArrayTwo(vals1,units='m') self.assertEqual(qnarr1.units, Units('m')) for i in range(len(vals1)): - self.assertEqual(qnarr1.values[i], vals1[i]) + self.assertEqual(qnarr1[i], vals1[i]) vals2 = [-10,-20,-30,0,5] sd2 = [0.1,0.2,0.3,0.4,0.1] qnarr2 = qnArrayTwo(vals2, units = 'J', sd = sd2) self.assertEqual(qnarr2.units, Units('J')) for i in range(len(vals2)): - self.assertEqual(qnarr2.values[i], vals2[i]) + self.assertEqual(qnarr2[i], vals2[i]) self.assertEqual(qnarr2.sd[i], sd2[i]) + with self.assertRaises(qnArrayTwoError) as e: + qnarr = qnArrayTwo(vals2, units='m', sd = vals1) + + def test_qn_array_two_add(self): + vals1 = [1,2,3,4] + qnarr1 = qnArrayTwo(vals1,units='m') + + vals2 = [2,3,4,1] + qnarr2 = qnArrayTwo(vals2, units='m') + + qnarr3 = qnarr1 + qnarr2 + for i in range(len(vals2)): + self.assertEqual(qnarr3[i], vals1[i]+vals2[i]) + if __name__ == '__main__': unittest.main() From 30f8afc59195b6b0e7d9e5f5e0bc5d6c3626d548 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 11:49:14 +0100 Subject: [PATCH 025/106] add functin to subtract qnArrayTwo objects --- pyqn/qn_array_two.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index ed76192..0b50586 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -55,3 +55,23 @@ def __add__(self, other): temp_q = Quantity(value=self[i], units=self.units) + other v.append(temp_q.value) return qnArrayTwo(v, units = temp_q.units) + else: + raise qnArrayTwoError("Can only add two qnArray objects or a qnArray with Quantity") + + def __sub__(self, other): + if type(other) is qnArrayTwo: + if len(other) != len(self): + raise qnArrayTwoError("Inconsistent array lengths") + v = [] + for i in range(len(self)): + temp_q = Quantity(value = self[i], units = self.units) - Quantity(value = other[i], units = other.units) + v.append(temp_q.value) + return qnArrayTwo(v, units = temp_q.units) + if type(other) is Quantity: + v = [] + for i in range(len(self)): + temp_q = Quantity(value=self[i], units=self.units) - other + v.append(temp_q.value) + return qnArrayTwo(v, units = temp_q.units) + else: + raise qnArrayTwoError("Can only add two qnArray objects or a qnArray with Quantity") From aecb9da6fc2cacc59261fead3a5918f479e41aab Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 11:49:35 +0100 Subject: [PATCH 026/106] add tests for subtracting qnArrayTwo objects --- pyqn/tests/test_qn_array_two.py | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index 78c7a15..4cbb4df 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -1,6 +1,7 @@ import unittest from ..qn_array_two import qnArrayTwo, qnArrayTwoError from ..units import Units +from ..quantity import Quantity class qnArrayTwoTest(unittest.TestCase): def test_qn_array_two_init(self): @@ -31,6 +32,45 @@ def test_qn_array_two_add(self): qnarr3 = qnarr1 + qnarr2 for i in range(len(vals2)): self.assertEqual(qnarr3[i], vals1[i]+vals2[i]) + + vals3 = [1,1,1] + qnarr3 = qnArrayTwo(vals3, units='m') + with self.assertRaises(qnArrayTwoError) as e: + qnarr = qnarr1 + qnarr3 + + q1 = Quantity(value = 10, units = 'm') + qnarr4 = qnarr1+q1 + self.assertEqual(qnarr4.units, Units('m')) + for i in range(len(qnarr4)): + self.assertEqual(qnarr4[i], qnarr1[i]+10) + + with self.assertRaises(qnArrayTwoError) as e: + qnarr = qnarr1 + 2 + + def test_qn_array_two_sub(self): + vals1 = [1,2,3,4] + qnarr1 = qnArrayTwo(vals1,units='m') + + vals2 = [2,3,4,1] + qnarr2 = qnArrayTwo(vals2, units='m') + + qnarr3 = qnarr1 - qnarr2 + for i in range(len(vals2)): + self.assertEqual(qnarr3[i], vals1[i]-vals2[i]) + + vals3 = [1,1,1] + qnarr3 = qnArrayTwo(vals3, units='m') + with self.assertRaises(qnArrayTwoError) as e: + qnarr = qnarr1 - qnarr3 + + q1 = Quantity(value = 10, units = 'm') + qnarr4 = qnarr1 - q1 + self.assertEqual(qnarr4.units, Units('m')) + for i in range(len(qnarr4)): + self.assertEqual(qnarr4[i], qnarr1[i]-10) + + with self.assertRaises(qnArrayTwoError) as e: + qnarr = qnarr1 - 2 if __name__ == '__main__': unittest.main() From 1d5a0ec6a464933e08d8ec22cc02d3217019acca Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 13:08:54 +0100 Subject: [PATCH 027/106] add multiplication function --- pyqn/qn_array_two.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index 0b50586..5125ddf 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -67,6 +67,7 @@ def __sub__(self, other): temp_q = Quantity(value = self[i], units = self.units) - Quantity(value = other[i], units = other.units) v.append(temp_q.value) return qnArrayTwo(v, units = temp_q.units) + if type(other) is Quantity: v = [] for i in range(len(self)): @@ -75,3 +76,22 @@ def __sub__(self, other): return qnArrayTwo(v, units = temp_q.units) else: raise qnArrayTwoError("Can only add two qnArray objects or a qnArray with Quantity") + + def __mul__(self, other): + if type(other) is qnArrayTwo: + if len(other) != len(self): + raise qnArrayTwoError("Inconsistent array lengths") + v = [] + for i in range(len(self)): + temp_q = Quantity(value = self[i], units = self.units) * Quantity(value = other[i], units = other.units) + v.append(temp_q.value) + return qnArrayTwo(v, units = temp_q.units) + + if type(other) is Quantity: + v = [] + for i in range(len(self)): + temp_q = Quantity(value=self[i], units=self.units) * other + v.append(temp_q.value) + return qnArrayTwo(v, units = temp_q.units) + else: + raise qnArrayTwoError("Can only add two qnArray objects or a qnArray with Quantity") From 1b8e93aa204e2b9c2765451bc2bcb30004cbbe2d Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 13:09:27 +0100 Subject: [PATCH 028/106] add testing of multiplication of qnArrayTwo objects --- pyqn/tests/test_qn_array_two.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index 4cbb4df..8f42f1e 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -72,5 +72,31 @@ def test_qn_array_two_sub(self): with self.assertRaises(qnArrayTwoError) as e: qnarr = qnarr1 - 2 + def test_qn_array_two_mul(self): + vals1 = [1,2,3,4] + qnarr1 = qnArrayTwo(vals1,units='m') + + vals2 = [2,3,4,1] + qnarr2 = qnArrayTwo(vals2, units='s') + + qnarr3 = qnarr1 * qnarr2 + self.assertEqual(qnarr3.units, Units('m.s')) + for i in range(len(vals2)): + self.assertEqual(qnarr3[i], vals1[i]*vals2[i]) + + vals3 = [1,1,1] + qnarr3 = qnArrayTwo(vals3, units='m') + with self.assertRaises(qnArrayTwoError) as e: + qnarr = qnarr1 * qnarr3 + + q1 = Quantity(value = 10, units = 'J') + qnarr4 = qnarr1 * q1 + self.assertEqual(qnarr4.units, Units('m.J')) + for i in range(len(qnarr4)): + self.assertEqual(qnarr4[i], qnarr1[i]*10) + + with self.assertRaises(qnArrayTwoError) as e: + qnarr = qnarr1 * 2 + if __name__ == '__main__': unittest.main() From f8e27c9482e244481f2405ad7d9fb391b41fe0c0 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 13:14:54 +0100 Subject: [PATCH 029/106] add division function --- pyqn/qn_array_two.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index 5125ddf..2f10fd6 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -75,7 +75,7 @@ def __sub__(self, other): v.append(temp_q.value) return qnArrayTwo(v, units = temp_q.units) else: - raise qnArrayTwoError("Can only add two qnArray objects or a qnArray with Quantity") + raise qnArrayTwoError("Can only subtract two qnArray objects or a qnArray with Quantity") def __mul__(self, other): if type(other) is qnArrayTwo: @@ -94,4 +94,23 @@ def __mul__(self, other): v.append(temp_q.value) return qnArrayTwo(v, units = temp_q.units) else: - raise qnArrayTwoError("Can only add two qnArray objects or a qnArray with Quantity") + raise qnArrayTwoError("Can only multiply two qnArray objects or a qnArray with Quantity") + + def __truediv__(self, other): + if type(other) is qnArrayTwo: + if len(other) != len(self): + raise qnArrayTwoError("Inconsistent array lengths") + v = [] + for i in range(len(self)): + temp_q = Quantity(value = self[i], units = self.units) / Quantity(value = other[i], units = other.units) + v.append(temp_q.value) + return qnArrayTwo(v, units = temp_q.units) + + if type(other) is Quantity: + v = [] + for i in range(len(self)): + temp_q = Quantity(value=self[i], units=self.units) / other + v.append(temp_q.value) + return qnArrayTwo(v, units = temp_q.units) + else: + raise qnArrayTwoError("Can onlydividde two qnArray objects or a qnArray with Quantity") From c0e80ccbb7f816cdf1f1d175a78a7a83ecdaddf8 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 13:15:05 +0100 Subject: [PATCH 030/106] test division function --- pyqn/tests/test_qn_array_two.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index 8f42f1e..0c7b86e 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -98,5 +98,31 @@ def test_qn_array_two_mul(self): with self.assertRaises(qnArrayTwoError) as e: qnarr = qnarr1 * 2 + def test_qn_array_two_mul(self): + vals1 = [1,2,3,4] + qnarr1 = qnArrayTwo(vals1,units='m') + + vals2 = [2,3,4,1] + qnarr2 = qnArrayTwo(vals2, units='s') + + qnarr3 = qnarr1 / qnarr2 + self.assertEqual(qnarr3.units, Units('m.s-1')) + for i in range(len(vals2)): + self.assertEqual(qnarr3[i], vals1[i]/vals2[i]) + + vals3 = [1,1,1] + qnarr3 = qnArrayTwo(vals3, units='m') + with self.assertRaises(qnArrayTwoError) as e: + qnarr = qnarr1 / qnarr3 + + q1 = Quantity(value = 10, units = 'J') + qnarr4 = qnarr1 / q1 + self.assertEqual(qnarr4.units, Units('m.J-1')) + for i in range(len(qnarr4)): + self.assertEqual(qnarr4[i], qnarr1[i]/10) + + with self.assertRaises(qnArrayTwoError) as e: + qnarr = qnarr1 / 2 + if __name__ == '__main__': unittest.main() From dfb73da18d64456d43987d69169d19d8d3728ae3 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 14:03:05 +0100 Subject: [PATCH 031/106] add standard deviation calculations to algebra function --- pyqn/qn_array_two.py | 52 +++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index 2f10fd6..7957ab1 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -26,6 +26,8 @@ def __new__(cls, input_array, info=None, units=None, sd=None): if len(sd) != len(input_array): raise qnArrayTwoError("Standard deviation array must be of the same length as values array") obj.sd = sd + else: + obj.sd = np.zeros(len(input_array)) return obj @@ -45,16 +47,20 @@ def __add__(self, other): if len(other) != len(self): raise qnArrayTwoError("Inconsistent array lengths") v = [] + sd_arr = [] for i in range(len(self)): - temp_q = Quantity(value = self[i], units = self.units) + Quantity(value = other[i], units = other.units) + temp_q = Quantity(value = self[i], units = self.units, sd = self.sd[i]) + Quantity(value = other[i], units = other.units, sd = other.sd[i]) v.append(temp_q.value) - return qnArrayTwo(v, units = temp_q.units) + sd_arr.append(temp_q.sd) + return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) if type(other) is Quantity: v = [] + sd_arr = [] for i in range(len(self)): - temp_q = Quantity(value=self[i], units=self.units) + other + temp_q = Quantity(value=self[i], units=self.units, sd = self.sd[i]) + other v.append(temp_q.value) - return qnArrayTwo(v, units = temp_q.units) + sd_arr.append(temp_q.sd) + return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) else: raise qnArrayTwoError("Can only add two qnArray objects or a qnArray with Quantity") @@ -63,17 +69,21 @@ def __sub__(self, other): if len(other) != len(self): raise qnArrayTwoError("Inconsistent array lengths") v = [] + sd_arr = [] for i in range(len(self)): - temp_q = Quantity(value = self[i], units = self.units) - Quantity(value = other[i], units = other.units) + temp_q = Quantity(value = self[i], units = self.units, sd = self.sd[i]) - Quantity(value = other[i], units = other.units, sd = other.sd[i]) v.append(temp_q.value) - return qnArrayTwo(v, units = temp_q.units) + sd_arr.append(temp_q.sd) + return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) if type(other) is Quantity: v = [] + sd_arr = [] for i in range(len(self)): - temp_q = Quantity(value=self[i], units=self.units) - other + temp_q = Quantity(value=self[i], units=self.units, sd = self.sd[i]) - other v.append(temp_q.value) - return qnArrayTwo(v, units = temp_q.units) + sd_arr.append(temp_q.sd) + return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) else: raise qnArrayTwoError("Can only subtract two qnArray objects or a qnArray with Quantity") @@ -82,17 +92,21 @@ def __mul__(self, other): if len(other) != len(self): raise qnArrayTwoError("Inconsistent array lengths") v = [] + sd_arr = [] for i in range(len(self)): - temp_q = Quantity(value = self[i], units = self.units) * Quantity(value = other[i], units = other.units) + temp_q = Quantity(value = self[i], units = self.units, sd = self.sd[i]) * Quantity(value = other[i], units = other.units, sd = other.sd[i]) v.append(temp_q.value) - return qnArrayTwo(v, units = temp_q.units) + sd_arr.append(temp_q.sd) + return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) if type(other) is Quantity: v = [] + sd_arr = [] for i in range(len(self)): - temp_q = Quantity(value=self[i], units=self.units) * other + temp_q = Quantity(value=self[i], units=self.units, sd = self.sd[i]) * other v.append(temp_q.value) - return qnArrayTwo(v, units = temp_q.units) + sd_arr.append(temp_q.sd) + return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) else: raise qnArrayTwoError("Can only multiply two qnArray objects or a qnArray with Quantity") @@ -101,16 +115,20 @@ def __truediv__(self, other): if len(other) != len(self): raise qnArrayTwoError("Inconsistent array lengths") v = [] + sd_arr = [] for i in range(len(self)): - temp_q = Quantity(value = self[i], units = self.units) / Quantity(value = other[i], units = other.units) + temp_q = Quantity(value = self[i], units = self.units, sd = self.sd[i]) / Quantity(value = other[i], units = other.units, sd = other.sd[i]) v.append(temp_q.value) - return qnArrayTwo(v, units = temp_q.units) + sd_arr.append(temp_q.sd) + return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) if type(other) is Quantity: v = [] + sd_arr = [] for i in range(len(self)): - temp_q = Quantity(value=self[i], units=self.units) / other + temp_q = Quantity(value=self[i], units=self.units, sd = self.sd[i]) / other v.append(temp_q.value) - return qnArrayTwo(v, units = temp_q.units) + sd_arr.append(temp_q.sd) + return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) else: - raise qnArrayTwoError("Can onlydividde two qnArray objects or a qnArray with Quantity") + raise qnArrayTwoError("Can only divide two qnArray objects or a qnArray with Quantity") From 0b6e892e15be5c3bb52da3a6d5820bd27f1d2175 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 14:03:30 +0100 Subject: [PATCH 032/106] test standard deivation calculations during algebraic calculations --- pyqn/tests/test_qn_array_two.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index 0c7b86e..f13fa48 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -2,6 +2,7 @@ from ..qn_array_two import qnArrayTwo, qnArrayTwoError from ..units import Units from ..quantity import Quantity +import numpy as np class qnArrayTwoTest(unittest.TestCase): def test_qn_array_two_init(self): @@ -10,6 +11,7 @@ def test_qn_array_two_init(self): self.assertEqual(qnarr1.units, Units('m')) for i in range(len(vals1)): self.assertEqual(qnarr1[i], vals1[i]) + self.assertEqual(qnarr1.sd[i], 0) vals2 = [-10,-20,-30,0,5] sd2 = [0.1,0.2,0.3,0.4,0.1] @@ -24,14 +26,17 @@ def test_qn_array_two_init(self): def test_qn_array_two_add(self): vals1 = [1,2,3,4] - qnarr1 = qnArrayTwo(vals1,units='m') + sd1 = [0.1, 0.2, 0.3, 0.1] + qnarr1 = qnArrayTwo(vals1,units='m',sd=sd1) vals2 = [2,3,4,1] - qnarr2 = qnArrayTwo(vals2, units='m') + sd2 = [0.2, 0.1, 0.2, 0.1] + qnarr2 = qnArrayTwo(vals2, units='m', sd=sd2) qnarr3 = qnarr1 + qnarr2 for i in range(len(vals2)): self.assertEqual(qnarr3[i], vals1[i]+vals2[i]) + self.assertAlmostEqual(qnarr3.sd[i], np.sqrt(sd1[i]**2 + sd2[i]**2)) vals3 = [1,1,1] qnarr3 = qnArrayTwo(vals3, units='m') @@ -49,14 +54,17 @@ def test_qn_array_two_add(self): def test_qn_array_two_sub(self): vals1 = [1,2,3,4] - qnarr1 = qnArrayTwo(vals1,units='m') + sd1 = [0.1, 0.2, 0.3, 0.1] + qnarr1 = qnArrayTwo(vals1,units='m',sd=sd1) vals2 = [2,3,4,1] - qnarr2 = qnArrayTwo(vals2, units='m') + sd2 = [0.2, 0.1, 0.2, 0.1] + qnarr2 = qnArrayTwo(vals2, units='m',sd=sd2) qnarr3 = qnarr1 - qnarr2 for i in range(len(vals2)): self.assertEqual(qnarr3[i], vals1[i]-vals2[i]) + self.assertAlmostEqual(qnarr3.sd[i], np.sqrt(sd1[i]**2 + sd2[i]**2)) vals3 = [1,1,1] qnarr3 = qnArrayTwo(vals3, units='m') @@ -74,15 +82,18 @@ def test_qn_array_two_sub(self): def test_qn_array_two_mul(self): vals1 = [1,2,3,4] - qnarr1 = qnArrayTwo(vals1,units='m') + sd1 = [0.1, 0.2, 0.3, 0.1] + qnarr1 = qnArrayTwo(vals1,units='m',sd=sd1) vals2 = [2,3,4,1] - qnarr2 = qnArrayTwo(vals2, units='s') + sd2 = [0.2, 0.1, 0.2, 0.1] + qnarr2 = qnArrayTwo(vals2, units='s',sd=sd2) qnarr3 = qnarr1 * qnarr2 self.assertEqual(qnarr3.units, Units('m.s')) for i in range(len(vals2)): self.assertEqual(qnarr3[i], vals1[i]*vals2[i]) + self.assertAlmostEqual(qnarr3.sd[i], qnarr3[i]*np.sqrt((sd1[i]/vals1[i])**2+(sd2[i]/vals2[i])**2)) vals3 = [1,1,1] qnarr3 = qnArrayTwo(vals3, units='m') @@ -100,15 +111,18 @@ def test_qn_array_two_mul(self): def test_qn_array_two_mul(self): vals1 = [1,2,3,4] - qnarr1 = qnArrayTwo(vals1,units='m') + sd1 = [0.1, 0.2, 0.3, 0.1] + qnarr1 = qnArrayTwo(vals1,units='m',sd=sd1) vals2 = [2,3,4,1] - qnarr2 = qnArrayTwo(vals2, units='s') + sd2 = [0.2, 0.1, 0.2, 0.1] + qnarr2 = qnArrayTwo(vals2, units='s',sd=sd2) qnarr3 = qnarr1 / qnarr2 self.assertEqual(qnarr3.units, Units('m.s-1')) for i in range(len(vals2)): self.assertEqual(qnarr3[i], vals1[i]/vals2[i]) + self.assertAlmostEqual(qnarr3.sd[i], qnarr3[i]*np.sqrt((sd1[i]/vals1[i])**2+(sd2[i]/vals2[i])**2)) vals3 = [1,1,1] qnarr3 = qnArrayTwo(vals3, units='m') From dfbb8ef10407eee3703556e90ad201020e4f7143 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 14:29:02 +0100 Subject: [PATCH 033/106] add standard deviation calculation to __pow__ function --- pyqn/quantity.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyqn/quantity.py b/pyqn/quantity.py index d5dbe5e..7aca4f4 100644 --- a/pyqn/quantity.py +++ b/pyqn/quantity.py @@ -295,7 +295,8 @@ def __rtruediv__(self, other): def __pow__(self, power): return Quantity(value = self.value**power, - units = self.units**power) + units = self.units**power, + sd = self.value**power*math.hypot(self.sd/self.value, self.sd/self.value)) @classmethod def parse(self, s_quantity, name=None, units=None, sd=None, From 306b4de208a6b1076a019baf5db9dce70303bb90 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 14:29:32 +0100 Subject: [PATCH 034/106] add __pow__ function to qnArrayTwo class --- pyqn/qn_array_two.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index 7957ab1..f5a9ca3 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -132,3 +132,13 @@ def __truediv__(self, other): return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) else: raise qnArrayTwoError("Can only divide two qnArray objects or a qnArray with Quantity") + + def __pow__(self, other): + v = [] + sd_arr = [] + for i in range(len(self)): + temp_q = Quantity(value=self[i], units = self.units, sd = self.sd[i]) ** other + v.append(temp_q.value) + sd_arr.append(temp_q.sd) + return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) + From 0a53c638b8b306f8bb064c075274898c81c2867e Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 14:29:51 +0100 Subject: [PATCH 035/106] test qnArrayTwo __pow__ function --- pyqn/tests/test_qn_array_two.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index f13fa48..2a4c2c8 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -138,5 +138,16 @@ def test_qn_array_two_mul(self): with self.assertRaises(qnArrayTwoError) as e: qnarr = qnarr1 / 2 + def test_qn_array_two_pow(self): + vals1 = [1,2,3,4] + sd1 = [0.1, 0.2, 0.3, 0.4] + qnarr1 = qnArrayTwo(vals1, units = 'm', sd = sd1) + + qnarr2 = qnarr1 ** 2 + self.assertEqual(qnarr2.units, Units('m2')) + for i in range(len(vals1)): + self.assertEqual(qnarr2[i], vals1[i]**2) + self.assertAlmostEqual(qnarr2.sd[i], qnarr2[i]*np.sqrt(2.0*(sd1[i]/vals1[i])**2)) + if __name__ == '__main__': unittest.main() From b6f9c09d726863deaae94283e08f653b69f906ef Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 14:48:49 +0100 Subject: [PATCH 036/106] added __eq__ function but facing recursion depth exceded error --- pyqn/qn_array_two.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index f5a9ca3..ced35ca 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -142,3 +142,8 @@ def __pow__(self, other): sd_arr.append(temp_q.sd) return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) + #def __eq__(self, other): + # if all(self == other) and (self.units == other.units) and (self.sd == other.sd): + # return True + # else: + # return False From 1c8033fb89fdc65fe9631648530e3f87e7340fee Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 14:49:19 +0100 Subject: [PATCH 037/106] prepare tests for not currently functioning __eq__ function --- pyqn/tests/test_qn_array_two.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index 2a4c2c8..d338820 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -149,5 +149,25 @@ def test_qn_array_two_pow(self): self.assertEqual(qnarr2[i], vals1[i]**2) self.assertAlmostEqual(qnarr2.sd[i], qnarr2[i]*np.sqrt(2.0*(sd1[i]/vals1[i])**2)) + #def test_qn_array_eq(self): + # qnarr1 = qnArrayTwo([1,1,1],units = 'm', sd = [0.1,0.1,0.1]) + # qnarr2 = qnArrayTwo([1,1,1],units = 'm') + # qnarr3 = qnArrayTwo([1,2,3],units = 'm', sd = [0.1,0.1,0.1]) + # qnarr4 = qnArrayTwo([1,2,3],units = 'J', sd = [0.1,0.1,0.1]) + # qnarr5 = qnArrayTwo([1.0,1.0,1.0],units = Units('m'), sd = [0,0,0]) + + # self.assertFalse(qnarr1 == qnarr2) + # self.assertFalse(qnarr1 == qnarr3) + # self.assertFalse(qnarr1 == qnarr4) + # self.assertFalse(qnarr1 == qnarr5) + + # self.assertFalse(qnarr2 == qnarr3) + # self.assertFalse(qnarr2 == qnarr4) + # self.assertTrue(qnarr2 == qnarr5) + + # self.assertFalse(qnarr3 == qnarr4) + # self.assertFalse(qnarr3 == qnarr5) + + # self.assertFalse(qnarr4 == qnarr5) if __name__ == '__main__': unittest.main() From fd6db2a754715c74e3e5d3cd38fa2dea3c3e7f45 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 15:04:00 +0100 Subject: [PATCH 038/106] add html_str function to output html style representation of the array --- pyqn/qn_array_two.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index ced35ca..e347b64 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -35,10 +35,6 @@ def __array_finalize__(self, obj): if obj is None: return self.info = getattr(obj, 'info', None) - #def __mul__(self, other): - # if type(other) is not Quantity: - # raise qnArrayTwoError("Multiplication operation can be done only using Quantity objects") - def __add__(self, other): """ Function for adding a Quantity value to all values in qnArrayTwo or adding another anArrayTwo to the current array @@ -147,3 +143,10 @@ def __pow__(self, other): # return True # else: # return False + + @property + def html_str(self): + html_chunks = [] + for i in range(len(self)): + html_chunks.append(Quantity(value=self[i],units = self.units, sd = self.sd[i]).html_str) + return ', '.join(html_chunks) From df8068b4472caebfa5a964802a5e3b2e4d64de72 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 4 Jul 2017 15:04:14 +0100 Subject: [PATCH 039/106] add tests for html_str function --- pyqn/tests/test_qn_array_two.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index d338820..1a98739 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -169,5 +169,13 @@ def test_qn_array_two_pow(self): # self.assertFalse(qnarr3 == qnarr5) # self.assertFalse(qnarr4 == qnarr5) + + def test_qn_array_two_html(self): + vals = [1,2,3,4] + sd = [0.1,0.2,0.3,0.4] + qnarr = qnArrayTwo(vals, units = 'm', sd = sd) + + self.assertEqual(qnarr.html_str, '1 ± 0.1 m, 2 ± 0.2 m, 3 ± 0.3 m, 4 ± 0.4 m') + if __name__ == '__main__': unittest.main() From 73f4e2743831854f79d84465ba64f483f8564e3f Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 6 Jul 2017 12:24:09 +0100 Subject: [PATCH 040/106] add test file for Dimensions class --- pyqn/tests/test_dimensions.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 pyqn/tests/test_dimensions.py diff --git a/pyqn/tests/test_dimensions.py b/pyqn/tests/test_dimensions.py new file mode 100644 index 0000000..f26980a --- /dev/null +++ b/pyqn/tests/test_dimensions.py @@ -0,0 +1,11 @@ +import unittest +from ..dimensions import Dimensions + +class DimensionsCheck(unittest.TestCase): + def test_dimensions_init(self): + d1 = Dimensions(dims = [1,0,0,0,0,0,1]) + d2 = Dimensions(dims = [0,0,0,0,0,0,0]) + d3 = Dimensions(dims = [1,1,1,1,1,1,1]) + +if __name__ == '__main__': + unittest.main() From f28400c976ca1edfaf934cb13ba78cd18b19e93b Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 6 Jul 2017 12:32:48 +0100 Subject: [PATCH 041/106] add DimensionsError class to handle exceptions --- pyqn/dimensions.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pyqn/dimensions.py b/pyqn/dimensions.py index 884e260..dea30ba 100644 --- a/pyqn/dimensions.py +++ b/pyqn/dimensions.py @@ -25,6 +25,12 @@ # You should have received a copy of the GNU General Public License # along with PyQn. If not, see +class DimensionsError(Exception): + def __init__(self, error_str): + self.error_str = error_str + def __str__(self): + return self.error_str + class Dimensions(object): # these are the abbreviations for Length, Mass, Time, Temperature, # Quantity (amount of substance), Current, and Luminous Intensity @@ -40,10 +46,12 @@ def __init__(self, dims=None, **kwargs): if dims: # initialize by dims array if not kwargs: - self.dims = dims + if len(dims) == 7: + self.dims = dims + else: + raise DimensionsError('Inconsistent number of dimensions in input') else: - print('bad initialisation of Dimensions object') - sys.exit(1) + raise DimensionsError('Bad initialisation of Dimensions object') else: # initialize by keyword arguments for dim_name in kwargs: From 3986d7266679f4e2aeb06bf7db3b658bbff87cda Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 6 Jul 2017 12:33:22 +0100 Subject: [PATCH 042/106] add tests for usage of DimensionsError class and when it arises furing initialisation --- pyqn/tests/test_dimensions.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/pyqn/tests/test_dimensions.py b/pyqn/tests/test_dimensions.py index f26980a..b739d2c 100644 --- a/pyqn/tests/test_dimensions.py +++ b/pyqn/tests/test_dimensions.py @@ -1,11 +1,26 @@ import unittest -from ..dimensions import Dimensions +from ..dimensions import Dimensions, DimensionsError class DimensionsCheck(unittest.TestCase): def test_dimensions_init(self): - d1 = Dimensions(dims = [1,0,0,0,0,0,1]) - d2 = Dimensions(dims = [0,0,0,0,0,0,0]) - d3 = Dimensions(dims = [1,1,1,1,1,1,1]) + arr1 = [1,0,0,0,0,0,1] + arr2 = [0,0,0,0,0,0,0] + arr3 = [1,1,1,1,1,1,1] + d1 = Dimensions(dims = arr1) + d2 = Dimensions(dims = arr2) + d3 = Dimensions(dims = arr3) + d4 = Dimensions(dims = []) + + for i in range(7): + self.assertEqual(d1.dims[i], arr1[i]) + self.assertEqual(d2.dims[i], arr2[i]) + self.assertEqual(d3.dims[i], arr3[i]) + self.assertEqual(d4.dims[i], 0) + + with self.assertRaises(DimensionsError) as e: + d = Dimensions(dims = [1]) + with self.assertRaises(DimensionsError) as e: + d = Dimensions(dims = [1,1,1,1,1,1,1,1,1,1,1]) if __name__ == '__main__': unittest.main() From f562e106a4425bd9658ec0b1ae55c490a17e585e Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 6 Jul 2017 12:43:55 +0100 Subject: [PATCH 043/106] add tests for Dimensions objects mutiplication and division --- pyqn/tests/test_dimensions.py | 43 +++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/pyqn/tests/test_dimensions.py b/pyqn/tests/test_dimensions.py index b739d2c..1b06e13 100644 --- a/pyqn/tests/test_dimensions.py +++ b/pyqn/tests/test_dimensions.py @@ -4,8 +4,8 @@ class DimensionsCheck(unittest.TestCase): def test_dimensions_init(self): arr1 = [1,0,0,0,0,0,1] - arr2 = [0,0,0,0,0,0,0] - arr3 = [1,1,1,1,1,1,1] + arr2 = [0,2,10,0,5,0,0] + arr3 = [1,1,-1,1,-1,1,-1] d1 = Dimensions(dims = arr1) d2 = Dimensions(dims = arr2) d3 = Dimensions(dims = arr3) @@ -22,5 +22,44 @@ def test_dimensions_init(self): with self.assertRaises(DimensionsError) as e: d = Dimensions(dims = [1,1,1,1,1,1,1,1,1,1,1]) + def test_dimensions_mul(self): + arr1 = [1,0,0,0,0,0,0] + arr2 = [0,1,1,0,1,0,0] + arr3 = [-1,10,5,2,0,-4,0] + d1 = Dimensions(dims = arr1) + d2 = Dimensions(dims = arr2) + d3 = Dimensions(dims = arr3) + + d12 = d1 * d2 + d13 = d1 * d3 + d23 = d2 * d3 + for i in range(7): + self.assertEqual(d12.dims[i], arr1[i]+arr2[i]) + self.assertEqual(d13.dims[i], arr1[i]+arr3[i]) + self.assertEqual(d23.dims[i], arr2[i]+arr3[i]) + + def test_dimensions_div(self): + arr1 = [1,0,0,0,0,0,0] + arr2 = [0,1,1,0,1,0,0] + arr3 = [-1,10,5,2,0,-4,0] + d1 = Dimensions(dims = arr1) + d2 = Dimensions(dims = arr2) + d3 = Dimensions(dims = arr3) + + d12 = d1 / d2 + d21 = d2 / d1 + d13 = d1 / d3 + d31 = d3 / d1 + d23 = d2 / d3 + d32 = d3 / d2 + for i in range(7): + self.assertEqual(d12.dims[i], arr1[i]-arr2[i]) + self.assertEqual(d21.dims[i], arr2[i]-arr1[i]) + self.assertEqual(d13.dims[i], arr1[i]-arr3[i]) + self.assertEqual(d31.dims[i], arr3[i]-arr1[i]) + self.assertEqual(d23.dims[i], arr2[i]-arr3[i]) + self.assertEqual(d32.dims[i], arr3[i]-arr2[i]) + + if __name__ == '__main__': unittest.main() From 73e56299881519ec61c80bc8f395ccf358182d40 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 6 Jul 2017 13:41:00 +0100 Subject: [PATCH 044/106] add tests for Dimensions class for __pow__ and __eq__ --- pyqn/tests/test_dimensions.py | 38 ++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/pyqn/tests/test_dimensions.py b/pyqn/tests/test_dimensions.py index 1b06e13..0516b3f 100644 --- a/pyqn/tests/test_dimensions.py +++ b/pyqn/tests/test_dimensions.py @@ -38,7 +38,7 @@ def test_dimensions_mul(self): self.assertEqual(d13.dims[i], arr1[i]+arr3[i]) self.assertEqual(d23.dims[i], arr2[i]+arr3[i]) - def test_dimensions_div(self): + def test_dimensions_truediv(self): arr1 = [1,0,0,0,0,0,0] arr2 = [0,1,1,0,1,0,0] arr3 = [-1,10,5,2,0,-4,0] @@ -60,6 +60,42 @@ def test_dimensions_div(self): self.assertEqual(d23.dims[i], arr2[i]-arr3[i]) self.assertEqual(d32.dims[i], arr3[i]-arr2[i]) + def test_dimensions_pow(self): + arr1 = [1,0,0,0,0,0,0] + arr2 = [0,1,1,0,1,0,0] + arr3 = [-1,10,5,2,0,-4,0] + d1 = Dimensions(dims = arr1) + d2 = Dimensions(dims = arr2) + d3 = Dimensions(dims = arr3) + + d1_1 = d1 ** 1 + d1_2 = d1 ** 2 + d1__10 = d1 ** (-10) + d2_1 = d2 ** 1 + d2_2 = d2 ** 2 + d2__10 = d2 ** (-10) + d3_1 = d3 ** 1 + d3_2 = d3 ** 2 + d3__10 = d3 ** (-10) + + for i in range(7): + self.assertEqual(d1_1.dims[i], arr1[i]) + self.assertEqual(d1_2.dims[i], arr1[i]*2) + self.assertEqual(d1__10.dims[i], arr1[i]*(-10)) + self.assertEqual(d2_1.dims[i], arr2[i]) + self.assertEqual(d2_2.dims[i], arr2[i]*2) + self.assertEqual(d2__10.dims[i], arr2[i]*(-10)) + self.assertEqual(d3_1.dims[i], arr3[i]) + self.assertEqual(d3_2.dims[i], arr3[i]*2) + self.assertEqual(d3__10.dims[i], arr3[i]*(-10)) + + def test_dimensions_eq(self): + d1 = Dimensions(dims = [1,1,1,0,1,1,1]) + d2 = Dimensions(dims = [1,1,1,0,1,1,1]) + d3 = Dimensions(dims = []) + d4 = Dimensions(dims = [0,0,0,0,0,0,0]) + self.assertTrue(d1 == d2) + self.assertTrue(d3 == d4) if __name__ == '__main__': unittest.main() From 95fb38b59e213d6e2a6f41a6323aa6155a8bdb2d Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Fri, 7 Jul 2017 10:04:00 +0100 Subject: [PATCH 045/106] add dimensions __neq__ function tests --- pyqn/tests/test_dimensions.py | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/pyqn/tests/test_dimensions.py b/pyqn/tests/test_dimensions.py index 0516b3f..83b50a1 100644 --- a/pyqn/tests/test_dimensions.py +++ b/pyqn/tests/test_dimensions.py @@ -96,6 +96,42 @@ def test_dimensions_eq(self): d4 = Dimensions(dims = [0,0,0,0,0,0,0]) self.assertTrue(d1 == d2) self.assertTrue(d3 == d4) + + def test_dimensions_neq(self): + d1 = Dimensions(dims = [1,0,0,0,0,0,0]) + d2 = Dimensions(dims = [0,1,1,0,1,0,0]) + d3 = Dimensions(dims = [-1,10,5,2,0,-4,0]) + d4 = Dimensions(dims = [1,1,1,0,1,1,1]) + d5 = Dimensions(dims = [1,1,1,0,1,1,1]) + d6 = Dimensions(dims = []) + d7 = Dimensions(dims = [0,0,0,0,0,0,0]) + + self.assertTrue(d1 != d2) + self.assertTrue(d1 != d3) + self.assertTrue(d1 != d4) + self.assertTrue(d1 != d5) + self.assertTrue(d1 != d6) + self.assertTrue(d1 != d7) + + self.assertTrue(d2 != d3) + self.assertTrue(d2 != d4) + self.assertTrue(d2 != d5) + self.assertTrue(d2 != d6) + self.assertTrue(d2 != d7) + + self.assertTrue(d3 != d4) + self.assertTrue(d3 != d5) + self.assertTrue(d3 != d6) + self.assertTrue(d3 != d7) + + self.assertFalse(d4 != d5) + self.assertTrue(d4 != d6) + self.assertTrue(d4 != d7) + + self.assertTrue(d5 != d6) + self.assertTrue(d5 != d7) + + self.assertFalse(d6 != d7) if __name__ == '__main__': unittest.main() From c3e923a04b9da4e3bda6b170e77340b7f448b8be Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Fri, 7 Jul 2017 10:08:22 +0100 Subject: [PATCH 046/106] add testing of kwargs during init --- pyqn/tests/test_dimensions.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pyqn/tests/test_dimensions.py b/pyqn/tests/test_dimensions.py index 83b50a1..0814561 100644 --- a/pyqn/tests/test_dimensions.py +++ b/pyqn/tests/test_dimensions.py @@ -21,6 +21,12 @@ def test_dimensions_init(self): d = Dimensions(dims = [1]) with self.assertRaises(DimensionsError) as e: d = Dimensions(dims = [1,1,1,1,1,1,1,1,1,1,1]) + with self.assertRaises(DimensionsError) as e: + d = Dimensions(dims = [], kwargs = 1) + with self.assertRaises(DimensionsError) as e: + d = Dimensions(dims = [], kwargs = {'1':'a','2':'b'}) + with self.assertRaises(DimensionsError) as e: + d = Dimensions(dims = [], kwargs = [1,1,1]) def test_dimensions_mul(self): arr1 = [1,0,0,0,0,0,0] From fc24734b1b6715587e8a741e180b787ee4a1dfe7 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Fri, 7 Jul 2017 10:28:15 +0100 Subject: [PATCH 047/106] add test for var type in dims list upon init --- pyqn/dimensions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyqn/dimensions.py b/pyqn/dimensions.py index dea30ba..319de59 100644 --- a/pyqn/dimensions.py +++ b/pyqn/dimensions.py @@ -46,10 +46,10 @@ def __init__(self, dims=None, **kwargs): if dims: # initialize by dims array if not kwargs: - if len(dims) == 7: + if (len(dims) == 7) and (type(dims[0]) is not str): self.dims = dims else: - raise DimensionsError('Inconsistent number of dimensions in input') + raise DimensionsError('Inconsistent number of dimensions in input or non-value elements of input array') else: raise DimensionsError('Bad initialisation of Dimensions object') else: From e8ae7d7012514130db9c9a431fac7b6d9011d965 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Fri, 7 Jul 2017 10:28:48 +0100 Subject: [PATCH 048/106] add tests for Dimensions initialisation using key word args --- pyqn/tests/test_dimensions.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/pyqn/tests/test_dimensions.py b/pyqn/tests/test_dimensions.py index 0814561..c684215 100644 --- a/pyqn/tests/test_dimensions.py +++ b/pyqn/tests/test_dimensions.py @@ -17,16 +17,27 @@ def test_dimensions_init(self): self.assertEqual(d3.dims[i], arr3[i]) self.assertEqual(d4.dims[i], 0) + d5 = Dimensions(M = 1) + self.assertEqual(d5.dims[1], 1) + + d6 = Dimensions(Q = -2, Theta = -100) + self.assertEqual(d6.dims[4], -2) + self.assertEqual(d6.dims[3], -100) + + d7 = Dimensions(C = 10, I = 0) + self.assertEqual(d7.dims[5], 10) + self.assertEqual(d7.dims[6], 0) + with self.assertRaises(DimensionsError) as e: d = Dimensions(dims = [1]) with self.assertRaises(DimensionsError) as e: d = Dimensions(dims = [1,1,1,1,1,1,1,1,1,1,1]) with self.assertRaises(DimensionsError) as e: - d = Dimensions(dims = [], kwargs = 1) - with self.assertRaises(DimensionsError) as e: - d = Dimensions(dims = [], kwargs = {'1':'a','2':'b'}) - with self.assertRaises(DimensionsError) as e: - d = Dimensions(dims = [], kwargs = [1,1,1]) + d = Dimensions(dims = ['a','b','c','d','e','f','g']) + with self.assertRaises(KeyError) as e: + d = Dimensions(Mass = 1) + with self.assertRaises(KeyError) as e: + d = Dimensions(time = -10) def test_dimensions_mul(self): arr1 = [1,0,0,0,0,0,0] From fe4a31dd280495d8cd69e56fca34a4e53dc71527 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Fri, 7 Jul 2017 10:39:03 +0100 Subject: [PATCH 049/106] add tests for Dimensions class str representation --- pyqn/tests/test_dimensions.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyqn/tests/test_dimensions.py b/pyqn/tests/test_dimensions.py index c684215..5f49e25 100644 --- a/pyqn/tests/test_dimensions.py +++ b/pyqn/tests/test_dimensions.py @@ -39,6 +39,11 @@ def test_dimensions_init(self): with self.assertRaises(KeyError) as e: d = Dimensions(time = -10) + def test_dimensions_str(self): + self.assertEqual(str(Dimensions(dims = [])),'[dimensionless]') + self.assertEqual(str(Dimensions(dims = [1,2,3,4,5,6,7])),'L.M2.T3.Theta4.Q5.C6.I7') + self.assertEqual(str(Dimensions(dims = [1,0,0,-2,0,1,2])),'L.Theta-2.C.I2') + def test_dimensions_mul(self): arr1 = [1,0,0,0,0,0,0] arr2 = [0,1,1,0,1,0,0] From 4a0b43e33c0b64257d197a794c66b7840f50074b Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Fri, 7 Jul 2017 11:19:39 +0100 Subject: [PATCH 050/106] add test for symbol class init --- pyqn/tests/test_symbol.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 pyqn/tests/test_symbol.py diff --git a/pyqn/tests/test_symbol.py b/pyqn/tests/test_symbol.py new file mode 100644 index 0000000..3fcb500 --- /dev/null +++ b/pyqn/tests/test_symbol.py @@ -0,0 +1,38 @@ +import unittest +from ..symbol import Symbol + +class SymbolCheck(unittest.TestCase): + def test_symbol_init(self): + s = Symbol() + self.assertTrue(s.name == None) + self.assertTrue(s.latex == None) + self.assertTrue(s.html == None) + self.assertTrue(s.definition == None) + + s = Symbol(name = 'NAME') + self.assertTrue(s.name == 'NAME') + self.assertTrue(s.latex == 'NAME') + self.assertTrue(s.html == 'NAME') + self.assertTrue(s.definition == None) + + s = Symbol(name = 'NAME', html = 'HTML') + self.assertTrue(s.name == 'NAME') + self.assertTrue(s.html == 'HTML') + self.assertTrue(s.latex == 'NAME') + self.assertTrue(s.definition == None) + + s = Symbol(definition = 'DEFINITION') + self.assertTrue(s.name == None) + self.assertTrue(s.html == None) + self.assertTrue(s.latex == None) + self.assertTrue(s.definition == 'DEFINITION') + + s = Symbol(name = 'NAME', latex = 'LATEX') + self.assertTrue(s.name == 'NAME') + self.assertTrue(s.html == 'NAME') + self.assertTrue(s.latex == 'LATEX') + self.assertTrue(s.definition == None) + +if __name__ == '__main__': + unittest.main() + From dc505c03f50724ff7be59720fdb31f407d9e3b2d Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Fri, 7 Jul 2017 11:23:16 +0100 Subject: [PATCH 051/106] add str output to symbol in case no name is supplied --- pyqn/symbol.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyqn/symbol.py b/pyqn/symbol.py index 4b7115e..19a58be 100644 --- a/pyqn/symbol.py +++ b/pyqn/symbol.py @@ -49,4 +49,7 @@ def __str__(self): """ Return the string representation of the Symbol, its name attribute. """ - return self.name + if self.name: + return self.name + else: + return '[undefined]' From 8eb3768f39b55e9ad63b1d2d06bcd27212a2a1b3 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Fri, 7 Jul 2017 11:23:37 +0100 Subject: [PATCH 052/106] add test for str representation of symbol class --- pyqn/tests/test_symbol.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pyqn/tests/test_symbol.py b/pyqn/tests/test_symbol.py index 3fcb500..1681a2b 100644 --- a/pyqn/tests/test_symbol.py +++ b/pyqn/tests/test_symbol.py @@ -32,6 +32,12 @@ def test_symbol_init(self): self.assertTrue(s.html == 'NAME') self.assertTrue(s.latex == 'LATEX') self.assertTrue(s.definition == None) + + def test_symbol_str(self): + self.assertTrue(str(Symbol()), '[undefined]') + self.assertTrue(str(Symbol(name='NAME')),'NAME') + self.assertTrue(str(Symbol(latex='LATEX')),'[undefined]') + self.assertTrue(str(Symbol(name='NAME',latex='LATEX')),'NAME') if __name__ == '__main__': unittest.main() From cc6ef6299a71886528289a9729f6227545525c3d Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Fri, 7 Jul 2017 11:36:10 +0100 Subject: [PATCH 053/106] add tests of si_prefixes --- pyqn/tests/test_si.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 pyqn/tests/test_si.py diff --git a/pyqn/tests/test_si.py b/pyqn/tests/test_si.py new file mode 100644 index 0000000..4937e2e --- /dev/null +++ b/pyqn/tests/test_si.py @@ -0,0 +1,28 @@ +import unittest +from ..si import SIPrefix, si_prefixes + +class SICheck(unittest.TestCase): + def test_siprefix_init(self): + pass + + def test_siprefixes(self): + self.assertEqual(si_prefixes['y'].prefix, 'y') + self.assertEqual(si_prefixes['y'].name, 'yocto') + self.assertEqual(si_prefixes['y'].power, -24) + self.assertEqual(si_prefixes['y'].fac, 1e-24) + + self.assertEqual(si_prefixes['μ'].prefix, 'μ') + self.assertEqual(si_prefixes['μ'].name, 'micro') + self.assertEqual(si_prefixes['μ'].power, -6) + self.assertEqual(si_prefixes['μ'].fac, 1e-6) + + self.assertEqual(si_prefixes['M'].prefix, 'M') + self.assertEqual(si_prefixes['M'].name, 'mega') + self.assertEqual(si_prefixes['M'].power, 6) + self.assertEqual(si_prefixes['M'].fac, 1e6) + + def test_si_unit_systems(self): + pass + +if __name__ == '__main__': + unittest.main() From 85cf58e055934e3810257159fdbf59a868cb1d3e Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Fri, 7 Jul 2017 11:40:11 +0100 Subject: [PATCH 054/106] add test for SIPrefix init --- pyqn/tests/test_si.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pyqn/tests/test_si.py b/pyqn/tests/test_si.py index 4937e2e..a55b9ce 100644 --- a/pyqn/tests/test_si.py +++ b/pyqn/tests/test_si.py @@ -3,7 +3,11 @@ class SICheck(unittest.TestCase): def test_siprefix_init(self): - pass + s = SIPrefix('PREFIX','NAME',2.5) + self.assertEqual(s.prefix, 'PREFIX') + self.assertEqual(s.name, 'NAME') + self.assertEqual(s.power, 2.5) + self.assertEqual(s.fac, 10**2.5) def test_siprefixes(self): self.assertEqual(si_prefixes['y'].prefix, 'y') @@ -21,8 +25,5 @@ def test_siprefixes(self): self.assertEqual(si_prefixes['M'].power, 6) self.assertEqual(si_prefixes['M'].fac, 1e6) - def test_si_unit_systems(self): - pass - if __name__ == '__main__': unittest.main() From 398c83b4cb12160cf1aecfe5cd4ebed007dedeb3 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 10 Jul 2017 11:58:08 +0100 Subject: [PATCH 055/106] add test for BaseUnit class --- pyqn/tests/test_base_unit.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 pyqn/tests/test_base_unit.py diff --git a/pyqn/tests/test_base_unit.py b/pyqn/tests/test_base_unit.py new file mode 100644 index 0000000..774c229 --- /dev/null +++ b/pyqn/tests/test_base_unit.py @@ -0,0 +1,27 @@ +import unittest +from ..base_unit import BaseUnit +from ..dimensions import d_length, Dimensions, d_voltage, d_current + +class BaseUnitCheck(unittest.TestCase): + def test_base_unit_init(self): + bu1 = BaseUnit('m', 'metre', 'length', 1., '', 'm', d_length) + self.assertEqual(bu1.stem, 'm') + self.assertEqual(bu1.name, 'metre') + self.assertEqual(bu1.unit_type, 'length') + self.assertEqual(bu1.fac, 1) + self.assertEqual(bu1.description, '') + self.assertEqual(bu1.latex, 'm') + self.assertEqual(bu1.dims, Dimensions(L=1)) + + bu2 = BaseUnit('Ω', 'ohm','electric resistance', 1, '',r'\Omega',d_voltage / d_current) + self.assertEqual(bu2.stem, 'Ω') + self.assertEqual(bu2.name, 'ohm') + self.assertEqual(bu2.unit_type, 'electric resistance') + self.assertEqual(bu2.fac, 1) + self.assertEqual(bu2.description, '') + self.assertEqual(bu2.latex, r'\Omega') + self.assertEqual(bu2.dims, d_voltage/d_current) + +if __name__ == '__main__': + unittest.main() + From 87d72d362be94813ac7329cb4a2d375c009caa10 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 10 Jul 2017 12:36:20 +0100 Subject: [PATCH 056/106] add test for equality between base units --- pyqn/tests/test_base_unit.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pyqn/tests/test_base_unit.py b/pyqn/tests/test_base_unit.py index 774c229..ff585c5 100644 --- a/pyqn/tests/test_base_unit.py +++ b/pyqn/tests/test_base_unit.py @@ -1,6 +1,6 @@ import unittest from ..base_unit import BaseUnit -from ..dimensions import d_length, Dimensions, d_voltage, d_current +from ..dimensions import d_length, Dimensions, d_voltage, d_current, d_time, d_mass class BaseUnitCheck(unittest.TestCase): def test_base_unit_init(self): @@ -21,6 +21,21 @@ def test_base_unit_init(self): self.assertEqual(bu2.description, '') self.assertEqual(bu2.latex, r'\Omega') self.assertEqual(bu2.dims, d_voltage/d_current) + + def test_base_unit_eq(self): + bu1 = BaseUnit('m', 'metre', 'length', 1., '', 'm', d_length) + bu2 = BaseUnit('s', 'second', 'time', 1., '', 's', d_time) + bu3 = BaseUnit('g', 'gram', 'mass', 1.e-3, '', 'g', d_mass) + bu4 = BaseUnit('K', 'kelvin', 'temperature', 1., '', 'K', Dimensions(Theta=1)) + self.assertFalse(bu1 == bu2) + self.assertFalse(bu1 == bu3) + self.assertFalse(bu1 == bu4) + self.assertFalse(bu2 == bu3) + self.assertFalse(bu2 == bu4) + self.assertFalse(bu3 == bu4) + + bu5 = BaseUnit('k', '', '', 1, '', '', Dimensions(dims = [])) + self.assertFalse(bu4 == bu5) if __name__ == '__main__': unittest.main() From e9cdcbb42fcedc0ac31e0c0b4c03530db69c9a45 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 10 Jul 2017 12:38:18 +0100 Subject: [PATCH 057/106] add test for str representation of base units --- pyqn/tests/test_base_unit.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pyqn/tests/test_base_unit.py b/pyqn/tests/test_base_unit.py index ff585c5..4858568 100644 --- a/pyqn/tests/test_base_unit.py +++ b/pyqn/tests/test_base_unit.py @@ -36,6 +36,16 @@ def test_base_unit_eq(self): bu5 = BaseUnit('k', '', '', 1, '', '', Dimensions(dims = [])) self.assertFalse(bu4 == bu5) + + def test_base_unit_str(self): + bu1 = BaseUnit('m', 'metre', 'length', 1., '', 'm', d_length) + bu2 = BaseUnit('s', 'second', 'time', 1., '', 's', d_time) + bu3 = BaseUnit('g', 'gram', 'mass', 1.e-3, '', 'g', d_mass) + bu4 = BaseUnit('K', 'kelvin', 'temperature', 1., '', 'K', Dimensions(Theta=1)) + self.assertEqual(str(bu1), 'm') + self.assertEqual(str(bu2), 's') + self.assertEqual(str(bu3), 'g') + self.assertEqual(str(bu4), 'K') if __name__ == '__main__': unittest.main() From e140da81e1a671d27fe890523c399e72382af79b Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 10 Jul 2017 12:59:17 +0100 Subject: [PATCH 058/106] add SIPrefix pbject comparison function --- pyqn/si.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pyqn/si.py b/pyqn/si.py index 16f8db2..4527020 100644 --- a/pyqn/si.py +++ b/pyqn/si.py @@ -29,6 +29,12 @@ def __init__(self, prefix, name, power): self.name = name self.power = power self.fac = 10**power + + def __eq__(self, other): + if (self.prefix == other.prefix) and (self.power == other.power): + return True + else: + return False # Here are the SI prefixes that we recognise. si_prefixes = { 'y': SIPrefix('y', 'yocto', -24), From 3a79b18057d9ee2d8805e33734d6d3930ac4af67 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 10 Jul 2017 12:59:41 +0100 Subject: [PATCH 059/106] add SIPrefix object comparison tests --- pyqn/tests/test_si.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pyqn/tests/test_si.py b/pyqn/tests/test_si.py index a55b9ce..9bb682c 100644 --- a/pyqn/tests/test_si.py +++ b/pyqn/tests/test_si.py @@ -25,5 +25,9 @@ def test_siprefixes(self): self.assertEqual(si_prefixes['M'].power, 6) self.assertEqual(si_prefixes['M'].fac, 1e6) + def test_siprefix_eq(self): + self.assertTrue(SIPrefix('PREFIX','NAME',2.0) == SIPrefix('PREFIX','',2)) + self.assertFalse(SIPrefix('P','NAME',3) == SIPrefix('P','NAME',-3)) + if __name__ == '__main__': unittest.main() From 16ae6a12d4de5c8ae6c625f64f10724bb67086e1 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 13 Jul 2017 21:44:00 +0100 Subject: [PATCH 060/106] add test for AtomUnit init --- pyqn/tests/test_atom_unit.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 pyqn/tests/test_atom_unit.py diff --git a/pyqn/tests/test_atom_unit.py b/pyqn/tests/test_atom_unit.py new file mode 100644 index 0000000..07a8b36 --- /dev/null +++ b/pyqn/tests/test_atom_unit.py @@ -0,0 +1,23 @@ +import unittest +from ..atom_unit import AtomUnit +from ..base_unit import BaseUnit, base_units +from ..dimensions import d_length, d_energy +from ..si import SIPrefix + +class AtomUnitCheck(unittest.TestCase): + def test_atom_unit_init(self): + au1 = AtomUnit('m', BaseUnit('m', 'metre', 'length', 1., '', 'm', d_length), -2) + self.assertEqual(au1.base_unit, BaseUnit('m', 'metre', 'length', 1., '', 'm', d_length)) + self.assertEqual(au1.exponent, -2) + self.assertEqual(au1.si_prefix, SIPrefix('m', 'milli', -3)) + self.assertEqual(au1.si_fac, 1000000.0) + + def test_atom_unit_parse(self): + au1 = AtomUnit.parse('μJ') + self.assertEqual(au1.base_unit, BaseUnit('J','','',1,'','',d_energy)) + self.assertEqual(au1.exponent, 1) + self.assertEqual(au1.si_prefix, SIPrefix('μ', 'micro', -6)) + self.assertEqual(au1.si_fac, 1e-6) + +if __name__ == '__main__': + unittest.main() From 778981582274ba91fd10af60cfb8bca01c9c631e Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 13 Jul 2017 21:51:51 +0100 Subject: [PATCH 061/106] add test for pow of AtomUnit --- pyqn/tests/test_atom_unit.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pyqn/tests/test_atom_unit.py b/pyqn/tests/test_atom_unit.py index 07a8b36..72b8666 100644 --- a/pyqn/tests/test_atom_unit.py +++ b/pyqn/tests/test_atom_unit.py @@ -19,5 +19,13 @@ def test_atom_unit_parse(self): self.assertEqual(au1.si_prefix, SIPrefix('μ', 'micro', -6)) self.assertEqual(au1.si_fac, 1e-6) + def test_atom_unit_pow(self): + au1 = AtomUnit.parse('mm') + au2 = au1 ** 3 + self.assertEqual(au2.base_unit, BaseUnit('m', 'metre', 'length', 1., '', 'm', d_length), -2) + self.assertEqual(au2.exponent, 3) + self.assertEqual(au2.si_prefix, SIPrefix('m', 'milli', -3)) + self.assertEqual(au2.si_fac, 1e-9) + if __name__ == '__main__': unittest.main() From c4a204648c0267940650d0732ebd6ed924352645 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 10 Jul 2017 15:40:24 +0100 Subject: [PATCH 062/106] fix quantity class to provide result to __pow__ function using Quantity with .sd = None --- pyqn/quantity.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pyqn/quantity.py b/pyqn/quantity.py index 7aca4f4..9459c3e 100644 --- a/pyqn/quantity.py +++ b/pyqn/quantity.py @@ -294,9 +294,11 @@ def __rtruediv__(self, other): return self.__truediv__(other) def __pow__(self, power): - return Quantity(value = self.value**power, - units = self.units**power, - sd = self.value**power*math.hypot(self.sd/self.value, self.sd/self.value)) + new_quantity = Quantity(value = self.value**power, + units = self.units**power) + if self.sd: + new_quantity.sd = self.value**power*math.hypot(self.sd/self.value, self.sd/self.value) + return new_quantity @classmethod def parse(self, s_quantity, name=None, units=None, sd=None, From 06866cdcfdcf90355082b1742334186dd286a11c Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 10 Jul 2017 16:05:45 +0100 Subject: [PATCH 063/106] add Quantity.parse function tests --- pyqn/tests/test_quantity.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/pyqn/tests/test_quantity.py b/pyqn/tests/test_quantity.py index 453b169..d1605bc 100644 --- a/pyqn/tests/test_quantity.py +++ b/pyqn/tests/test_quantity.py @@ -1,12 +1,29 @@ import unittest from ..quantity import Quantity, QuantityError from ..dimensions import Dimensions, d_energy -from ..units import UnitsError +from ..units import UnitsError, Units class QuantityManipulations(unittest.TestCase): def test_quantity_init(self): pass + def test_quantity_parse(self): + q1 = Quantity.parse("a = 10 m/s") + q2 = Quantity.parse("lambda = 300.15(10) nm") + q3 = Quantity.parse("1e5 J") + + self.assertEqual(q1.name, 'a') + self.assertEqual(q1.value, 10) + self.assertEqual(q1.units, Units('m.s-1')) + + self.assertEqual(q2.name, 'lambda') + self.assertEqual(q2.value, 300.15) + self.assertEqual(q2.sd, 0.1) + self.assertEqual(q2.units, Units('nm')) + + self.assertEqual(q3.value, 1e5) + self.assertEqual(q3.units, Units('J')) + def test_quantity_multiplication(self): q1 = Quantity(value=22.4,units='m/s') q2 = Quantity(value=2,units='s') @@ -88,4 +105,4 @@ def test_quantity_html(self): self.assertEqual(q4.html_str, '22.4 m s-1') if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() From b43d2742adcb28f79439ae0fcf3d4d536773d088 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 12 Jul 2017 10:13:25 +0100 Subject: [PATCH 064/106] remove sd parameter in favour of speed, adjust all algebraic operations to use only numpy predefined functions --- pyqn/qn_array_two.py | 126 ++++++++++--------------------------------- 1 file changed, 28 insertions(+), 98 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index e347b64..8f79e6a 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -9,7 +9,7 @@ def __str__(self): return self.error_str class qnArrayTwo(np.ndarray): - def __new__(cls, input_array, info=None, units=None, sd=None): + def __new__(cls, input_array, info=None, units='1', sd=None): """ Initialises a qnArray as a child class derived from the numpy ndarray. """ @@ -19,16 +19,7 @@ def __new__(cls, input_array, info=None, units=None, sd=None): if type(units) is str: obj.units = Units(units) #records units as Unit class elif type(units) is Units: - obj.units = units - - # checks for length of standard deviation array - if sd is not None: - if len(sd) != len(input_array): - raise qnArrayTwoError("Standard deviation array must be of the same length as values array") - obj.sd = sd - else: - obj.sd = np.zeros(len(input_array)) - + obj.units = units return obj def __array_finalize__(self, obj): @@ -40,103 +31,42 @@ def __add__(self, other): qnArrayTwo or adding another anArrayTwo to the current array """ if type(other) is qnArrayTwo: - if len(other) != len(self): - raise qnArrayTwoError("Inconsistent array lengths") - v = [] - sd_arr = [] - for i in range(len(self)): - temp_q = Quantity(value = self[i], units = self.units, sd = self.sd[i]) + Quantity(value = other[i], units = other.units, sd = other.sd[i]) - v.append(temp_q.value) - sd_arr.append(temp_q.sd) - return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) + if self.units != other.units: + raise qnArrayTwoError('Units of the two array must be compatible') + return qnArrayTwo(super(qnArrayTwo, self).__add__(super(qnArrayTwo, other)), units = self.units) if type(other) is Quantity: - v = [] - sd_arr = [] - for i in range(len(self)): - temp_q = Quantity(value=self[i], units=self.units, sd = self.sd[i]) + other - v.append(temp_q.value) - sd_arr.append(temp_q.sd) - return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) - else: - raise qnArrayTwoError("Can only add two qnArray objects or a qnArray with Quantity") - + if self.units != other.units: + raise qnArrayTwoError('Units of the two array must be compatible') + return qnArrayTwo(super(qnArrayTwo, self).__add__(other.value), units = self.units) + return qnArrayTwo(super(qnArrayTwo, self).__add__(other), units = self.units) + def __sub__(self, other): if type(other) is qnArrayTwo: - if len(other) != len(self): - raise qnArrayTwoError("Inconsistent array lengths") - v = [] - sd_arr = [] - for i in range(len(self)): - temp_q = Quantity(value = self[i], units = self.units, sd = self.sd[i]) - Quantity(value = other[i], units = other.units, sd = other.sd[i]) - v.append(temp_q.value) - sd_arr.append(temp_q.sd) - return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) - + if self.units != other.units: + raise qnArrayTwoError('Units of the two array must be compatible') + return qnArrayTwo(super(qnArrayTwo, self).__sub__(super(qnArrayTwo, other)), units = self.units) if type(other) is Quantity: - v = [] - sd_arr = [] - for i in range(len(self)): - temp_q = Quantity(value=self[i], units=self.units, sd = self.sd[i]) - other - v.append(temp_q.value) - sd_arr.append(temp_q.sd) - return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) - else: - raise qnArrayTwoError("Can only subtract two qnArray objects or a qnArray with Quantity") - + if self.units != other.units: + raise qnArrayTwoError('Units of the two array must be compatible') + return qnArrayTwo(super(qnArrayTwo, self).__sub__(other.value), units = self.units) + return qnArrayTwo(super(qnArrayTwo, self).__sub__(other), units = self.units) + def __mul__(self, other): if type(other) is qnArrayTwo: - if len(other) != len(self): - raise qnArrayTwoError("Inconsistent array lengths") - v = [] - sd_arr = [] - for i in range(len(self)): - temp_q = Quantity(value = self[i], units = self.units, sd = self.sd[i]) * Quantity(value = other[i], units = other.units, sd = other.sd[i]) - v.append(temp_q.value) - sd_arr.append(temp_q.sd) - return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) - + return qnArrayTwo(super(qnArrayTwo, self).__mul__(super(qnArrayTwo, other)), units = self.units * other.units) if type(other) is Quantity: - v = [] - sd_arr = [] - for i in range(len(self)): - temp_q = Quantity(value=self[i], units=self.units, sd = self.sd[i]) * other - v.append(temp_q.value) - sd_arr.append(temp_q.sd) - return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) - else: - raise qnArrayTwoError("Can only multiply two qnArray objects or a qnArray with Quantity") - + return qnArrayTwo(super(qnArrayTwo, self).__mul__(other.value), units = self.units * other.units) + return qnArrayTwo(super(qnArrayTwo, self).__mul__(other), units = self.units) + def __truediv__(self, other): if type(other) is qnArrayTwo: - if len(other) != len(self): - raise qnArrayTwoError("Inconsistent array lengths") - v = [] - sd_arr = [] - for i in range(len(self)): - temp_q = Quantity(value = self[i], units = self.units, sd = self.sd[i]) / Quantity(value = other[i], units = other.units, sd = other.sd[i]) - v.append(temp_q.value) - sd_arr.append(temp_q.sd) - return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) - + return qnArrayTwo(super(qnArrayTwo, self).__truediv__(super(qnArrayTwo, other)), units = self.units / other.units) if type(other) is Quantity: - v = [] - sd_arr = [] - for i in range(len(self)): - temp_q = Quantity(value=self[i], units=self.units, sd = self.sd[i]) / other - v.append(temp_q.value) - sd_arr.append(temp_q.sd) - return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) - else: - raise qnArrayTwoError("Can only divide two qnArray objects or a qnArray with Quantity") - - def __pow__(self, other): - v = [] - sd_arr = [] - for i in range(len(self)): - temp_q = Quantity(value=self[i], units = self.units, sd = self.sd[i]) ** other - v.append(temp_q.value) - sd_arr.append(temp_q.sd) - return qnArrayTwo(v, units = temp_q.units, sd = sd_arr) + return qnArrayTwo(super(qnArrayTwo, self).__truediv__(other.value), units = self.units / other.units) + return qnArrayTwo(super(qnArrayTwo, self).__truediv__(other), units = self.units) + + def __pow__(self, power): + return qnArrayTwo(super(qnArrayTwo, self).__pow__(power), units = self.units ** power) #def __eq__(self, other): # if all(self == other) and (self.units == other.units) and (self.sd == other.sd): From a7a6a9b01d0d4f573d873a903021556b19e42f46 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 12 Jul 2017 10:13:51 +0100 Subject: [PATCH 065/106] adjust tests to not include sd parameter in the qnArrayTwo class initialisation --- pyqn/tests/test_qn_array_two.py | 68 +++++++++------------------------ 1 file changed, 18 insertions(+), 50 deletions(-) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index 1a98739..fb6e307 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -11,64 +11,50 @@ def test_qn_array_two_init(self): self.assertEqual(qnarr1.units, Units('m')) for i in range(len(vals1)): self.assertEqual(qnarr1[i], vals1[i]) - self.assertEqual(qnarr1.sd[i], 0) vals2 = [-10,-20,-30,0,5] - sd2 = [0.1,0.2,0.3,0.4,0.1] - qnarr2 = qnArrayTwo(vals2, units = 'J', sd = sd2) + qnarr2 = qnArrayTwo(vals2, units = 'J') self.assertEqual(qnarr2.units, Units('J')) for i in range(len(vals2)): self.assertEqual(qnarr2[i], vals2[i]) - self.assertEqual(qnarr2.sd[i], sd2[i]) - - with self.assertRaises(qnArrayTwoError) as e: - qnarr = qnArrayTwo(vals2, units='m', sd = vals1) def test_qn_array_two_add(self): vals1 = [1,2,3,4] - sd1 = [0.1, 0.2, 0.3, 0.1] - qnarr1 = qnArrayTwo(vals1,units='m',sd=sd1) + qnarr1 = qnArrayTwo(vals1,units='m') vals2 = [2,3,4,1] - sd2 = [0.2, 0.1, 0.2, 0.1] - qnarr2 = qnArrayTwo(vals2, units='m', sd=sd2) + qnarr2 = qnArrayTwo(vals2, units='m') qnarr3 = qnarr1 + qnarr2 + self.assertEqual(qnarr3.units, qnarr1.units) for i in range(len(vals2)): self.assertEqual(qnarr3[i], vals1[i]+vals2[i]) - self.assertAlmostEqual(qnarr3.sd[i], np.sqrt(sd1[i]**2 + sd2[i]**2)) vals3 = [1,1,1] qnarr3 = qnArrayTwo(vals3, units='m') - with self.assertRaises(qnArrayTwoError) as e: + with self.assertRaises(ValueError) as e: qnarr = qnarr1 + qnarr3 q1 = Quantity(value = 10, units = 'm') - qnarr4 = qnarr1+q1 + qnarr4 = qnarr1 + q1 self.assertEqual(qnarr4.units, Units('m')) for i in range(len(qnarr4)): self.assertEqual(qnarr4[i], qnarr1[i]+10) - - with self.assertRaises(qnArrayTwoError) as e: - qnarr = qnarr1 + 2 def test_qn_array_two_sub(self): vals1 = [1,2,3,4] - sd1 = [0.1, 0.2, 0.3, 0.1] - qnarr1 = qnArrayTwo(vals1,units='m',sd=sd1) + qnarr1 = qnArrayTwo(vals1,units='m') vals2 = [2,3,4,1] - sd2 = [0.2, 0.1, 0.2, 0.1] - qnarr2 = qnArrayTwo(vals2, units='m',sd=sd2) + qnarr2 = qnArrayTwo(vals2, units='m') qnarr3 = qnarr1 - qnarr2 for i in range(len(vals2)): self.assertEqual(qnarr3[i], vals1[i]-vals2[i]) - self.assertAlmostEqual(qnarr3.sd[i], np.sqrt(sd1[i]**2 + sd2[i]**2)) vals3 = [1,1,1] qnarr3 = qnArrayTwo(vals3, units='m') - with self.assertRaises(qnArrayTwoError) as e: + with self.assertRaises(ValueError) as e: qnarr = qnarr1 - qnarr3 q1 = Quantity(value = 10, units = 'm') @@ -77,27 +63,21 @@ def test_qn_array_two_sub(self): for i in range(len(qnarr4)): self.assertEqual(qnarr4[i], qnarr1[i]-10) - with self.assertRaises(qnArrayTwoError) as e: - qnarr = qnarr1 - 2 - def test_qn_array_two_mul(self): vals1 = [1,2,3,4] - sd1 = [0.1, 0.2, 0.3, 0.1] - qnarr1 = qnArrayTwo(vals1,units='m',sd=sd1) + qnarr1 = qnArrayTwo(vals1,units='m') vals2 = [2,3,4,1] - sd2 = [0.2, 0.1, 0.2, 0.1] - qnarr2 = qnArrayTwo(vals2, units='s',sd=sd2) + qnarr2 = qnArrayTwo(vals2, units='s') qnarr3 = qnarr1 * qnarr2 self.assertEqual(qnarr3.units, Units('m.s')) for i in range(len(vals2)): self.assertEqual(qnarr3[i], vals1[i]*vals2[i]) - self.assertAlmostEqual(qnarr3.sd[i], qnarr3[i]*np.sqrt((sd1[i]/vals1[i])**2+(sd2[i]/vals2[i])**2)) vals3 = [1,1,1] qnarr3 = qnArrayTwo(vals3, units='m') - with self.assertRaises(qnArrayTwoError) as e: + with self.assertRaises(ValueError) as e: qnarr = qnarr1 * qnarr3 q1 = Quantity(value = 10, units = 'J') @@ -106,27 +86,21 @@ def test_qn_array_two_mul(self): for i in range(len(qnarr4)): self.assertEqual(qnarr4[i], qnarr1[i]*10) - with self.assertRaises(qnArrayTwoError) as e: - qnarr = qnarr1 * 2 - def test_qn_array_two_mul(self): vals1 = [1,2,3,4] - sd1 = [0.1, 0.2, 0.3, 0.1] - qnarr1 = qnArrayTwo(vals1,units='m',sd=sd1) + qnarr1 = qnArrayTwo(vals1,units='m') vals2 = [2,3,4,1] - sd2 = [0.2, 0.1, 0.2, 0.1] - qnarr2 = qnArrayTwo(vals2, units='s',sd=sd2) + qnarr2 = qnArrayTwo(vals2, units='s') qnarr3 = qnarr1 / qnarr2 self.assertEqual(qnarr3.units, Units('m.s-1')) for i in range(len(vals2)): self.assertEqual(qnarr3[i], vals1[i]/vals2[i]) - self.assertAlmostEqual(qnarr3.sd[i], qnarr3[i]*np.sqrt((sd1[i]/vals1[i])**2+(sd2[i]/vals2[i])**2)) vals3 = [1,1,1] qnarr3 = qnArrayTwo(vals3, units='m') - with self.assertRaises(qnArrayTwoError) as e: + with self.assertRaises(ValueError) as e: qnarr = qnarr1 / qnarr3 q1 = Quantity(value = 10, units = 'J') @@ -135,19 +109,14 @@ def test_qn_array_two_mul(self): for i in range(len(qnarr4)): self.assertEqual(qnarr4[i], qnarr1[i]/10) - with self.assertRaises(qnArrayTwoError) as e: - qnarr = qnarr1 / 2 - def test_qn_array_two_pow(self): vals1 = [1,2,3,4] - sd1 = [0.1, 0.2, 0.3, 0.4] - qnarr1 = qnArrayTwo(vals1, units = 'm', sd = sd1) + qnarr1 = qnArrayTwo(vals1, units = 'm') qnarr2 = qnarr1 ** 2 self.assertEqual(qnarr2.units, Units('m2')) for i in range(len(vals1)): self.assertEqual(qnarr2[i], vals1[i]**2) - self.assertAlmostEqual(qnarr2.sd[i], qnarr2[i]*np.sqrt(2.0*(sd1[i]/vals1[i])**2)) #def test_qn_array_eq(self): # qnarr1 = qnArrayTwo([1,1,1],units = 'm', sd = [0.1,0.1,0.1]) @@ -172,10 +141,9 @@ def test_qn_array_two_pow(self): def test_qn_array_two_html(self): vals = [1,2,3,4] - sd = [0.1,0.2,0.3,0.4] - qnarr = qnArrayTwo(vals, units = 'm', sd = sd) + qnarr = qnArrayTwo(vals, units = 'm') - self.assertEqual(qnarr.html_str, '1 ± 0.1 m, 2 ± 0.2 m, 3 ± 0.3 m, 4 ± 0.4 m') + #self.assertEqual(qnarr.html_str, '1 m, 2 m, 3 m, 4 m') if __name__ == '__main__': unittest.main() From 79b9ace31d358e390ce6a172462afc8a91454a38 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 12 Jul 2017 11:14:41 +0100 Subject: [PATCH 066/106] add radd, rsub, rmul, and rtruediv functions to qnArrayTwo class --- pyqn/qn_array_two.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index 8f79e6a..7bc1541 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -40,6 +40,9 @@ def __add__(self, other): return qnArrayTwo(super(qnArrayTwo, self).__add__(other.value), units = self.units) return qnArrayTwo(super(qnArrayTwo, self).__add__(other), units = self.units) + def __radd__(self, other): + return self.__add__(other) + def __sub__(self, other): if type(other) is qnArrayTwo: if self.units != other.units: @@ -51,12 +54,26 @@ def __sub__(self, other): return qnArrayTwo(super(qnArrayTwo, self).__sub__(other.value), units = self.units) return qnArrayTwo(super(qnArrayTwo, self).__sub__(other), units = self.units) + def __rsub__(self, other): + if type(other) is qnArrayTwo: + if self.units != other.units: + raise qnArrayTwoError('Units of the two array must be compatible') + return qnArrayTwo(super(qnArrayTwo, self).__rsub__(super(qnArrayTwo, other)), units = self.units) + if type(other) is Quantity: + if self.units != other.units: + raise qnArrayTwoError('Units of the two array must be compatible') + return qnArrayTwo(super(qnArrayTwo, self).__rsub__(other.value), units = self.units) + return qnArrayTwo(super(qnArrayTwo, self).__rsub__(other), units = self.units) + def __mul__(self, other): if type(other) is qnArrayTwo: return qnArrayTwo(super(qnArrayTwo, self).__mul__(super(qnArrayTwo, other)), units = self.units * other.units) if type(other) is Quantity: return qnArrayTwo(super(qnArrayTwo, self).__mul__(other.value), units = self.units * other.units) return qnArrayTwo(super(qnArrayTwo, self).__mul__(other), units = self.units) + + def __rmul__(self, other): + return self.__mul__(other) def __truediv__(self, other): if type(other) is qnArrayTwo: @@ -65,6 +82,13 @@ def __truediv__(self, other): return qnArrayTwo(super(qnArrayTwo, self).__truediv__(other.value), units = self.units / other.units) return qnArrayTwo(super(qnArrayTwo, self).__truediv__(other), units = self.units) + def __rtruediv__(self, other): + if type(other) is qnArrayTwo: + return qnArrayTwo(super(qnArrayTwo, self).__rtruediv__(super(qnArrayTwo, other)), units = other.units / self.units) + if type(other) is Quantity: + return qnArrayTwo(super(qnArrayTwo, self).__rtruediv__(other.value), units = other.units / self.units) + return qnArrayTwo(super(qnArrayTwo, self).__rtruediv__(other), units = Units('1') / self.units) + def __pow__(self, power): return qnArrayTwo(super(qnArrayTwo, self).__pow__(power), units = self.units ** power) From ead80190786d23d4b2f6e34a81869c8cb0196d0c Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 12 Jul 2017 11:16:03 +0100 Subject: [PATCH 067/106] add possiblity to add, divide, multiply, and subtract by qnArrayTwo objects --- pyqn/quantity.py | 80 +++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/pyqn/quantity.py b/pyqn/quantity.py index 9459c3e..99b47e2 100644 --- a/pyqn/quantity.py +++ b/pyqn/quantity.py @@ -198,20 +198,24 @@ def __add__(self, other): are propagated, but assumed to be uncorrelated. """ - - if type(other) != Quantity: - raise TypeError - if self.value is None or other.value is None: - raise ValueError - if self.units != other.units: - raise UnitsError('Can\'t add two quantities with different' + if type(other) is Quantity: + if self.value is None or other.value is None: + raise ValueError + if self.units != other.units: + raise UnitsError('Can\'t add two quantities with different' ' units: %s and %s' % (self.units, other.units)) - if self.sd is None or other.sd is None: - sd = None + if self.sd is None or other.sd is None: + sd = None + else: + sd = math.hypot(self.sd, other.sd) + return Quantity(value=self.value+other.value, units=self.units, sd=sd) else: - sd = math.hypot(self.sd, other.sd) - return Quantity(value=self.value+other.value, units=self.units, sd=sd) - + try: + result = other.__radd__(self) + except TypeError: + print('These objects are not compatible') + return result + def __sub__(self, other): """ Subtract two Quantity objects; they must have the same units. Errors @@ -219,18 +223,23 @@ def __sub__(self, other): """ - if type(other) != Quantity: - raise TypeError - if self.value is None or other.value is None: - raise ValueError - if self.units != other.units: - raise UnitsError('Can\'t subtract two quantities with different' + if type(other) is Quantity: + if self.value is None or other.value is None: + raise ValueError + if self.units != other.units: + raise UnitsError('Can\'t subtract two quantities with different' ' units: %s and %s' % (self.units, other.units)) - if self.sd is None or other.sd is None: - sd = None + if self.sd is None or other.sd is None: + sd = None + else: + sd = math.hypot(self.sd, other.sd) + return Quantity(value=self.value-other.value, units=self.units, sd=sd) else: - sd = math.hypot(self.sd, other.sd) - return Quantity(value=self.value-other.value, units=self.units, sd=sd) + try: + result = other.__rsub__(self) + except TypeError: + print('These objects are not compatible') + return result def __mul__(self, other): """ @@ -267,19 +276,8 @@ def __truediv__(self, other): propagated, but assumed to be uncorrelated. """ - - if self.value is None: - raise ValueError - if type(other) in (int, float): - if self.sd is None: - sd = None - else: - sd = abs(other) / self.sd - return Quantity(value=self.value/other, units=self.units, sd=sd) - else: - #if type(other) != Quantity: - # raise TypeError - if other.value is None: + if type(other) is Quantity: + if (self.value is None) or other.value is None: raise ValueError value = self.value / other.value if not self.sd or not other.sd: @@ -289,6 +287,18 @@ def __truediv__(self, other): other.sd/other.value) units = self.units / other.units return Quantity(value=value, units=units, sd=sd) + if type(other) in (int, float): + if self.sd is None: + sd = None + else: + sd = abs(other) / self.sd + return Quantity(value=self.value/other, units=self.units, sd=sd) + else: + try: + result = other.__rtruediv__(self) + except TypeError: + print('These objects are not compatible') + return result def __rtruediv__(self, other): return self.__truediv__(other) From d3eafcfacc57e838f0b4c8642c82707e80240aa1 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 12 Jul 2017 11:16:40 +0100 Subject: [PATCH 068/106] add tests for all combinations of algebraic operations --- pyqn/tests/test_qn_array_two.py | 36 +++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index fb6e307..fd63627 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -37,9 +37,18 @@ def test_qn_array_two_add(self): q1 = Quantity(value = 10, units = 'm') qnarr4 = qnarr1 + q1 + qnarr5 = q1 + qnarr1 + qnarr6 = qnarr2 + 15 + qnarr7 = 15 + qnarr2 self.assertEqual(qnarr4.units, Units('m')) + self.assertEqual(qnarr5.units, Units('m')) + self.assertEqual(qnarr6.units, Units('m')) + self.assertEqual(qnarr7.units, Units('m')) for i in range(len(qnarr4)): self.assertEqual(qnarr4[i], qnarr1[i]+10) + self.assertEqual(qnarr5[i], 10+qnarr1[i]) + self.assertEqual(qnarr6[i], qnarr2[i]+15) + self.assertEqual(qnarr7[i], 15+qnarr2[i]) def test_qn_array_two_sub(self): vals1 = [1,2,3,4] @@ -59,9 +68,18 @@ def test_qn_array_two_sub(self): q1 = Quantity(value = 10, units = 'm') qnarr4 = qnarr1 - q1 + qnarr5 = q1 - qnarr1 + qnarr6 = qnarr2 - 15 + qnarr7 = 15 - qnarr2 self.assertEqual(qnarr4.units, Units('m')) + self.assertEqual(qnarr5.units, Units('m')) + self.assertEqual(qnarr6.units, Units('m')) + self.assertEqual(qnarr7.units, Units('m')) for i in range(len(qnarr4)): self.assertEqual(qnarr4[i], qnarr1[i]-10) + self.assertEqual(qnarr5[i], 10-qnarr1[i]) + self.assertEqual(qnarr6[i], qnarr2[i]-15) + self.assertEqual(qnarr7[i], 15-qnarr2[i]) def test_qn_array_two_mul(self): vals1 = [1,2,3,4] @@ -82,9 +100,18 @@ def test_qn_array_two_mul(self): q1 = Quantity(value = 10, units = 'J') qnarr4 = qnarr1 * q1 + qnarr5 = q1 * qnarr1 + qnarr6 = qnarr2 * 15 + qnarr7 = 15 * qnarr2 self.assertEqual(qnarr4.units, Units('m.J')) + self.assertEqual(qnarr5.units, Units('m.J')) + self.assertEqual(qnarr6.units, Units('s')) + self.assertEqual(qnarr7.units, Units('s')) for i in range(len(qnarr4)): self.assertEqual(qnarr4[i], qnarr1[i]*10) + self.assertEqual(qnarr5[i], 10*qnarr1[i]) + self.assertEqual(qnarr6[i], qnarr2[i]*15) + self.assertEqual(qnarr7[i], 15*qnarr2[i]) def test_qn_array_two_mul(self): vals1 = [1,2,3,4] @@ -105,9 +132,18 @@ def test_qn_array_two_mul(self): q1 = Quantity(value = 10, units = 'J') qnarr4 = qnarr1 / q1 + qnarr5 = q1 / qnarr1 + qnarr6 = qnarr2 / 15 + qnarr7 = 15 / qnarr2 self.assertEqual(qnarr4.units, Units('m.J-1')) + self.assertEqual(qnarr5.units, Units('m-1.J')) + self.assertEqual(qnarr6.units, Units('s')) + self.assertEqual(qnarr7.units, Units('s-1')) for i in range(len(qnarr4)): self.assertEqual(qnarr4[i], qnarr1[i]/10) + self.assertEqual(qnarr5[i], 10/qnarr1[i]) + self.assertEqual(qnarr6[i], qnarr2[i]/15) + self.assertEqual(qnarr7[i], 15/qnarr2[i]) def test_qn_array_two_pow(self): vals1 = [1,2,3,4] From ca2a490f286bfa48814c1ee833bd1ebcfb62b1a9 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 12 Jul 2017 11:23:59 +0100 Subject: [PATCH 069/106] add __eq__ function to qnArrayTwo --- pyqn/qn_array_two.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index 7bc1541..dc1a8f8 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -92,11 +92,11 @@ def __rtruediv__(self, other): def __pow__(self, power): return qnArrayTwo(super(qnArrayTwo, self).__pow__(power), units = self.units ** power) - #def __eq__(self, other): - # if all(self == other) and (self.units == other.units) and (self.sd == other.sd): - # return True - # else: - # return False + def __eq__(self, other): + if all(super(qnArrayTwo, self).__eq__(super(qnArrayTwo, other))) and (self.units == other.units): + return True + else: + return False @property def html_str(self): From a4d414f43aa7b2b8d9e185e4fec346e6c5302951 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 12 Jul 2017 11:24:12 +0100 Subject: [PATCH 070/106] add tests for __eq__ function --- pyqn/tests/test_qn_array_two.py | 40 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index fd63627..64e4701 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -154,26 +154,26 @@ def test_qn_array_two_pow(self): for i in range(len(vals1)): self.assertEqual(qnarr2[i], vals1[i]**2) - #def test_qn_array_eq(self): - # qnarr1 = qnArrayTwo([1,1,1],units = 'm', sd = [0.1,0.1,0.1]) - # qnarr2 = qnArrayTwo([1,1,1],units = 'm') - # qnarr3 = qnArrayTwo([1,2,3],units = 'm', sd = [0.1,0.1,0.1]) - # qnarr4 = qnArrayTwo([1,2,3],units = 'J', sd = [0.1,0.1,0.1]) - # qnarr5 = qnArrayTwo([1.0,1.0,1.0],units = Units('m'), sd = [0,0,0]) - - # self.assertFalse(qnarr1 == qnarr2) - # self.assertFalse(qnarr1 == qnarr3) - # self.assertFalse(qnarr1 == qnarr4) - # self.assertFalse(qnarr1 == qnarr5) - - # self.assertFalse(qnarr2 == qnarr3) - # self.assertFalse(qnarr2 == qnarr4) - # self.assertTrue(qnarr2 == qnarr5) - - # self.assertFalse(qnarr3 == qnarr4) - # self.assertFalse(qnarr3 == qnarr5) - - # self.assertFalse(qnarr4 == qnarr5) + def test_qn_array_eq(self): + qnarr1 = qnArrayTwo([1,1,1],units = 'm') + qnarr2 = qnArrayTwo([1,1,1],units = Units('J')) + qnarr3 = qnArrayTwo([1,2,3],units = 'm') + qnarr4 = qnArrayTwo([1,2,3],units = 'J') + qnarr5 = qnArrayTwo([1.0,1.0,1.0],units = Units('m')) + + self.assertFalse(qnarr1 == qnarr2) + self.assertFalse(qnarr1 == qnarr3) + self.assertFalse(qnarr1 == qnarr4) + self.assertTrue(qnarr1 == qnarr5) + + self.assertFalse(qnarr2 == qnarr3) + self.assertFalse(qnarr2 == qnarr4) + self.assertFalse(qnarr2 == qnarr5) + + self.assertFalse(qnarr3 == qnarr4) + self.assertFalse(qnarr3 == qnarr5) + + self.assertFalse(qnarr4 == qnarr5) def test_qn_array_two_html(self): vals = [1,2,3,4] From cc6906c4339d7a407d2ae9614d956c7cf8ce828c Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 12 Jul 2017 11:41:59 +0100 Subject: [PATCH 071/106] fix html_str functions results to not include standard deviation and adjust tests accordingly --- pyqn/qn_array_two.py | 5 ++++- pyqn/tests/test_qn_array_two.py | 23 ++++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index dc1a8f8..ab0dd71 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -98,9 +98,12 @@ def __eq__(self, other): else: return False + #def __neq__(self, other): + # return all(not self.__eq__(other)) + @property def html_str(self): html_chunks = [] for i in range(len(self)): - html_chunks.append(Quantity(value=self[i],units = self.units, sd = self.sd[i]).html_str) + html_chunks.append('{} {}'.format(self[i],self.units)) return ', '.join(html_chunks) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index 64e4701..d0ab4ec 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -174,12 +174,33 @@ def test_qn_array_eq(self): self.assertFalse(qnarr3 == qnarr5) self.assertFalse(qnarr4 == qnarr5) + +# def test_qn_array_neq(self): +# qnarr1 = qnArrayTwo([1,1,1],units = 'm') +# qnarr2 = qnArrayTwo([1,1,1],units = Units('J')) +# qnarr3 = qnArrayTwo([1,2,3],units = 'm') +# qnarr4 = qnArrayTwo([1,2,3],units = 'J') +# qnarr5 = qnArrayTwo([1.0,1.0,1.0],units = Units('m')) +# +# self.assertTrue(qnarr1 != qnarr2) +# self.assertTrue(qnarr1 != qnarr3) +# self.assertTrue(qnarr1 != qnarr4) +# self.assertFalse(qnarr1 != qnarr5) +# +# self.assertTrue(qnarr2 != qnarr3) +# self.assertTrue(qnarr2 != qnarr4) +# self.assertTrue(qnarr2 != qnarr5) +# +# self.assertTrue(qnarr3 != qnarr4) +# self.assertTrue(qnarr3 != qnarr5) +# +# self.assertTrue(qnarr4 != qnarr5) def test_qn_array_two_html(self): vals = [1,2,3,4] qnarr = qnArrayTwo(vals, units = 'm') - #self.assertEqual(qnarr.html_str, '1 m, 2 m, 3 m, 4 m') + self.assertEqual(qnarr.html_str, '1 m, 2 m, 3 m, 4 m') if __name__ == '__main__': unittest.main() From de2bb0c6ec3a31d3006f3f7941545b1f9632d3ee Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 13 Jul 2017 10:40:45 +0100 Subject: [PATCH 072/106] add initialisation of Quantity object standard deviation to 0 if None provided --- pyqn/quantity.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyqn/quantity.py b/pyqn/quantity.py index 99b47e2..72aed73 100644 --- a/pyqn/quantity.py +++ b/pyqn/quantity.py @@ -62,7 +62,10 @@ def __init__(self, name=None, latex=None, html=None, value=None, Symbol.__init__(self, name, latex, html, definition) self.value = value - self.sd = sd + if sd is None: + self.sd = 0 + else: + self.sd = sd if units is None: self.units = Units([]) else: From ca3eeca2a20ed727bdf2656c75aca268295ef729 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 13 Jul 2017 10:43:24 +0100 Subject: [PATCH 073/106] add standard deviation initialisation and calculation when adding/subtracting qn arrays --- pyqn/qn_array_two.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index ab0dd71..ef555b0 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -15,6 +15,10 @@ def __new__(cls, input_array, info=None, units='1', sd=None): """ obj = np.asarray(input_array).view(cls) obj.info = info + if sd is None: + obj.sd = np.zeros(len(input_array)) + else: + obj.sd = np.array(sd) if type(units) is str: obj.units = Units(units) #records units as Unit class @@ -33,12 +37,12 @@ def __add__(self, other): if type(other) is qnArrayTwo: if self.units != other.units: raise qnArrayTwoError('Units of the two array must be compatible') - return qnArrayTwo(super(qnArrayTwo, self).__add__(super(qnArrayTwo, other)), units = self.units) + return qnArrayTwo(super(qnArrayTwo, self).__add__(super(qnArrayTwo, other)), units = self.units, sd = np.sqrt(self.sd**2+other.sd**2)) if type(other) is Quantity: if self.units != other.units: raise qnArrayTwoError('Units of the two array must be compatible') - return qnArrayTwo(super(qnArrayTwo, self).__add__(other.value), units = self.units) - return qnArrayTwo(super(qnArrayTwo, self).__add__(other), units = self.units) + return qnArrayTwo(super(qnArrayTwo, self).__add__(other.value), units = self.units, sd = np.sqrt(self.sd**2+other.sd**2)) + return qnArrayTwo(super(qnArrayTwo, self).__add__(other), units = self.units, sd = self.sd) def __radd__(self, other): return self.__add__(other) @@ -47,23 +51,23 @@ def __sub__(self, other): if type(other) is qnArrayTwo: if self.units != other.units: raise qnArrayTwoError('Units of the two array must be compatible') - return qnArrayTwo(super(qnArrayTwo, self).__sub__(super(qnArrayTwo, other)), units = self.units) + return qnArrayTwo(super(qnArrayTwo, self).__sub__(super(qnArrayTwo, other)), units = self.units, sd = np.sqrt(self.sd**2+other.sd**2)) if type(other) is Quantity: if self.units != other.units: raise qnArrayTwoError('Units of the two array must be compatible') - return qnArrayTwo(super(qnArrayTwo, self).__sub__(other.value), units = self.units) - return qnArrayTwo(super(qnArrayTwo, self).__sub__(other), units = self.units) + return qnArrayTwo(super(qnArrayTwo, self).__sub__(other.value), units = self.units, sd = np.sqrt(self.sd**2+other.sd**2)) + return qnArrayTwo(super(qnArrayTwo, self).__sub__(other), units = self.units, sd = self.sd) def __rsub__(self, other): if type(other) is qnArrayTwo: if self.units != other.units: raise qnArrayTwoError('Units of the two array must be compatible') - return qnArrayTwo(super(qnArrayTwo, self).__rsub__(super(qnArrayTwo, other)), units = self.units) + return qnArrayTwo(super(qnArrayTwo, self).__rsub__(super(qnArrayTwo, other)), units = self.units, sd = np.sqrt(self.sd**2+other.sd**2)) if type(other) is Quantity: if self.units != other.units: raise qnArrayTwoError('Units of the two array must be compatible') - return qnArrayTwo(super(qnArrayTwo, self).__rsub__(other.value), units = self.units) - return qnArrayTwo(super(qnArrayTwo, self).__rsub__(other), units = self.units) + return qnArrayTwo(super(qnArrayTwo, self).__rsub__(other.value), units = self.units, sd = np.sqrt(self.sd**2+other.sd**2)) + return qnArrayTwo(super(qnArrayTwo, self).__rsub__(other), units = self.units, sd = self.sd) def __mul__(self, other): if type(other) is qnArrayTwo: From daac86728db4b4bd63b786ddd8c5a05cb3166e96 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 13 Jul 2017 10:45:56 +0100 Subject: [PATCH 074/106] add tests for manipulation of standard deviation when adding qn arrays --- pyqn/tests/test_qn_array_two.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index d0ab4ec..159c6c2 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -7,28 +7,34 @@ class qnArrayTwoTest(unittest.TestCase): def test_qn_array_two_init(self): vals1 = [1,2,3,4] - qnarr1 = qnArrayTwo(vals1,units='m') + sd1 = [0.1,0.2,0.3,0.4] + qnarr1 = qnArrayTwo(vals1,units='m',sd=sd1) self.assertEqual(qnarr1.units, Units('m')) for i in range(len(vals1)): self.assertEqual(qnarr1[i], vals1[i]) + self.assertEqual(qnarr1.sd[i], sd1[i]) vals2 = [-10,-20,-30,0,5] qnarr2 = qnArrayTwo(vals2, units = 'J') self.assertEqual(qnarr2.units, Units('J')) for i in range(len(vals2)): self.assertEqual(qnarr2[i], vals2[i]) + self.assertEqual(qnarr2.sd[i], 0) def test_qn_array_two_add(self): vals1 = [1,2,3,4] - qnarr1 = qnArrayTwo(vals1,units='m') + sd1 = [0.1,0.2,0.3,0.4] + qnarr1 = qnArrayTwo(vals1,units='m',sd=sd1) vals2 = [2,3,4,1] - qnarr2 = qnArrayTwo(vals2, units='m') + sd2 = [0.2,0.3,0.4,0.1] + qnarr2 = qnArrayTwo(vals2, units='m',sd=sd2) qnarr3 = qnarr1 + qnarr2 self.assertEqual(qnarr3.units, qnarr1.units) for i in range(len(vals2)): self.assertEqual(qnarr3[i], vals1[i]+vals2[i]) + self.assertAlmostEqual(qnarr3.sd[i], (sd1[i]**2+sd2[i]**2)**0.5) vals3 = [1,1,1] qnarr3 = qnArrayTwo(vals3, units='m') From d5daae4feeea78426a9e076af65e72d5137210fb Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 13 Jul 2017 15:01:28 +0100 Subject: [PATCH 075/106] replace algebraic functions with predefined ufuncs using __array_ufunc__ --- pyqn/qn_array_two.py | 101 +++++++++++++++---------------------------- 1 file changed, 36 insertions(+), 65 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index ef555b0..9a4d89d 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -29,72 +29,38 @@ def __new__(cls, input_array, info=None, units='1', sd=None): def __array_finalize__(self, obj): if obj is None: return self.info = getattr(obj, 'info', None) - - def __add__(self, other): - """ Function for adding a Quantity value to all values in - qnArrayTwo or adding another anArrayTwo to the current array - """ - if type(other) is qnArrayTwo: - if self.units != other.units: - raise qnArrayTwoError('Units of the two array must be compatible') - return qnArrayTwo(super(qnArrayTwo, self).__add__(super(qnArrayTwo, other)), units = self.units, sd = np.sqrt(self.sd**2+other.sd**2)) - if type(other) is Quantity: - if self.units != other.units: - raise qnArrayTwoError('Units of the two array must be compatible') - return qnArrayTwo(super(qnArrayTwo, self).__add__(other.value), units = self.units, sd = np.sqrt(self.sd**2+other.sd**2)) - return qnArrayTwo(super(qnArrayTwo, self).__add__(other), units = self.units, sd = self.sd) - - def __radd__(self, other): - return self.__add__(other) + self.sd = getattr(obj, 'sd', None) - def __sub__(self, other): - if type(other) is qnArrayTwo: - if self.units != other.units: - raise qnArrayTwoError('Units of the two array must be compatible') - return qnArrayTwo(super(qnArrayTwo, self).__sub__(super(qnArrayTwo, other)), units = self.units, sd = np.sqrt(self.sd**2+other.sd**2)) - if type(other) is Quantity: - if self.units != other.units: - raise qnArrayTwoError('Units of the two array must be compatible') - return qnArrayTwo(super(qnArrayTwo, self).__sub__(other.value), units = self.units, sd = np.sqrt(self.sd**2+other.sd**2)) - return qnArrayTwo(super(qnArrayTwo, self).__sub__(other), units = self.units, sd = self.sd) - - def __rsub__(self, other): - if type(other) is qnArrayTwo: - if self.units != other.units: - raise qnArrayTwoError('Units of the two array must be compatible') - return qnArrayTwo(super(qnArrayTwo, self).__rsub__(super(qnArrayTwo, other)), units = self.units, sd = np.sqrt(self.sd**2+other.sd**2)) - if type(other) is Quantity: - if self.units != other.units: - raise qnArrayTwoError('Units of the two array must be compatible') - return qnArrayTwo(super(qnArrayTwo, self).__rsub__(other.value), units = self.units, sd = np.sqrt(self.sd**2+other.sd**2)) - return qnArrayTwo(super(qnArrayTwo, self).__rsub__(other), units = self.units, sd = self.sd) - - def __mul__(self, other): - if type(other) is qnArrayTwo: - return qnArrayTwo(super(qnArrayTwo, self).__mul__(super(qnArrayTwo, other)), units = self.units * other.units) - if type(other) is Quantity: - return qnArrayTwo(super(qnArrayTwo, self).__mul__(other.value), units = self.units * other.units) - return qnArrayTwo(super(qnArrayTwo, self).__mul__(other), units = self.units) - - def __rmul__(self, other): - return self.__mul__(other) - - def __truediv__(self, other): - if type(other) is qnArrayTwo: - return qnArrayTwo(super(qnArrayTwo, self).__truediv__(super(qnArrayTwo, other)), units = self.units / other.units) - if type(other) is Quantity: - return qnArrayTwo(super(qnArrayTwo, self).__truediv__(other.value), units = self.units / other.units) - return qnArrayTwo(super(qnArrayTwo, self).__truediv__(other), units = self.units) - - def __rtruediv__(self, other): - if type(other) is qnArrayTwo: - return qnArrayTwo(super(qnArrayTwo, self).__rtruediv__(super(qnArrayTwo, other)), units = other.units / self.units) - if type(other) is Quantity: - return qnArrayTwo(super(qnArrayTwo, self).__rtruediv__(other.value), units = other.units / self.units) - return qnArrayTwo(super(qnArrayTwo, self).__rtruediv__(other), units = Units('1') / self.units) - - def __pow__(self, power): - return qnArrayTwo(super(qnArrayTwo, self).__pow__(power), units = self.units ** power) + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): + if ufunc in ufunc_dict: + alg_func = ufunc_dict[ufunc] + # check for units matching + if hasattr(inputs[0],'units') and hasattr(inputs[1],'units'): + if inputs[0].units != inputs[1].units: + raise qnArrayTwoError('Units must match') + # if both are qn arrays + if (type(inputs[1]) is qnArrayTwo) and (type(inputs[0]) is qnArrayTwo): + return qnArrayTwo(getattr(np.asarray(inputs[0]), alg_func)(np.asarray(inputs[1])), + units = inputs[0].units, + sd = np.sqrt(inputs[0].sd**2+inputs[1].sd**2)) + # if one input is a quantity + if type(inputs[1]) is Quantity: + return qnArrayTwo(getattr(np.asarray(inputs[0]), alg_func)(inputs[1].value), + units = inputs[0].units, + sd = np.sqrt(inputs[0].sd**2+inputs[1].sd**2)) + if type(inputs[0]) is Quantity: + return qnArrayTwo(getattr(inputs[0].value, alg_func)(np.asarray(inputs[1])), + units = inputs[1].units, + sd = np.sqrt(inputs[1].sd**2+inputs[0].sd**2)) + # for all other object types + if type(inputs[0]) is qnArrayTwo: + return qnArrayTwo(getattr(np.asarray(inputs[0]), alg_func)(inputs[1]), + units = inputs[0].units, + sd = inputs[0].sd) + else: + return qnArrayTwo(getattr(inputs[0], alg_func)(np.asarray(inputs[1])), + units = inputs[1].units, + sd = inputs[1].sd) def __eq__(self, other): if all(super(qnArrayTwo, self).__eq__(super(qnArrayTwo, other))) and (self.units == other.units): @@ -111,3 +77,8 @@ def html_str(self): for i in range(len(self)): html_chunks.append('{} {}'.format(self[i],self.units)) return ', '.join(html_chunks) + +ufunc_dict = { np.add: '__add__', + np.subtract: '__sub__', + np.multiply: '__mul__', + np.divide: '__truediv__'} From 2039ece580eea47deae3e43be71813b7591d9621 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 19 Jul 2017 10:59:40 +0100 Subject: [PATCH 076/106] implement radd, rsub, rmul, and rtruediv functions --- pyqn/qn_array_two.py | 106 +++++++++++++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 28 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index 9a4d89d..2d96cc3 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -32,36 +32,67 @@ def __array_finalize__(self, obj): self.sd = getattr(obj, 'sd', None) def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): - if ufunc in ufunc_dict: - alg_func = ufunc_dict[ufunc] + if ufunc in ufunc_dict_alg: + alg_func = ufunc_dict_alg[ufunc][0] + sd_func = ufunc_dict_alg[ufunc][1] + units_func = ufunc_dict_alg[ufunc][2] + alg_func_reverse = ufunc_dict_alg[ufunc][3] + # check for units matching - if hasattr(inputs[0],'units') and hasattr(inputs[1],'units'): - if inputs[0].units != inputs[1].units: - raise qnArrayTwoError('Units must match') + #if hasattr(inputs[0],'units') and hasattr(inputs[1],'units'): + # if inputs[0].units != inputs[1].units: + # raise qnArrayTwoError('Units must match') + + if all([hasattr(x, 'units') for x in inputs]): + result_units = units_func(inputs[0].units, inputs[1].units) + # if both are qn arrays if (type(inputs[1]) is qnArrayTwo) and (type(inputs[0]) is qnArrayTwo): - return qnArrayTwo(getattr(np.asarray(inputs[0]), alg_func)(np.asarray(inputs[1])), - units = inputs[0].units, - sd = np.sqrt(inputs[0].sd**2+inputs[1].sd**2)) + result_val = getattr(np.asarray(inputs[0]), alg_func)(np.asarray(inputs[1])) + result_sd = sd_func(result_val, np.asarray(inputs[0]), + np.asarray(inputs[1]), + inputs[0].sd, + inputs[1].sd) + # if one input is a quantity - if type(inputs[1]) is Quantity: - return qnArrayTwo(getattr(np.asarray(inputs[0]), alg_func)(inputs[1].value), - units = inputs[0].units, - sd = np.sqrt(inputs[0].sd**2+inputs[1].sd**2)) - if type(inputs[0]) is Quantity: - return qnArrayTwo(getattr(inputs[0].value, alg_func)(np.asarray(inputs[1])), - units = inputs[1].units, - sd = np.sqrt(inputs[1].sd**2+inputs[0].sd**2)) + elif type(inputs[1]) is Quantity: + result_val = getattr(np.asarray(inputs[0]), alg_func)(inputs[1].value) + result_sd = sd_func(result_val, np.asarray(inputs[0]), + inputs[1].value, + inputs[0].sd, + inputs[1].sd) + + elif type(inputs[0]) is Quantity: + result_val = getattr(np.asarray(inputs[1]), alg_func_reverse)(inputs[0].value) + result_sd = sd_func(result_val, inputs[0].value, + np.asarray(inputs[1]), + inputs[0].sd, + inputs[1].sd) + # for all other object types - if type(inputs[0]) is qnArrayTwo: - return qnArrayTwo(getattr(np.asarray(inputs[0]), alg_func)(inputs[1]), - units = inputs[0].units, - sd = inputs[0].sd) + elif type(inputs[0]) is qnArrayTwo: + result_val = getattr(np.asarray(inputs[0]), alg_func)(inputs[1]) + result_sd = sd_func(result_val, np.asarray(inputs[0]), + inputs[1], + inputs[0].sd, 0) + result_units = units_func(inputs[0].units, Units('1')) + else: - return qnArrayTwo(getattr(inputs[0], alg_func)(np.asarray(inputs[1])), - units = inputs[1].units, - sd = inputs[1].sd) + result_val = getattr(np.asarray(inputs[1]), alg_func_reverse)(inputs[0]) + result_sd = sd_func(result_val, inputs[0], + np.asarray(inputs[1]), + 0, inputs[1].sd) + result_units = units_func(Units('1'), inputs[1].units) + return qnArrayTwo(result_val, units = result_units, sd = result_sd) + #~ elif ufunc in ufunc_dict_other: + #~ if inputs[0].units.has_units() is True: + #~ raise qnArrayTwoError('qnArray must be unitless') + #~ sd_func = ufunc_dict_other[ufunc] + #~ result_val = np.exp(super(qnArrayTwo, inputs[0])) + #~ result_sd = sd_func(super(qnArrayTwo, result_val), super(qnArrayTwo, inputs[0]), inputs[0].sd) + #~ return qnArrayTwo(result_val, units = Units('1'), sd = result_sd) + def __eq__(self, other): if all(super(qnArrayTwo, self).__eq__(super(qnArrayTwo, other))) and (self.units == other.units): return True @@ -77,8 +108,27 @@ def html_str(self): for i in range(len(self)): html_chunks.append('{} {}'.format(self[i],self.units)) return ', '.join(html_chunks) - -ufunc_dict = { np.add: '__add__', - np.subtract: '__sub__', - np.multiply: '__mul__', - np.divide: '__truediv__'} + +def sd_add_sub(result, vals1, vals2, sd1, sd2): + return np.sqrt(sd1**2+sd2**2) +def sd_mul_div(result, vals1, vals2, sd1, sd2): + return result*np.sqrt((sd1/vals1)**2+(sd2/vals2)**2) +def sd_exp(result, vals, sd): + return result * sd + +def units_add_sub(u1, u2): + if u1.has_units() is True: + return u1 + else: + return u2 +def units_mul(u1,u2): + return u1*u2 +def units_div(u1,u2): + return u1/u2 + +ufunc_dict_alg = { np.add: ('__add__', sd_add_sub, units_add_sub, '__radd__'), + np.subtract: ('__sub__', sd_add_sub, units_add_sub, '__rsub__'), + np.multiply: ('__mul__', sd_mul_div, units_mul, '__rmul__'), + np.divide: ('__truediv__', sd_mul_div, units_div, '__rtruediv__')} + +ufunc_dict_other = { np.exp: sd_exp} From 61a2428599a74d6b3ceee0919cee06465fe2e930 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 19 Jul 2017 11:00:02 +0100 Subject: [PATCH 077/106] add future tests for other ufuncs --- pyqn/tests/test_qn_array_two.py | 90 +++++++++++++++------------------ 1 file changed, 41 insertions(+), 49 deletions(-) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index 159c6c2..2742584 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -151,62 +151,54 @@ def test_qn_array_two_mul(self): self.assertEqual(qnarr6[i], qnarr2[i]/15) self.assertEqual(qnarr7[i], 15/qnarr2[i]) - def test_qn_array_two_pow(self): - vals1 = [1,2,3,4] - qnarr1 = qnArrayTwo(vals1, units = 'm') + #~ def test_qn_array_two_pow(self): + #~ vals1 = [1,2,3,4] + #~ qnarr1 = qnArrayTwo(vals1, units = 'm') - qnarr2 = qnarr1 ** 2 - self.assertEqual(qnarr2.units, Units('m2')) - for i in range(len(vals1)): - self.assertEqual(qnarr2[i], vals1[i]**2) + #~ qnarr2 = qnarr1 ** 2 + #~ self.assertEqual(qnarr2.units, Units('m2')) + #~ for i in range(len(vals1)): + #~ self.assertEqual(qnarr2[i], vals1[i]**2) + + #~ def test_qn_array_eq(self): + #~ qnarr1 = qnArrayTwo([1,1,1],units = 'm') + #~ qnarr2 = qnArrayTwo([1,1,1],units = Units('J')) + #~ qnarr3 = qnArrayTwo([1,2,3],units = 'm') + #~ qnarr4 = qnArrayTwo([1,2,3],units = 'J') + #~ qnarr5 = qnArrayTwo([1.0,1.0,1.0],units = Units('m')) - def test_qn_array_eq(self): - qnarr1 = qnArrayTwo([1,1,1],units = 'm') - qnarr2 = qnArrayTwo([1,1,1],units = Units('J')) - qnarr3 = qnArrayTwo([1,2,3],units = 'm') - qnarr4 = qnArrayTwo([1,2,3],units = 'J') - qnarr5 = qnArrayTwo([1.0,1.0,1.0],units = Units('m')) + #~ self.assertFalse(qnarr1 == qnarr2) + #~ self.assertFalse(qnarr1 == qnarr3) + #~ self.assertFalse(qnarr1 == qnarr4) + #~ self.assertTrue(qnarr1 == qnarr5) - self.assertFalse(qnarr1 == qnarr2) - self.assertFalse(qnarr1 == qnarr3) - self.assertFalse(qnarr1 == qnarr4) - self.assertTrue(qnarr1 == qnarr5) + #~ self.assertFalse(qnarr2 == qnarr3) + #~ self.assertFalse(qnarr2 == qnarr4) + #~ self.assertFalse(qnarr2 == qnarr5) - self.assertFalse(qnarr2 == qnarr3) - self.assertFalse(qnarr2 == qnarr4) - self.assertFalse(qnarr2 == qnarr5) + #~ self.assertFalse(qnarr3 == qnarr4) + #~ self.assertFalse(qnarr3 == qnarr5) - self.assertFalse(qnarr3 == qnarr4) - self.assertFalse(qnarr3 == qnarr5) + #~ self.assertFalse(qnarr4 == qnarr5) - self.assertFalse(qnarr4 == qnarr5) + #~ def test_qn_array_two_html(self): + #~ vals = [1,2,3,4] + #~ qnarr = qnArrayTwo(vals, units = 'm') + + #~ self.assertEqual(qnarr.html_str, '1 m, 2 m, 3 m, 4 m') + + #~ def test_qn_array_two_ufunc(self): + #~ a1 = [1,2,3] + #~ sd1 = [0.1,0.2,0.3] + #~ q1 = qnArrayTwo(a1,units = 'm', sd = sd1) + #~ q2 = qnArrayTwo([4,5,6],units = 'm', sd = [0.4,0.5,0.6]) + #~ add = np.add(q1,q2) -# def test_qn_array_neq(self): -# qnarr1 = qnArrayTwo([1,1,1],units = 'm') -# qnarr2 = qnArrayTwo([1,1,1],units = Units('J')) -# qnarr3 = qnArrayTwo([1,2,3],units = 'm') -# qnarr4 = qnArrayTwo([1,2,3],units = 'J') -# qnarr5 = qnArrayTwo([1.0,1.0,1.0],units = Units('m')) -# -# self.assertTrue(qnarr1 != qnarr2) -# self.assertTrue(qnarr1 != qnarr3) -# self.assertTrue(qnarr1 != qnarr4) -# self.assertFalse(qnarr1 != qnarr5) -# -# self.assertTrue(qnarr2 != qnarr3) -# self.assertTrue(qnarr2 != qnarr4) -# self.assertTrue(qnarr2 != qnarr5) -# -# self.assertTrue(qnarr3 != qnarr4) -# self.assertTrue(qnarr3 != qnarr5) -# -# self.assertTrue(qnarr4 != qnarr5) - - def test_qn_array_two_html(self): - vals = [1,2,3,4] - qnarr = qnArrayTwo(vals, units = 'm') - - self.assertEqual(qnarr.html_str, '1 m, 2 m, 3 m, 4 m') + #~ q3 = qnArrayTwo(a1, units = '1', sd = sd1) + #~ q4 = np.exp(q3) + #~ for i in range(3): + #~ self.assertEqual(q3[i], np.exp(a1[i])) + #~ self.assertEqual(q3.sd[i], np.exp(sd1[i])) if __name__ == '__main__': unittest.main() From a0ef262c6f88ff8af40906b43f0fe3a2e15b7508 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 19 Jul 2017 11:07:12 +0100 Subject: [PATCH 078/106] implement exp ufunc --- pyqn/qn_array_two.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index 2d96cc3..7ea5773 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -85,13 +85,13 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): result_units = units_func(Units('1'), inputs[1].units) return qnArrayTwo(result_val, units = result_units, sd = result_sd) - #~ elif ufunc in ufunc_dict_other: - #~ if inputs[0].units.has_units() is True: - #~ raise qnArrayTwoError('qnArray must be unitless') - #~ sd_func = ufunc_dict_other[ufunc] - #~ result_val = np.exp(super(qnArrayTwo, inputs[0])) - #~ result_sd = sd_func(super(qnArrayTwo, result_val), super(qnArrayTwo, inputs[0]), inputs[0].sd) - #~ return qnArrayTwo(result_val, units = Units('1'), sd = result_sd) + elif ufunc in ufunc_dict_other: + if inputs[0].units.has_units() is True: + raise qnArrayTwoError('qnArray must be unitless') + sd_func = ufunc_dict_other[ufunc] + result_val = np.exp(super(qnArrayTwo, inputs[0])) + result_sd = sd_func(super(qnArrayTwo, result_val), super(qnArrayTwo, inputs[0]), inputs[0].sd) + return qnArrayTwo(result_val, units = Units('1'), sd = result_sd) def __eq__(self, other): if all(super(qnArrayTwo, self).__eq__(super(qnArrayTwo, other))) and (self.units == other.units): From 90fee7d47b76e7844210f6bc0b135e4404dd9a26 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 19 Jul 2017 11:07:23 +0100 Subject: [PATCH 079/106] fix testing equation --- pyqn/tests/test_qn_array_two.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index 2742584..4bcde9b 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -187,18 +187,18 @@ def test_qn_array_two_mul(self): #~ self.assertEqual(qnarr.html_str, '1 m, 2 m, 3 m, 4 m') - #~ def test_qn_array_two_ufunc(self): - #~ a1 = [1,2,3] - #~ sd1 = [0.1,0.2,0.3] - #~ q1 = qnArrayTwo(a1,units = 'm', sd = sd1) - #~ q2 = qnArrayTwo([4,5,6],units = 'm', sd = [0.4,0.5,0.6]) - #~ add = np.add(q1,q2) + def test_qn_array_two_ufunc(self): + a1 = [1,2,3] + sd1 = [0.1,0.2,0.3] + q1 = qnArrayTwo(a1,units = 'm', sd = sd1) + q2 = qnArrayTwo([4,5,6],units = 'm', sd = [0.4,0.5,0.6]) + add = np.add(q1,q2) - #~ q3 = qnArrayTwo(a1, units = '1', sd = sd1) - #~ q4 = np.exp(q3) - #~ for i in range(3): - #~ self.assertEqual(q3[i], np.exp(a1[i])) - #~ self.assertEqual(q3.sd[i], np.exp(sd1[i])) + q3 = qnArrayTwo(a1, units = '1', sd = sd1) + q4 = np.exp(q3) + for i in range(3): + self.assertAlmostEqual(q4[i], np.exp(a1[i])) + self.assertAlmostEqual(q4.sd[i], q4[i]*q3.sd[i]) if __name__ == '__main__': unittest.main() From 5995aad89a565750bdf2ab671e3c7434b99f5515 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 19 Jul 2017 11:20:19 +0100 Subject: [PATCH 080/106] implement sin and cos ufuncs --- pyqn/qn_array_two.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index 7ea5773..fb44244 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -89,8 +89,8 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): if inputs[0].units.has_units() is True: raise qnArrayTwoError('qnArray must be unitless') sd_func = ufunc_dict_other[ufunc] - result_val = np.exp(super(qnArrayTwo, inputs[0])) - result_sd = sd_func(super(qnArrayTwo, result_val), super(qnArrayTwo, inputs[0]), inputs[0].sd) + result_val = ufunc(np.asarray(inputs[0])) + result_sd = sd_func(result_val, np.asarray(inputs[0]), inputs[0].sd) return qnArrayTwo(result_val, units = Units('1'), sd = result_sd) def __eq__(self, other): @@ -115,6 +115,10 @@ def sd_mul_div(result, vals1, vals2, sd1, sd2): return result*np.sqrt((sd1/vals1)**2+(sd2/vals2)**2) def sd_exp(result, vals, sd): return result * sd +def sd_sin(result, vals, sd): + return np.cos(vals) * sd +def sd_cos(result, vals, sd): + return np.sin(vals) * sd def units_add_sub(u1, u2): if u1.has_units() is True: @@ -131,4 +135,6 @@ def units_div(u1,u2): np.multiply: ('__mul__', sd_mul_div, units_mul, '__rmul__'), np.divide: ('__truediv__', sd_mul_div, units_div, '__rtruediv__')} -ufunc_dict_other = { np.exp: sd_exp} +ufunc_dict_other = { np.exp: sd_exp, + np.sin: sd_sin, + np.cos: sd_cos} From d4ddb9e2a4cc52507aa9f2476d21fdf4871accf8 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 19 Jul 2017 11:20:32 +0100 Subject: [PATCH 081/106] add tests for sin and cos ufuncs --- pyqn/tests/test_qn_array_two.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index 4bcde9b..1421d34 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -196,9 +196,16 @@ def test_qn_array_two_ufunc(self): q3 = qnArrayTwo(a1, units = '1', sd = sd1) q4 = np.exp(q3) + q5 = np.sin(q3) + q6 = np.cos(q3) for i in range(3): self.assertAlmostEqual(q4[i], np.exp(a1[i])) self.assertAlmostEqual(q4.sd[i], q4[i]*q3.sd[i]) + self.assertAlmostEqual(q5[i], np.sin(a1[i])) + self.assertAlmostEqual(q5.sd[i], np.cos(a1[i])*sd1[i]) + self.assertAlmostEqual(q6[i], np.cos(a1[i])) + self.assertAlmostEqual(q6.sd[i], np.sin(a1[i])*sd1[i]) + if __name__ == '__main__': unittest.main() From e856c31a15231088a4c3ea030e243caace7e1088 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 19 Jul 2017 11:40:25 +0100 Subject: [PATCH 082/106] implement more arcsin, arccos, arctan, sinh, cosh, tanh, arcsinh, arccosh, arctanh --- pyqn/qn_array_two.py | 46 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index fb44244..cc21c61 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -76,7 +76,7 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): inputs[1], inputs[0].sd, 0) result_units = units_func(inputs[0].units, Units('1')) - + else: result_val = getattr(np.asarray(inputs[1]), alg_func_reverse)(inputs[0]) result_sd = sd_func(result_val, inputs[0], @@ -116,15 +116,33 @@ def sd_mul_div(result, vals1, vals2, sd1, sd2): def sd_exp(result, vals, sd): return result * sd def sd_sin(result, vals, sd): - return np.cos(vals) * sd + return np.cos(vals) * sd def sd_cos(result, vals, sd): - return np.sin(vals) * sd + return np.sin(vals) * sd +def sd_tan(result, vals, sd): + return np.cos(vals)**(-2) * sd +def sd_arcsin_arccos(result, vals, sd): + return sd/np.sqrt(1-vals**2) +def sd_arctan(result, vals, sd): + return sd/(1+vals**2) +def sd_sinh(result, vals, sd): + return sd*np.cosh(vals) +def sd_cosh(result, vals, sd): + return sd*np.sinh(vals) +def sd_tanh(result, vals, sd): + return sd*np.cosh(vals)**(-2) +def sd_arcsinh(result, vals, sd): + return sd/np.sqrt(1+vals**2) +def sd_arccosh(result, vals, sd): + return sd/(np.sqrt(vals-1)*np.sqrt(vals+1)) +def sd_arctanh(result, vals, sd): + return sd/(1-vals**2) def units_add_sub(u1, u2): - if u1.has_units() is True: - return u1 - else: - return u2 + if u1.has_units() is True: + return u1 + else: + return u2 def units_mul(u1,u2): return u1*u2 def units_div(u1,u2): @@ -136,5 +154,15 @@ def units_div(u1,u2): np.divide: ('__truediv__', sd_mul_div, units_div, '__rtruediv__')} ufunc_dict_other = { np.exp: sd_exp, - np.sin: sd_sin, - np.cos: sd_cos} + np.sin: sd_sin, + np.cos: sd_cos, + np.tan: sd_tan, + np.arcsin: sd_arcsin_arccos, + np.arccos: sd_arcsin_arccos, + np.arctan: sd_arctan, + np.sinh: sd_sinh, + np.cosh: sd_cosh, + np.tanh: sd_tanh, + np.arcsinh: sd_arcsinh, + np.arccosh: sd_arccosh, + np.arctanh: sd_arctanh} From 12a5dc9d4d8eea4ffbd0454ac673d71164da6771 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 19 Jul 2017 11:40:49 +0100 Subject: [PATCH 083/106] implement tests for arcsin, arccos, and arctan ufuncs --- pyqn/tests/test_qn_array_two.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index 1421d34..0f6c2d9 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -190,14 +190,21 @@ def test_qn_array_two_mul(self): def test_qn_array_two_ufunc(self): a1 = [1,2,3] sd1 = [0.1,0.2,0.3] + a2 = [0.1,0.2,0.3] + sd2 = [0.01,0.02,0.03] q1 = qnArrayTwo(a1,units = 'm', sd = sd1) - q2 = qnArrayTwo([4,5,6],units = 'm', sd = [0.4,0.5,0.6]) + q2 = qnArrayTwo(a2,units = 'm', sd = sd2) add = np.add(q1,q2) q3 = qnArrayTwo(a1, units = '1', sd = sd1) + q33 = qnArrayTwo(a2, units = '1', sd = sd2) q4 = np.exp(q3) q5 = np.sin(q3) q6 = np.cos(q3) + q7 = np.tan(q3) + q8 = np.arcsin(q33) + q9 = np.arccos(q33) + q10 = np.arctan(q33) for i in range(3): self.assertAlmostEqual(q4[i], np.exp(a1[i])) self.assertAlmostEqual(q4.sd[i], q4[i]*q3.sd[i]) @@ -205,7 +212,11 @@ def test_qn_array_two_ufunc(self): self.assertAlmostEqual(q5.sd[i], np.cos(a1[i])*sd1[i]) self.assertAlmostEqual(q6[i], np.cos(a1[i])) self.assertAlmostEqual(q6.sd[i], np.sin(a1[i])*sd1[i]) - + self.assertAlmostEqual(q7[i], np.tan(a1[i])) + self.assertAlmostEqual(q7.sd[i], np.cos(a1[i])**(-2)*sd1[i]) + self.assertAlmostEqual(q8[i], np.arcsin(a2[i])) + self.assertAlmostEqual(q9[i], np.arccos(a2[i])) + self.assertAlmostEqual(q10[i], np.arctan(a2[i])) if __name__ == '__main__': unittest.main() From c03ed2fed63106cf32eba4d1d1ebfc3cfc58f5fb Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 20 Jul 2017 10:14:20 +0100 Subject: [PATCH 084/106] add more tests for sd prop --- pyqn/qn_array_two.py | 25 ++++++++++++++++++++----- pyqn/tests/test_qn_array_two.py | 18 +++++++++++++++++- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index cc21c61..f0200ec 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -38,11 +38,6 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): units_func = ufunc_dict_alg[ufunc][2] alg_func_reverse = ufunc_dict_alg[ufunc][3] - # check for units matching - #if hasattr(inputs[0],'units') and hasattr(inputs[1],'units'): - # if inputs[0].units != inputs[1].units: - # raise qnArrayTwoError('Units must match') - if all([hasattr(x, 'units') for x in inputs]): result_units = units_func(inputs[0].units, inputs[1].units) @@ -93,6 +88,14 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): result_sd = sd_func(result_val, np.asarray(inputs[0]), inputs[0].sd) return qnArrayTwo(result_val, units = Units('1'), sd = result_sd) + elif ufunc in ufunc_dict_otherother: + if inputs[0].units.has_units() is True: + raise qnArrayTwoError('qnArray must be unitless') + sd_func = ufunc_dict_otherother[ufunc] + result_val = ufunc(np.asarray(inputs[0]),np.asarray(inputs[1])) + result_sd = sd_func(result_val, np.asarray(inputs[0]), np.asarray(inputs[1]), inputs[0].sd, inputs[1].sd) + return qnArrayTwo(result_val, units = Units('1'), sd = result_sd) + def __eq__(self, other): if all(super(qnArrayTwo, self).__eq__(super(qnArrayTwo, other))) and (self.units == other.units): return True @@ -113,6 +116,14 @@ def sd_add_sub(result, vals1, vals2, sd1, sd2): return np.sqrt(sd1**2+sd2**2) def sd_mul_div(result, vals1, vals2, sd1, sd2): return result*np.sqrt((sd1/vals1)**2+(sd2/vals2)**2) + +def sd_logaddexp(result, vals1, vals2, sd1, sd2): + return np.sqrt(np.exp(vals1)**2*sd1**2+np.exp(vals2)**2*sd2**2)/(np.exp(vals1)+np.exp(vals2)) +def sd_logaddexp2(result, vals1, vals2, sd1, sd2): + return np.sqrt(np.exp(vals1)**2*sd1**2+np.exp(vals2)**2*sd2**2)/((np.log(2))*(np.exp(vals1)+np.exp(vals2))) +def sd_power(result, vals1, vals2, sd1, sd2): + return np.sqrt(sd1**2*(vals2*vals1**(vals2-1))**2 + sd2**2*(result*np.log(vals1))**2) + def sd_exp(result, vals, sd): return result * sd def sd_sin(result, vals, sd): @@ -166,3 +177,7 @@ def units_div(u1,u2): np.arcsinh: sd_arcsinh, np.arccosh: sd_arccosh, np.arctanh: sd_arctanh} + +ufunc_dict_otherother = {np.logaddexp: sd_logaddexp, + np.logaddexp2: sd_logaddexp2, + np.power: sd_power} diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index 0f6c2d9..64f418c 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -205,6 +205,11 @@ def test_qn_array_two_ufunc(self): q8 = np.arcsin(q33) q9 = np.arccos(q33) q10 = np.arctan(q33) + q11 = np.sinh(q33) + q12 = np.cosh(q33) + q13 = np.tanh(q33) + q14 = np.logaddexp(q3,q33) + q15 = np.power(q3,q33) for i in range(3): self.assertAlmostEqual(q4[i], np.exp(a1[i])) self.assertAlmostEqual(q4.sd[i], q4[i]*q3.sd[i]) @@ -213,10 +218,21 @@ def test_qn_array_two_ufunc(self): self.assertAlmostEqual(q6[i], np.cos(a1[i])) self.assertAlmostEqual(q6.sd[i], np.sin(a1[i])*sd1[i]) self.assertAlmostEqual(q7[i], np.tan(a1[i])) - self.assertAlmostEqual(q7.sd[i], np.cos(a1[i])**(-2)*sd1[i]) + #self.assertAlmostEqual(q7.sd[i], np.cos(a1[i])**(-2)*sd1[i]) self.assertAlmostEqual(q8[i], np.arcsin(a2[i])) + #self.assertAlmostEqual(q8.sd[i], sd2[i]/np.sqrt(1-sd2[i]**2)) self.assertAlmostEqual(q9[i], np.arccos(a2[i])) + #self.assertAlmostEqual(q9.sd[i], sd2[i]/np.sqrt(1-sd2[i]**2)) self.assertAlmostEqual(q10[i], np.arctan(a2[i])) + #self.assertAlmostEqual(q10.sd[i], sd2[i]*np.cosh(a2[i])**(-2)) + self.assertAlmostEqual(q11[i], np.sinh(a2[i])) + self.assertAlmostEqual(q11.sd[i], sd2[i]*np.cosh(a2[i])) + self.assertAlmostEqual(q12[i], np.cosh(a2[i])) + self.assertAlmostEqual(q12.sd[i], sd2[i]*np.sinh(a2[i])) + self.assertAlmostEqual(q13[i], np.tanh(a2[i])) + self.assertAlmostEqual(q13.sd[i], sd2[i]*np.cosh(a2[i])**(-2)) + self.assertAlmostEqual(q14[i], np.logaddexp(a1[i], a2[i])) + self.assertAlmostEqual(q15[i], np.power(np.asarray(q3[i]),np.asarray(q33[i]))) if __name__ == '__main__': unittest.main() From 064eefb0b1ecc46f1dfd831e3f73b495ba0f6bca Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 20 Jul 2017 11:36:11 +0100 Subject: [PATCH 085/106] add conversion function --- pyqn/qn_array_two.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index f0200ec..9f8cde5 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -111,6 +111,13 @@ def html_str(self): for i in range(len(self)): html_chunks.append('{} {}'.format(self[i],self.units)) return ', '.join(html_chunks) + + def convert_units_to(self, new_units, force=None): + to_units = Units(new_units) + fac = self.units.conversion(to_units, force) + new_vals = np.asarray(self)*fac + new_sd = self.sd*fac + return qnArrayTwo(new_vals, units = new_units, sd = new_sd) def sd_add_sub(result, vals1, vals2, sd1, sd2): return np.sqrt(sd1**2+sd2**2) From 04783e6b46aacf690be42732b901e8d726dc93d9 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 20 Jul 2017 11:36:23 +0100 Subject: [PATCH 086/106] add tests for qnArrayTwo conversion --- pyqn/tests/test_qn_array_two.py | 49 +++++++++------------------------ 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index 64f418c..f43633a 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -150,42 +150,19 @@ def test_qn_array_two_mul(self): self.assertEqual(qnarr5[i], 10/qnarr1[i]) self.assertEqual(qnarr6[i], qnarr2[i]/15) self.assertEqual(qnarr7[i], 15/qnarr2[i]) - - #~ def test_qn_array_two_pow(self): - #~ vals1 = [1,2,3,4] - #~ qnarr1 = qnArrayTwo(vals1, units = 'm') - - #~ qnarr2 = qnarr1 ** 2 - #~ self.assertEqual(qnarr2.units, Units('m2')) - #~ for i in range(len(vals1)): - #~ self.assertEqual(qnarr2[i], vals1[i]**2) - - #~ def test_qn_array_eq(self): - #~ qnarr1 = qnArrayTwo([1,1,1],units = 'm') - #~ qnarr2 = qnArrayTwo([1,1,1],units = Units('J')) - #~ qnarr3 = qnArrayTwo([1,2,3],units = 'm') - #~ qnarr4 = qnArrayTwo([1,2,3],units = 'J') - #~ qnarr5 = qnArrayTwo([1.0,1.0,1.0],units = Units('m')) - - #~ self.assertFalse(qnarr1 == qnarr2) - #~ self.assertFalse(qnarr1 == qnarr3) - #~ self.assertFalse(qnarr1 == qnarr4) - #~ self.assertTrue(qnarr1 == qnarr5) - - #~ self.assertFalse(qnarr2 == qnarr3) - #~ self.assertFalse(qnarr2 == qnarr4) - #~ self.assertFalse(qnarr2 == qnarr5) - - #~ self.assertFalse(qnarr3 == qnarr4) - #~ self.assertFalse(qnarr3 == qnarr5) - - #~ self.assertFalse(qnarr4 == qnarr5) - - #~ def test_qn_array_two_html(self): - #~ vals = [1,2,3,4] - #~ qnarr = qnArrayTwo(vals, units = 'm') - - #~ self.assertEqual(qnarr.html_str, '1 m, 2 m, 3 m, 4 m') + + def test_qn_array_two_conversion(self): + a1 = [1,2,3] + sd1 = [0.1,0.2,0.3] + q1 = qnArrayTwo(a1, units = 'm', sd = sd1) + q2 = q1.convert_units_to('inch') + r_wanted = [a*39.37007874 for a in a1] + sd_wanted = [s*39.37007874 for s in sd1] + + self.assertEqual(q2.units, Units('inch')) + for i in range(3): + self.assertAlmostEqual(q2[i], r_wanted[i]) + self.assertAlmostEqual(q2.sd[i], sd_wanted[i]) def test_qn_array_two_ufunc(self): a1 = [1,2,3] From a7bd632175ce84c4e5487e2dde87651efd119275 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 20 Jul 2017 12:15:36 +0100 Subject: [PATCH 087/106] add function to append values to qnArrayTwo and to plot two qnArrayTwo objects with error bars --- pyqn/qn_array_two.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index 9f8cde5..0f7b592 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -1,6 +1,7 @@ import numpy as np from .units import Units from .quantity import Quantity +import matplotlib.pyplot as plt class qnArrayTwoError(Exception): def __init__(self, error_str): @@ -118,6 +119,17 @@ def convert_units_to(self, new_units, force=None): new_vals = np.asarray(self)*fac new_sd = self.sd*fac return qnArrayTwo(new_vals, units = new_units, sd = new_sd) + + def append(self, value = None, sd = 0, *inputs): + if type(inputs[0]) is Quantity: + if self.units != inputs[0].units: + raise qnArrayTwoError('Same units expected') + if inputs[0] is not None: + return qnArrayTwo(np.append(np.asarray(self),inputs[0].value), units = self.units, sd = np.append(self.sd,inputs[0].sd)) + else: + return qnArrayTwo(np.append(np.asarray(self),inputs[0].value), units = self.units, sd = np.append(self.sd,0)) + elif value is not None: + return qnArrayTwo(np.append(np.asarray(self),value), units = self.units, sd = np.append(self.sd,sd)) def sd_add_sub(result, vals1, vals2, sd1, sd2): return np.sqrt(sd1**2+sd2**2) @@ -188,3 +200,7 @@ def units_div(u1,u2): ufunc_dict_otherother = {np.logaddexp: sd_logaddexp, np.logaddexp2: sd_logaddexp2, np.power: sd_power} + +def plot_qn_arrays(qn_arr_1, qn_arr_2): + plt.errorbar(np.asarray(qn_arr_1),np.asarray(qn_arr_2),xerr = qn_arr_1.sd, yerr = qn_arr_2.sd) + plt.show() From b25fe35ec355910685f7467c9b8f7d8d86369f83 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 20 Jul 2017 12:15:53 +0100 Subject: [PATCH 088/106] test append function --- pyqn/tests/test_qn_array_two.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index f43633a..5c6ae88 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -163,6 +163,30 @@ def test_qn_array_two_conversion(self): for i in range(3): self.assertAlmostEqual(q2[i], r_wanted[i]) self.assertAlmostEqual(q2.sd[i], sd_wanted[i]) + + def test_qn_array_append(self): + a1 = [1,2,3] + sd1 = [0.1,0.2,0.3] + q1 = qnArrayTwo(a1, units = 'm', sd = sd1) + quant1 = Quantity(value=10,units='m') + quant2 = Quantity(value=5,units='m',sd=0.5) + quant3 = Quantity(value=2,units='J',sd=0.1) + + result1 = q1.append(quant1) + result2 = q1.append(quant2) + with self.assertRaises(qnArrayTwoError) as e: + result3 = q1.append(quant3) + self.assertEqual(len(result1),4) + self.assertEqual(result1[-1],10) + self.assertEqual(len(result2),4) + self.assertEqual(result2[-1],5) + + result1 = q1.append(value=2) + result2 = q1.append(value=1,sd=0.5) + self.assertEqual(len(result1),4) + self.assertEqual(result1[-1],2) + self.assertEqual(len(result2),4) + self.assertEqual(result2[-1],1) def test_qn_array_two_ufunc(self): a1 = [1,2,3] From 3fa23b42c0ef3520ab034d222e571cc3b55b66b8 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 24 Jul 2017 13:05:00 +0100 Subject: [PATCH 089/106] add unit checking for ufuncs, make append function only accept Quantity objects --- pyqn/qn_array_two.py | 108 +++++++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 50 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index 0f7b592..0bed1dc 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -11,8 +11,8 @@ def __str__(self): class qnArrayTwo(np.ndarray): def __new__(cls, input_array, info=None, units='1', sd=None): - """ Initialises a qnArray as a child class derived from the - numpy ndarray. + """ Initialises a qnArray as a child class derived from the + numpy ndarray. """ obj = np.asarray(input_array).view(cls) obj.info = info @@ -20,28 +20,28 @@ def __new__(cls, input_array, info=None, units='1', sd=None): obj.sd = np.zeros(len(input_array)) else: obj.sd = np.array(sd) - + if type(units) is str: obj.units = Units(units) #records units as Unit class elif type(units) is Units: - obj.units = units + obj.units = units return obj def __array_finalize__(self, obj): if obj is None: return self.info = getattr(obj, 'info', None) self.sd = getattr(obj, 'sd', None) - + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): if ufunc in ufunc_dict_alg: alg_func = ufunc_dict_alg[ufunc][0] sd_func = ufunc_dict_alg[ufunc][1] units_func = ufunc_dict_alg[ufunc][2] alg_func_reverse = ufunc_dict_alg[ufunc][3] - + if all([hasattr(x, 'units') for x in inputs]): result_units = units_func(inputs[0].units, inputs[1].units) - + # if both are qn arrays if (type(inputs[1]) is qnArrayTwo) and (type(inputs[0]) is qnArrayTwo): result_val = getattr(np.asarray(inputs[0]), alg_func)(np.asarray(inputs[1])) @@ -49,7 +49,7 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): np.asarray(inputs[1]), inputs[0].sd, inputs[1].sd) - + # if one input is a quantity elif type(inputs[1]) is Quantity: result_val = getattr(np.asarray(inputs[0]), alg_func)(inputs[1].value) @@ -57,14 +57,14 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): inputs[1].value, inputs[0].sd, inputs[1].sd) - + elif type(inputs[0]) is Quantity: result_val = getattr(np.asarray(inputs[1]), alg_func_reverse)(inputs[0].value) result_sd = sd_func(result_val, inputs[0].value, np.asarray(inputs[1]), inputs[0].sd, inputs[1].sd) - + # for all other object types elif type(inputs[0]) is qnArrayTwo: result_val = getattr(np.asarray(inputs[0]), alg_func)(inputs[1]) @@ -72,7 +72,7 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): inputs[1], inputs[0].sd, 0) result_units = units_func(inputs[0].units, Units('1')) - + else: result_val = getattr(np.asarray(inputs[1]), alg_func_reverse)(inputs[0]) result_sd = sd_func(result_val, inputs[0], @@ -82,13 +82,13 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): return qnArrayTwo(result_val, units = result_units, sd = result_sd) elif ufunc in ufunc_dict_other: - if inputs[0].units.has_units() is True: - raise qnArrayTwoError('qnArray must be unitless') - sd_func = ufunc_dict_other[ufunc] - result_val = ufunc(np.asarray(inputs[0])) - result_sd = sd_func(result_val, np.asarray(inputs[0]), inputs[0].sd) + unit_test_func = ufunc_dict_other[ufunc][1] + inputs_checked = unit_test_func(inputs[0]) + sd_func = ufunc_dict_other[ufunc][0] + result_val = ufunc(np.asarray(inputs_checked)) + result_sd = sd_func(result_val, np.asarray(inputs_checked), inputs_checked.sd) return qnArrayTwo(result_val, units = Units('1'), sd = result_sd) - + elif ufunc in ufunc_dict_otherother: if inputs[0].units.has_units() is True: raise qnArrayTwoError('qnArray must be unitless') @@ -96,7 +96,7 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): result_val = ufunc(np.asarray(inputs[0]),np.asarray(inputs[1])) result_sd = sd_func(result_val, np.asarray(inputs[0]), np.asarray(inputs[1]), inputs[0].sd, inputs[1].sd) return qnArrayTwo(result_val, units = Units('1'), sd = result_sd) - + def __eq__(self, other): if all(super(qnArrayTwo, self).__eq__(super(qnArrayTwo, other))) and (self.units == other.units): return True @@ -112,37 +112,31 @@ def html_str(self): for i in range(len(self)): html_chunks.append('{} {}'.format(self[i],self.units)) return ', '.join(html_chunks) - + def convert_units_to(self, new_units, force=None): to_units = Units(new_units) fac = self.units.conversion(to_units, force) new_vals = np.asarray(self)*fac new_sd = self.sd*fac return qnArrayTwo(new_vals, units = new_units, sd = new_sd) - - def append(self, value = None, sd = 0, *inputs): - if type(inputs[0]) is Quantity: - if self.units != inputs[0].units: - raise qnArrayTwoError('Same units expected') - if inputs[0] is not None: - return qnArrayTwo(np.append(np.asarray(self),inputs[0].value), units = self.units, sd = np.append(self.sd,inputs[0].sd)) - else: - return qnArrayTwo(np.append(np.asarray(self),inputs[0].value), units = self.units, sd = np.append(self.sd,0)) - elif value is not None: - return qnArrayTwo(np.append(np.asarray(self),value), units = self.units, sd = np.append(self.sd,sd)) - + + def append(self, input_quantity): + if self.units != input_quantity.units: + raise qnArrayTwoError('Same units expected') + return qnArrayTwo(np.append(np.asarray(self),input_quantity.value), units = self.units, sd = np.append(self.sd,input_quantity.sd)) + def sd_add_sub(result, vals1, vals2, sd1, sd2): return np.sqrt(sd1**2+sd2**2) def sd_mul_div(result, vals1, vals2, sd1, sd2): return result*np.sqrt((sd1/vals1)**2+(sd2/vals2)**2) - + def sd_logaddexp(result, vals1, vals2, sd1, sd2): return np.sqrt(np.exp(vals1)**2*sd1**2+np.exp(vals2)**2*sd2**2)/(np.exp(vals1)+np.exp(vals2)) def sd_logaddexp2(result, vals1, vals2, sd1, sd2): return np.sqrt(np.exp(vals1)**2*sd1**2+np.exp(vals2)**2*sd2**2)/((np.log(2))*(np.exp(vals1)+np.exp(vals2))) def sd_power(result, vals1, vals2, sd1, sd2): return np.sqrt(sd1**2*(vals2*vals1**(vals2-1))**2 + sd2**2*(result*np.log(vals1))**2) - + def sd_exp(result, vals, sd): return result * sd def sd_sin(result, vals, sd): @@ -167,7 +161,21 @@ def sd_arccosh(result, vals, sd): return sd/(np.sqrt(vals-1)*np.sqrt(vals+1)) def sd_arctanh(result, vals, sd): return sd/(1-vals**2) - + +def units_check_unitless(input_arr): + if input_arr.units.has_units() is True: + raise qnArrayTwoError('qnArray must be unitless') + else: + return input_arr + +def units_check_unitless_deg_rad(input_arr): + if input_arr.units == Units('deg'): + return input_arr.convert_units_to('rad') + elif input_add.units == Units('rad') or input_arr.units.has_units() is True: + return input_add + else: + raise qnArrayTwoError('qnArray must have units: deg, rad, unitless') + def units_add_sub(u1, u2): if u1.has_units() is True: return u1 @@ -177,26 +185,26 @@ def units_mul(u1,u2): return u1*u2 def units_div(u1,u2): return u1/u2 - + ufunc_dict_alg = { np.add: ('__add__', sd_add_sub, units_add_sub, '__radd__'), np.subtract: ('__sub__', sd_add_sub, units_add_sub, '__rsub__'), np.multiply: ('__mul__', sd_mul_div, units_mul, '__rmul__'), np.divide: ('__truediv__', sd_mul_div, units_div, '__rtruediv__')} - -ufunc_dict_other = { np.exp: sd_exp, - np.sin: sd_sin, - np.cos: sd_cos, - np.tan: sd_tan, - np.arcsin: sd_arcsin_arccos, - np.arccos: sd_arcsin_arccos, - np.arctan: sd_arctan, - np.sinh: sd_sinh, - np.cosh: sd_cosh, - np.tanh: sd_tanh, - np.arcsinh: sd_arcsinh, - np.arccosh: sd_arccosh, - np.arctanh: sd_arctanh} - + +ufunc_dict_other = { np.exp: (sd_exp, units_check_unitless), + np.sin: (sd_sin, units_check_unitless_deg_rad), + np.cos: (sd_cos, units_check_unitless_deg_rad), + np.tan: (sd_tan, units_check_unitless_deg_rad), + np.arcsin: (sd_arcsin_arccos, units_check_unitless), + np.arccos: (sd_arcsin_arccos, units_check_unitless), + np.arctan: (sd_arctan, units_check_unitless), + np.sinh: (sd_sinh, units_check_unitless), + np.cosh: (sd_cosh, units_check_unitless), + np.tanh: (sd_tanh, units_check_unitless), + np.arcsinh: (sd_arcsinh, units_check_unitless), + np.arccosh: (sd_arccosh, units_check_unitless), + np.arctanh: (sd_arctanh, units_check_unitless)} + ufunc_dict_otherother = {np.logaddexp: sd_logaddexp, np.logaddexp2: sd_logaddexp2, np.power: sd_power} From cab9536c9620760f6aac7d2654a3078f60083ad1 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 24 Jul 2017 13:05:23 +0100 Subject: [PATCH 090/106] adjust tests for appending only Quantities to qnArrayTwo types --- pyqn/tests/test_qn_array_two.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index 5c6ae88..19aef82 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -180,13 +180,6 @@ def test_qn_array_append(self): self.assertEqual(result1[-1],10) self.assertEqual(len(result2),4) self.assertEqual(result2[-1],5) - - result1 = q1.append(value=2) - result2 = q1.append(value=1,sd=0.5) - self.assertEqual(len(result1),4) - self.assertEqual(result1[-1],2) - self.assertEqual(len(result2),4) - self.assertEqual(result2[-1],1) def test_qn_array_two_ufunc(self): a1 = [1,2,3] From 33ed1063058326db17c5078da5563061446b4a50 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 25 Jul 2017 09:54:24 +0100 Subject: [PATCH 091/106] add more robust testing mechanism for ufuncs --- pyqn/qn_array_two.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index 0bed1dc..ce53e85 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -90,11 +90,12 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): return qnArrayTwo(result_val, units = Units('1'), sd = result_sd) elif ufunc in ufunc_dict_otherother: - if inputs[0].units.has_units() is True: - raise qnArrayTwoError('qnArray must be unitless') - sd_func = ufunc_dict_otherother[ufunc] - result_val = ufunc(np.asarray(inputs[0]),np.asarray(inputs[1])) - result_sd = sd_func(result_val, np.asarray(inputs[0]), np.asarray(inputs[1]), inputs[0].sd, inputs[1].sd) + unit_test_func = ufunc_dict_otherother[ufunc][1] + input1 = unit_test_func(inputs[0]) + input2 = unit_test_func(inputs[1]) + sd_func = ufunc_dict_otherother[ufunc][0] + result_val = ufunc(np.asarray(input1),np.asarray(input2)) + result_sd = sd_func(result_val, np.asarray(input1), np.asarray(input2), input1.sd, input2.sd) return qnArrayTwo(result_val, units = Units('1'), sd = result_sd) def __eq__(self, other): @@ -124,7 +125,7 @@ def append(self, input_quantity): if self.units != input_quantity.units: raise qnArrayTwoError('Same units expected') return qnArrayTwo(np.append(np.asarray(self),input_quantity.value), units = self.units, sd = np.append(self.sd,input_quantity.sd)) - + def sd_add_sub(result, vals1, vals2, sd1, sd2): return np.sqrt(sd1**2+sd2**2) def sd_mul_div(result, vals1, vals2, sd1, sd2): @@ -205,9 +206,9 @@ def units_div(u1,u2): np.arccosh: (sd_arccosh, units_check_unitless), np.arctanh: (sd_arctanh, units_check_unitless)} -ufunc_dict_otherother = {np.logaddexp: sd_logaddexp, - np.logaddexp2: sd_logaddexp2, - np.power: sd_power} +ufunc_dict_otherother = {np.logaddexp: (sd_logaddexp, units_check_unitless), + np.logaddexp2: (sd_logaddexp2, units_check_unitless), + np.power: (sd_power, units_check_unitless)} def plot_qn_arrays(qn_arr_1, qn_arr_2): plt.errorbar(np.asarray(qn_arr_1),np.asarray(qn_arr_2),xerr = qn_arr_1.sd, yerr = qn_arr_2.sd) From a602c03f68b2620392b7c1681fd8ae96bff52150 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 25 Jul 2017 12:47:20 +0100 Subject: [PATCH 092/106] add true_divide, floor_divide, and negative ufuncs --- pyqn/qn_array_two.py | 67 ++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index ce53e85..5fe331d 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -81,21 +81,26 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): result_units = units_func(Units('1'), inputs[1].units) return qnArrayTwo(result_val, units = result_units, sd = result_sd) - elif ufunc in ufunc_dict_other: - unit_test_func = ufunc_dict_other[ufunc][1] + + elif ufunc in ufunc_dict_one_input: + unit_test_func = ufunc_dict_one_input[ufunc][1] inputs_checked = unit_test_func(inputs[0]) - sd_func = ufunc_dict_other[ufunc][0] + sd_func = ufunc_dict_one_input[ufunc][0] + units_func = ufunc_dict_one_input[ufunc][2] result_val = ufunc(np.asarray(inputs_checked)) result_sd = sd_func(result_val, np.asarray(inputs_checked), inputs_checked.sd) - return qnArrayTwo(result_val, units = Units('1'), sd = result_sd) + result_units = units_func(inputs[0].units) + return qnArrayTwo(result_val, units = result_units, sd = result_sd) - elif ufunc in ufunc_dict_otherother: - unit_test_func = ufunc_dict_otherother[ufunc][1] + elif ufunc in ufunc_dict_two_inputs: + unit_test_func = ufunc_dict_two_inputs[ufunc][1] input1 = unit_test_func(inputs[0]) input2 = unit_test_func(inputs[1]) - sd_func = ufunc_dict_otherother[ufunc][0] + sd_func = ufunc_dict_two_inputs[ufunc][0] + units_func = ufunc_dict_two_inputs[ufunc][2] result_val = ufunc(np.asarray(input1),np.asarray(input2)) result_sd = sd_func(result_val, np.asarray(input1), np.asarray(input2), input1.sd, input2.sd) + result_units = units_func(input1.units, input2.units) return qnArrayTwo(result_val, units = Units('1'), sd = result_sd) def __eq__(self, other): @@ -162,6 +167,8 @@ def sd_arccosh(result, vals, sd): return sd/(np.sqrt(vals-1)*np.sqrt(vals+1)) def sd_arctanh(result, vals, sd): return sd/(1-vals**2) +def sd_nochange(result, vals, sd): + return sd def units_check_unitless(input_arr): if input_arr.units.has_units() is True: @@ -177,6 +184,9 @@ def units_check_unitless_deg_rad(input_arr): else: raise qnArrayTwoError('qnArray must have units: deg, rad, unitless') +def units_check_any(input_arr): + return input_arr + def units_add_sub(u1, u2): if u1.has_units() is True: return u1 @@ -186,29 +196,38 @@ def units_mul(u1,u2): return u1*u2 def units_div(u1,u2): return u1/u2 +def units_unitless(u): + return Units('1') +def units_self(u): + return u +def units_unitless2(u1,u2): + return Units('1') ufunc_dict_alg = { np.add: ('__add__', sd_add_sub, units_add_sub, '__radd__'), np.subtract: ('__sub__', sd_add_sub, units_add_sub, '__rsub__'), np.multiply: ('__mul__', sd_mul_div, units_mul, '__rmul__'), np.divide: ('__truediv__', sd_mul_div, units_div, '__rtruediv__')} -ufunc_dict_other = { np.exp: (sd_exp, units_check_unitless), - np.sin: (sd_sin, units_check_unitless_deg_rad), - np.cos: (sd_cos, units_check_unitless_deg_rad), - np.tan: (sd_tan, units_check_unitless_deg_rad), - np.arcsin: (sd_arcsin_arccos, units_check_unitless), - np.arccos: (sd_arcsin_arccos, units_check_unitless), - np.arctan: (sd_arctan, units_check_unitless), - np.sinh: (sd_sinh, units_check_unitless), - np.cosh: (sd_cosh, units_check_unitless), - np.tanh: (sd_tanh, units_check_unitless), - np.arcsinh: (sd_arcsinh, units_check_unitless), - np.arccosh: (sd_arccosh, units_check_unitless), - np.arctanh: (sd_arctanh, units_check_unitless)} - -ufunc_dict_otherother = {np.logaddexp: (sd_logaddexp, units_check_unitless), - np.logaddexp2: (sd_logaddexp2, units_check_unitless), - np.power: (sd_power, units_check_unitless)} +ufunc_dict_one_input = { np.exp: (sd_exp, units_check_unitless, units_unitless), + np.sin: (sd_sin, units_check_unitless_deg_rad, units_unitless), + np.cos: (sd_cos, units_check_unitless_deg_rad, units_unitless), + np.tan: (sd_tan, units_check_unitless_deg_rad, units_unitless), + np.arcsin: (sd_arcsin_arccos, units_check_unitless, units_unitless), + np.arccos: (sd_arcsin_arccos, units_check_unitless, units_unitless), + np.arctan: (sd_arctan, units_check_unitless, units_unitless), + np.sinh: (sd_sinh, units_check_unitless, units_unitless), + np.cosh: (sd_cosh, units_check_unitless, units_unitless), + np.tanh: (sd_tanh, units_check_unitless, units_unitless), + np.arcsinh: (sd_arcsinh, units_check_unitless, units_unitless), + np.arccosh: (sd_arccosh, units_check_unitless, units_unitless), + np.arctanh: (sd_arctanh, units_check_unitless, units_unitless), + np.negative: (sd_nochange, units_check_any, units_self)} + +ufunc_dict_two_inputs = {np.logaddexp: (sd_logaddexp, units_check_unitless, units_unitless2), + np.logaddexp2: (sd_logaddexp2, units_check_unitless, units_unitless2), + np.power: (sd_power, units_check_unitless, units_unitless2), + np.true_divide: (sd_mul_div, units_check_any, units_div), + np.floor_divide: (sd_mul_div, units_check_any, units_div)} def plot_qn_arrays(qn_arr_1, qn_arr_2): plt.errorbar(np.asarray(qn_arr_1),np.asarray(qn_arr_2),xerr = qn_arr_1.sd, yerr = qn_arr_2.sd) From 2bca37140173648c02d0721bdfb647c69f6e4083 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 27 Jul 2017 01:34:50 +0100 Subject: [PATCH 093/106] fix minor bug --- pyqn/qn_array_two.py | 106 +++---------------------------------------- 1 file changed, 7 insertions(+), 99 deletions(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index 5fe331d..5d650ca 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -1,6 +1,7 @@ import numpy as np from .units import Units from .quantity import Quantity +from .ufunc_dictionaries import * import matplotlib.pyplot as plt class qnArrayTwoError(Exception): @@ -83,12 +84,17 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): return qnArrayTwo(result_val, units = result_units, sd = result_sd) elif ufunc in ufunc_dict_one_input: + #checks if units of input are valid unit_test_func = ufunc_dict_one_input[ufunc][1] inputs_checked = unit_test_func(inputs[0]) + + #extracts functions for finding sd and units sd_func = ufunc_dict_one_input[ufunc][0] units_func = ufunc_dict_one_input[ufunc][2] + + #calculates results result_val = ufunc(np.asarray(inputs_checked)) - result_sd = sd_func(result_val, np.asarray(inputs_checked), inputs_checked.sd) + result_sd = sd_func(result_val, np.asarray(inputs_checked), np.asarray(inputs_checked.sd)) result_units = units_func(inputs[0].units) return qnArrayTwo(result_val, units = result_units, sd = result_sd) @@ -131,104 +137,6 @@ def append(self, input_quantity): raise qnArrayTwoError('Same units expected') return qnArrayTwo(np.append(np.asarray(self),input_quantity.value), units = self.units, sd = np.append(self.sd,input_quantity.sd)) -def sd_add_sub(result, vals1, vals2, sd1, sd2): - return np.sqrt(sd1**2+sd2**2) -def sd_mul_div(result, vals1, vals2, sd1, sd2): - return result*np.sqrt((sd1/vals1)**2+(sd2/vals2)**2) - -def sd_logaddexp(result, vals1, vals2, sd1, sd2): - return np.sqrt(np.exp(vals1)**2*sd1**2+np.exp(vals2)**2*sd2**2)/(np.exp(vals1)+np.exp(vals2)) -def sd_logaddexp2(result, vals1, vals2, sd1, sd2): - return np.sqrt(np.exp(vals1)**2*sd1**2+np.exp(vals2)**2*sd2**2)/((np.log(2))*(np.exp(vals1)+np.exp(vals2))) -def sd_power(result, vals1, vals2, sd1, sd2): - return np.sqrt(sd1**2*(vals2*vals1**(vals2-1))**2 + sd2**2*(result*np.log(vals1))**2) - -def sd_exp(result, vals, sd): - return result * sd -def sd_sin(result, vals, sd): - return np.cos(vals) * sd -def sd_cos(result, vals, sd): - return np.sin(vals) * sd -def sd_tan(result, vals, sd): - return np.cos(vals)**(-2) * sd -def sd_arcsin_arccos(result, vals, sd): - return sd/np.sqrt(1-vals**2) -def sd_arctan(result, vals, sd): - return sd/(1+vals**2) -def sd_sinh(result, vals, sd): - return sd*np.cosh(vals) -def sd_cosh(result, vals, sd): - return sd*np.sinh(vals) -def sd_tanh(result, vals, sd): - return sd*np.cosh(vals)**(-2) -def sd_arcsinh(result, vals, sd): - return sd/np.sqrt(1+vals**2) -def sd_arccosh(result, vals, sd): - return sd/(np.sqrt(vals-1)*np.sqrt(vals+1)) -def sd_arctanh(result, vals, sd): - return sd/(1-vals**2) -def sd_nochange(result, vals, sd): - return sd - -def units_check_unitless(input_arr): - if input_arr.units.has_units() is True: - raise qnArrayTwoError('qnArray must be unitless') - else: - return input_arr - -def units_check_unitless_deg_rad(input_arr): - if input_arr.units == Units('deg'): - return input_arr.convert_units_to('rad') - elif input_add.units == Units('rad') or input_arr.units.has_units() is True: - return input_add - else: - raise qnArrayTwoError('qnArray must have units: deg, rad, unitless') - -def units_check_any(input_arr): - return input_arr - -def units_add_sub(u1, u2): - if u1.has_units() is True: - return u1 - else: - return u2 -def units_mul(u1,u2): - return u1*u2 -def units_div(u1,u2): - return u1/u2 -def units_unitless(u): - return Units('1') -def units_self(u): - return u -def units_unitless2(u1,u2): - return Units('1') - -ufunc_dict_alg = { np.add: ('__add__', sd_add_sub, units_add_sub, '__radd__'), - np.subtract: ('__sub__', sd_add_sub, units_add_sub, '__rsub__'), - np.multiply: ('__mul__', sd_mul_div, units_mul, '__rmul__'), - np.divide: ('__truediv__', sd_mul_div, units_div, '__rtruediv__')} - -ufunc_dict_one_input = { np.exp: (sd_exp, units_check_unitless, units_unitless), - np.sin: (sd_sin, units_check_unitless_deg_rad, units_unitless), - np.cos: (sd_cos, units_check_unitless_deg_rad, units_unitless), - np.tan: (sd_tan, units_check_unitless_deg_rad, units_unitless), - np.arcsin: (sd_arcsin_arccos, units_check_unitless, units_unitless), - np.arccos: (sd_arcsin_arccos, units_check_unitless, units_unitless), - np.arctan: (sd_arctan, units_check_unitless, units_unitless), - np.sinh: (sd_sinh, units_check_unitless, units_unitless), - np.cosh: (sd_cosh, units_check_unitless, units_unitless), - np.tanh: (sd_tanh, units_check_unitless, units_unitless), - np.arcsinh: (sd_arcsinh, units_check_unitless, units_unitless), - np.arccosh: (sd_arccosh, units_check_unitless, units_unitless), - np.arctanh: (sd_arctanh, units_check_unitless, units_unitless), - np.negative: (sd_nochange, units_check_any, units_self)} - -ufunc_dict_two_inputs = {np.logaddexp: (sd_logaddexp, units_check_unitless, units_unitless2), - np.logaddexp2: (sd_logaddexp2, units_check_unitless, units_unitless2), - np.power: (sd_power, units_check_unitless, units_unitless2), - np.true_divide: (sd_mul_div, units_check_any, units_div), - np.floor_divide: (sd_mul_div, units_check_any, units_div)} - def plot_qn_arrays(qn_arr_1, qn_arr_2): plt.errorbar(np.asarray(qn_arr_1),np.asarray(qn_arr_2),xerr = qn_arr_1.sd, yerr = qn_arr_2.sd) plt.show() From 37e3abeab6be0783e0ecddecae844b0af0e2337e Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 27 Jul 2017 01:35:49 +0100 Subject: [PATCH 094/106] rearrange testing mechanism to loop over reworked ufuncs --- pyqn/tests/test_qn_array_two.py | 129 +++++++++++++++++++++++--------- 1 file changed, 92 insertions(+), 37 deletions(-) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index 19aef82..bae2e6a 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -2,6 +2,7 @@ from ..qn_array_two import qnArrayTwo, qnArrayTwoError from ..units import Units from ..quantity import Quantity +from ..ufunc_dictionaries import * import numpy as np class qnArrayTwoTest(unittest.TestCase): @@ -188,45 +189,99 @@ def test_qn_array_two_ufunc(self): sd2 = [0.01,0.02,0.03] q1 = qnArrayTwo(a1,units = 'm', sd = sd1) q2 = qnArrayTwo(a2,units = 'm', sd = sd2) - add = np.add(q1,q2) + q3 = qnArrayTwo(a2,units = 's', sd = sd2) + for ufunc in ufunc_dict_alg: + if (ufunc is np.multiply) or (ufunc is np.divide): + in1 = q1 + in2 = q3 + elif (ufunc is np.add) or (ufunc is np.subtract): + in1 = q1 + in2 = q2 + result = ufunc(in1, in2) + + sd_func = ufunc_dict_alg[ufunc][1] + units_func = ufunc_dict_alg[ufunc][2] + + self.assertTrue(result.units, units_func(in1.units, in2.units)) + for i in range(3): + self.assertEqual(result[i], ufunc(np.asarray(in1), np.asarray(in2))[i]) + self.assertEqual(result.sd[i], sd_func(np.asarray(result), np.asarray(in1), np.asarray(in2), in1.sd, in2.sd)[i]) + + print('{} tested!'.format(ufunc)) + + a1 = [0.1,0.2,0.3] + sd1 = [0.01,0.02,0.03] q3 = qnArrayTwo(a1, units = '1', sd = sd1) - q33 = qnArrayTwo(a2, units = '1', sd = sd2) - q4 = np.exp(q3) - q5 = np.sin(q3) - q6 = np.cos(q3) - q7 = np.tan(q3) - q8 = np.arcsin(q33) - q9 = np.arccos(q33) - q10 = np.arctan(q33) - q11 = np.sinh(q33) - q12 = np.cosh(q33) - q13 = np.tanh(q33) - q14 = np.logaddexp(q3,q33) - q15 = np.power(q3,q33) - for i in range(3): - self.assertAlmostEqual(q4[i], np.exp(a1[i])) - self.assertAlmostEqual(q4.sd[i], q4[i]*q3.sd[i]) - self.assertAlmostEqual(q5[i], np.sin(a1[i])) - self.assertAlmostEqual(q5.sd[i], np.cos(a1[i])*sd1[i]) - self.assertAlmostEqual(q6[i], np.cos(a1[i])) - self.assertAlmostEqual(q6.sd[i], np.sin(a1[i])*sd1[i]) - self.assertAlmostEqual(q7[i], np.tan(a1[i])) - #self.assertAlmostEqual(q7.sd[i], np.cos(a1[i])**(-2)*sd1[i]) - self.assertAlmostEqual(q8[i], np.arcsin(a2[i])) - #self.assertAlmostEqual(q8.sd[i], sd2[i]/np.sqrt(1-sd2[i]**2)) - self.assertAlmostEqual(q9[i], np.arccos(a2[i])) - #self.assertAlmostEqual(q9.sd[i], sd2[i]/np.sqrt(1-sd2[i]**2)) - self.assertAlmostEqual(q10[i], np.arctan(a2[i])) - #self.assertAlmostEqual(q10.sd[i], sd2[i]*np.cosh(a2[i])**(-2)) - self.assertAlmostEqual(q11[i], np.sinh(a2[i])) - self.assertAlmostEqual(q11.sd[i], sd2[i]*np.cosh(a2[i])) - self.assertAlmostEqual(q12[i], np.cosh(a2[i])) - self.assertAlmostEqual(q12.sd[i], sd2[i]*np.sinh(a2[i])) - self.assertAlmostEqual(q13[i], np.tanh(a2[i])) - self.assertAlmostEqual(q13.sd[i], sd2[i]*np.cosh(a2[i])**(-2)) - self.assertAlmostEqual(q14[i], np.logaddexp(a1[i], a2[i])) - self.assertAlmostEqual(q15[i], np.power(np.asarray(q3[i]),np.asarray(q33[i]))) + q4 = qnArrayTwo(a1, units = 'rad', sd = sd1) + q5 = qnArrayTwo(a1, units = 'deg', sd = sd1) + + #~ for ufunc in ufunc_dict_one_input: + #~ unit_test = ufunc_dict_one_input[ufunc][1] + #~ if unit_test is units_check_unitless: + #~ with self.assertRaises(Exception) as e: + #~ ufunc(q1) + #~ with self.assertRaises(Exception) as e: + #~ ufunc(q2) + #~ with self.assertRaises(Exception) as e: + #~ ufunc(q4) + #~ with self.assertRaises(Exception) as e: + #~ ufunc(q5) + #~ in1 = [q3] + #~ r = [ufunc(q3)] + #~ elif unit_test is units_check_unitless_deg_rad: + #~ with self.assertRaises(Exception) as e: + #~ ufunc(q1) + #~ with self.assertRaises(Exception) as e: + #~ ufunc(q2) + #~ in1 = [q3, q4, q5] + #~ r = [ufunc(q3), ufunc(q4), ufunc(q5)] + #~ sd_func = ufunc_dict_one_input[ufunc][0] #(result, vals, sd) + #~ units_func = ufunc_dict_one_input[ufunc][2] #(units) + + #~ for result, input1 in zip(r,in1): + #~ self.assertEqual(result.units, units_func(input1.units)) + #~ for i in range(3): + #~ self.assertAlmostEqual(result[i], ufunc(np.asarray(input1))[i], places = 1) + #~ self.assertAlmostEqual(result.sd[i], sd_func(result, input1, input1.sd)[i],places = 1) + + #~ print('{} tested!'.format(ufunc)) + + #~ q4 = np.exp(q3) + #~ q5 = np.sin(q3) + #~ q6 = np.cos(q3) + #~ q7 = np.tan(q3) + #~ q8 = np.arcsin(q33) + #~ q9 = np.arccos(q33) + #~ q10 = np.arctan(q33) + #~ q11 = np.sinh(q33) + #~ q12 = np.cosh(q33) + #~ q13 = np.tanh(q33) + #~ q14 = np.logaddexp(q3,q33) + #~ q15 = np.power(q3,q33) + #~ for i in range(3): + #~ self.assertAlmostEqual(q4[i], np.exp(a1[i])) + #~ self.assertAlmostEqual(q4.sd[i], q4[i]*q3.sd[i]) + #~ self.assertAlmostEqual(q5[i], np.sin(a1[i])) + #~ self.assertAlmostEqual(q5.sd[i], np.cos(a1[i])*sd1[i]) + #~ self.assertAlmostEqual(q6[i], np.cos(a1[i])) + #~ self.assertAlmostEqual(q6.sd[i], np.sin(a1[i])*sd1[i]) + #~ self.assertAlmostEqual(q7[i], np.tan(a1[i])) + #~ #self.assertAlmostEqual(q7.sd[i], np.cos(a1[i])**(-2)*sd1[i]) + #~ self.assertAlmostEqual(q8[i], np.arcsin(a2[i])) + #~ #self.assertAlmostEqual(q8.sd[i], sd2[i]/np.sqrt(1-sd2[i]**2)) + #~ self.assertAlmostEqual(q9[i], np.arccos(a2[i])) + #~ #self.assertAlmostEqual(q9.sd[i], sd2[i]/np.sqrt(1-sd2[i]**2)) + #~ self.assertAlmostEqual(q10[i], np.arctan(a2[i])) + #~ #self.assertAlmostEqual(q10.sd[i], sd2[i]*np.cosh(a2[i])**(-2)) + #~ self.assertAlmostEqual(q11[i], np.sinh(a2[i])) + #~ self.assertAlmostEqual(q11.sd[i], sd2[i]*np.cosh(a2[i])) + #~ self.assertAlmostEqual(q12[i], np.cosh(a2[i])) + #~ self.assertAlmostEqual(q12.sd[i], sd2[i]*np.sinh(a2[i])) + #~ self.assertAlmostEqual(q13[i], np.tanh(a2[i])) + #~ self.assertAlmostEqual(q13.sd[i], sd2[i]*np.cosh(a2[i])**(-2)) + #~ self.assertAlmostEqual(q14[i], np.logaddexp(a1[i], a2[i])) + #~ self.assertAlmostEqual(q15[i], np.power(np.asarray(q3[i]),np.asarray(q33[i]))) if __name__ == '__main__': unittest.main() From 2ac3fdbea6b381ca77e230d0af84bc575dda336c Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Thu, 27 Jul 2017 01:36:23 +0100 Subject: [PATCH 095/106] add separate file for ufuncs and error calculation function --- pyqn/ufunc_dictionaries.py | 102 +++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 pyqn/ufunc_dictionaries.py diff --git a/pyqn/ufunc_dictionaries.py b/pyqn/ufunc_dictionaries.py new file mode 100644 index 0000000..239d0ea --- /dev/null +++ b/pyqn/ufunc_dictionaries.py @@ -0,0 +1,102 @@ +from .units import Units, UnitsError +import numpy as np + +def sd_add_sub(result, vals1, vals2, sd1, sd2): + return np.sqrt(sd1**2+sd2**2) +def sd_mul_div(result, vals1, vals2, sd1, sd2): + return result*np.sqrt((sd1/vals1)**2+(sd2/vals2)**2) + +def sd_logaddexp(result, vals1, vals2, sd1, sd2): + return np.sqrt(np.exp(vals1)**2*sd1**2+np.exp(vals2)**2*sd2**2)/(np.exp(vals1)+np.exp(vals2)) +def sd_logaddexp2(result, vals1, vals2, sd1, sd2): + return np.sqrt(np.exp(vals1)**2*sd1**2+np.exp(vals2)**2*sd2**2)/((np.log(2))*(np.exp(vals1)+np.exp(vals2))) +def sd_power(result, vals1, vals2, sd1, sd2): + return np.sqrt(sd1**2*(vals2*vals1**(vals2-1))**2 + sd2**2*(result*np.log(vals1))**2) + +def sd_exp(result, vals, sd): + return result * sd +def sd_sin(result, vals, sd): + return np.cos(vals) * sd +def sd_cos(result, vals, sd): + return np.sin(vals) * sd +def sd_tan(result, vals, sd): + return np.cos(vals)**(-2) * sd +def sd_arcsin_arccos(result, vals, sd): + return np.asarray(sd)/np.sqrt(1-np.asarray(vals)**2) +def sd_arctan(result, vals, sd): + return np.asarray(sd)/(1.0+np.asarray(vals)**2) +def sd_sinh(result, vals, sd): + return sd*np.cosh(vals) +def sd_cosh(result, vals, sd): + return sd*np.sinh(vals) +def sd_tanh(result, vals, sd): + return np.asarray(sd)*np.cosh(np.asarray(vals))**(-2) +def sd_arcsinh(result, vals, sd): + return np.asarray(sd)/np.sqrt(1+np.asarray(vals)**2) +def sd_arccosh(result, vals, sd): + return sd/(np.sqrt(vals-1)*np.sqrt(vals+1)) +def sd_arctanh(result, vals, sd): + return np.asarray(sd)/(1.0-np.asarray(vals)**2) +def sd_nochange(result, vals, sd): + return sd + +def units_check_unitless(input_arr): + if input_arr.units.has_units() is True: + raise UnitsError('qnArray must be unitless') + else: + return input_arr + +def units_check_unitless_deg_rad(input_arr): + if input_arr.units == Units('deg'): + return input_arr.convert_units_to('rad') + elif (input_add.units == Units('rad')) or (input_arr.units.has_units() is False): + return input_arr + else: + raise UnitsError('qnArray must have units: deg, rad, unitless') + +def units_check_any(input_arr): + return input_arr + +def units_add_sub(u1, u2): + if u1.has_units() is True: + return u1 + else: + return u2 +def units_mul(u1,u2): + return u1*u2 +def units_div(u1,u2): + return u1/u2 +def units_unitless(u): + return Units('1') +def units_self(u): + return u +def units_unitless2(u1,u2): + return Units('1') + +ufunc_dict_alg = { np.add: ('__add__', sd_add_sub, units_add_sub, '__radd__'), + np.subtract: ('__sub__', sd_add_sub, units_add_sub, '__rsub__'), + np.multiply: ('__mul__', sd_mul_div, units_mul, '__rmul__'), + np.divide: ('__truediv__', sd_mul_div, units_div, '__rtruediv__')} + +ufunc_dict_one_input = {np.exp: (sd_exp, units_check_unitless, units_unitless), + np.sin: (sd_sin, units_check_unitless_deg_rad, units_unitless), + np.cos: (sd_cos, units_check_unitless_deg_rad, units_unitless), + np.tan: (sd_tan, units_check_unitless_deg_rad, units_unitless), + #np.arcsin: (sd_arcsin_arccos, units_check_unitless, units_unitless), + #np.arccos: (sd_arcsin_arccos, units_check_unitless, units_unitless), + #np.arctan: (sd_arctan, units_check_unitless, units_unitless), + #np.sinh: (sd_sinh, units_check_unitless, units_unitless), + #np.cosh: (sd_cosh, units_check_unitless, units_unitless), + #np.tanh: (sd_tanh, units_check_unitless, units_unitless), + #np.arcsinh: (sd_arcsinh, units_check_unitless, units_unitless), + #np.arccosh: (sd_arccosh, units_check_unitless, units_unitless), + #np.arctanh: (sd_arctanh, units_check_unitless, units_unitless), + #np.negative: (sd_nochange, units_check_any, units_self) + } + +ufunc_dict_two_inputs = {np.logaddexp: (sd_logaddexp, units_check_unitless, units_unitless2), + np.logaddexp2: (sd_logaddexp2, units_check_unitless, units_unitless2), + np.power: (sd_power, units_check_unitless, units_unitless2), + np.true_divide: (sd_mul_div, units_check_any, units_div), + np.floor_divide: (sd_mul_div, units_check_any, units_div)} + From 215c295cffa7423ecef15cdf71227c93341289bb Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 26 Jul 2017 14:05:31 +0100 Subject: [PATCH 096/106] fix minor bugs --- pyqn/tests/test_qn_array_two.py | 86 ++++++++++++++++----------------- pyqn/ufunc_dictionaries.py | 2 +- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index bae2e6a..c0c256b 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -191,24 +191,24 @@ def test_qn_array_two_ufunc(self): q2 = qnArrayTwo(a2,units = 'm', sd = sd2) q3 = qnArrayTwo(a2,units = 's', sd = sd2) - for ufunc in ufunc_dict_alg: - if (ufunc is np.multiply) or (ufunc is np.divide): - in1 = q1 - in2 = q3 - elif (ufunc is np.add) or (ufunc is np.subtract): - in1 = q1 - in2 = q2 - result = ufunc(in1, in2) + #~ for ufunc in ufunc_dict_alg: + #~ if (ufunc is np.multiply) or (ufunc is np.divide): + #~ in1 = q1 + #~ in2 = q3 + #~ elif (ufunc is np.add) or (ufunc is np.subtract): + #~ in1 = q1 + #~ in2 = q2 + #~ result = ufunc(in1, in2) - sd_func = ufunc_dict_alg[ufunc][1] - units_func = ufunc_dict_alg[ufunc][2] + #~ sd_func = ufunc_dict_alg[ufunc][1] + #~ units_func = ufunc_dict_alg[ufunc][2] - self.assertTrue(result.units, units_func(in1.units, in2.units)) - for i in range(3): - self.assertEqual(result[i], ufunc(np.asarray(in1), np.asarray(in2))[i]) - self.assertEqual(result.sd[i], sd_func(np.asarray(result), np.asarray(in1), np.asarray(in2), in1.sd, in2.sd)[i]) + #~ self.assertTrue(result.units, units_func(in1.units, in2.units)) + #~ for i in range(3): + #~ self.assertEqual(result[i], ufunc(np.asarray(in1), np.asarray(in2))[i]) + #~ self.assertEqual(result.sd[i], sd_func(np.asarray(result), np.asarray(in1), np.asarray(in2), in1.sd, in2.sd)[i]) - print('{} tested!'.format(ufunc)) + #~ print('{} tested!'.format(ufunc)) a1 = [0.1,0.2,0.3] sd1 = [0.01,0.02,0.03] @@ -216,36 +216,36 @@ def test_qn_array_two_ufunc(self): q4 = qnArrayTwo(a1, units = 'rad', sd = sd1) q5 = qnArrayTwo(a1, units = 'deg', sd = sd1) - #~ for ufunc in ufunc_dict_one_input: - #~ unit_test = ufunc_dict_one_input[ufunc][1] - #~ if unit_test is units_check_unitless: - #~ with self.assertRaises(Exception) as e: - #~ ufunc(q1) - #~ with self.assertRaises(Exception) as e: - #~ ufunc(q2) - #~ with self.assertRaises(Exception) as e: - #~ ufunc(q4) - #~ with self.assertRaises(Exception) as e: - #~ ufunc(q5) - #~ in1 = [q3] - #~ r = [ufunc(q3)] - #~ elif unit_test is units_check_unitless_deg_rad: - #~ with self.assertRaises(Exception) as e: - #~ ufunc(q1) - #~ with self.assertRaises(Exception) as e: - #~ ufunc(q2) - #~ in1 = [q3, q4, q5] - #~ r = [ufunc(q3), ufunc(q4), ufunc(q5)] - #~ sd_func = ufunc_dict_one_input[ufunc][0] #(result, vals, sd) - #~ units_func = ufunc_dict_one_input[ufunc][2] #(units) + for ufunc in ufunc_dict_one_input: + unit_test = ufunc_dict_one_input[ufunc][1] + if unit_test is units_check_unitless: + with self.assertRaises(Exception) as e: + ufunc(q1) + with self.assertRaises(Exception) as e: + ufunc(q2) + with self.assertRaises(Exception) as e: + ufunc(q4) + with self.assertRaises(Exception) as e: + ufunc(q5) + in1 = [unit_test(q3)] + r = [ufunc(in1[0])] + elif unit_test is units_check_unitless_deg_rad: + with self.assertRaises(Exception) as e: + ufunc(q1) + with self.assertRaises(Exception) as e: + ufunc(q2) + in1 = [unit_test(q3), unit_test(q4), unit_test(q5)] + r = [ufunc(in1[0]), ufunc(in1[1]), ufunc(in1[2])] + sd_func = ufunc_dict_one_input[ufunc][0] #(result, vals, sd) + units_func = ufunc_dict_one_input[ufunc][2] #(units) - #~ for result, input1 in zip(r,in1): - #~ self.assertEqual(result.units, units_func(input1.units)) - #~ for i in range(3): - #~ self.assertAlmostEqual(result[i], ufunc(np.asarray(input1))[i], places = 1) - #~ self.assertAlmostEqual(result.sd[i], sd_func(result, input1, input1.sd)[i],places = 1) + for result, input1 in zip(r,in1): + self.assertEqual(result.units, units_func(input1.units)) + for i in range(3): + self.assertAlmostEqual(result[i], ufunc(np.asarray(input1))[i], places = 2) + self.assertAlmostEqual(result.sd[i], sd_func(result, input1, input1.sd)[i],places = 1) - #~ print('{} tested!'.format(ufunc)) + print('{} tested!'.format(ufunc)) #~ q4 = np.exp(q3) #~ q5 = np.sin(q3) diff --git a/pyqn/ufunc_dictionaries.py b/pyqn/ufunc_dictionaries.py index 239d0ea..0664b49 100644 --- a/pyqn/ufunc_dictionaries.py +++ b/pyqn/ufunc_dictionaries.py @@ -20,7 +20,7 @@ def sd_sin(result, vals, sd): def sd_cos(result, vals, sd): return np.sin(vals) * sd def sd_tan(result, vals, sd): - return np.cos(vals)**(-2) * sd + return np.cos(np.asarray(vals))**(-2) * np.asarray(sd) def sd_arcsin_arccos(result, vals, sd): return np.asarray(sd)/np.sqrt(1-np.asarray(vals)**2) def sd_arctan(result, vals, sd): From afb2f0c13c36664a3ae0bbcdc5197bed245949d3 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 26 Jul 2017 14:06:27 +0100 Subject: [PATCH 097/106] complete testing of all ufuncs in ufunc_dict_one_input --- pyqn/ufunc_dictionaries.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pyqn/ufunc_dictionaries.py b/pyqn/ufunc_dictionaries.py index 0664b49..4993f50 100644 --- a/pyqn/ufunc_dictionaries.py +++ b/pyqn/ufunc_dictionaries.py @@ -82,12 +82,12 @@ def units_unitless2(u1,u2): np.sin: (sd_sin, units_check_unitless_deg_rad, units_unitless), np.cos: (sd_cos, units_check_unitless_deg_rad, units_unitless), np.tan: (sd_tan, units_check_unitless_deg_rad, units_unitless), - #np.arcsin: (sd_arcsin_arccos, units_check_unitless, units_unitless), - #np.arccos: (sd_arcsin_arccos, units_check_unitless, units_unitless), - #np.arctan: (sd_arctan, units_check_unitless, units_unitless), - #np.sinh: (sd_sinh, units_check_unitless, units_unitless), - #np.cosh: (sd_cosh, units_check_unitless, units_unitless), - #np.tanh: (sd_tanh, units_check_unitless, units_unitless), + np.arcsin: (sd_arcsin_arccos, units_check_unitless, units_unitless), + np.arccos: (sd_arcsin_arccos, units_check_unitless, units_unitless), + np.arctan: (sd_arctan, units_check_unitless, units_unitless), + np.sinh: (sd_sinh, units_check_unitless, units_unitless), + np.cosh: (sd_cosh, units_check_unitless, units_unitless), + np.tanh: (sd_tanh, units_check_unitless, units_unitless), #np.arcsinh: (sd_arcsinh, units_check_unitless, units_unitless), #np.arccosh: (sd_arccosh, units_check_unitless, units_unitless), #np.arctanh: (sd_arctanh, units_check_unitless, units_unitless), From 05e5c781b7b2e1b1356ef6187a51f995fd538447 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 26 Jul 2017 15:15:42 +0100 Subject: [PATCH 098/106] add changing of units given a ufunc with two inputs --- pyqn/qn_array_two.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py index 5d650ca..ce81a4d 100644 --- a/pyqn/qn_array_two.py +++ b/pyqn/qn_array_two.py @@ -107,7 +107,7 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): result_val = ufunc(np.asarray(input1),np.asarray(input2)) result_sd = sd_func(result_val, np.asarray(input1), np.asarray(input2), input1.sd, input2.sd) result_units = units_func(input1.units, input2.units) - return qnArrayTwo(result_val, units = Units('1'), sd = result_sd) + return qnArrayTwo(result_val, units = result_units, sd = result_sd) def __eq__(self, other): if all(super(qnArrayTwo, self).__eq__(super(qnArrayTwo, other))) and (self.units == other.units): From 93d79e1b9ef391d5b23664b470bcfb5a2104e487 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 26 Jul 2017 15:15:58 +0100 Subject: [PATCH 099/106] add testing of ufuncs with two inputs --- pyqn/tests/test_qn_array_two.py | 77 ++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py index c0c256b..7f92258 100644 --- a/pyqn/tests/test_qn_array_two.py +++ b/pyqn/tests/test_qn_array_two.py @@ -212,9 +212,12 @@ def test_qn_array_two_ufunc(self): a1 = [0.1,0.2,0.3] sd1 = [0.01,0.02,0.03] + a2 = [0.4,0.5,0.6] + sd2 = [0.04,0.05,0.06] q3 = qnArrayTwo(a1, units = '1', sd = sd1) q4 = qnArrayTwo(a1, units = 'rad', sd = sd1) q5 = qnArrayTwo(a1, units = 'deg', sd = sd1) + q6 = qnArrayTwo(a2, units = '1', sd = sd2) for ufunc in ufunc_dict_one_input: unit_test = ufunc_dict_one_input[ufunc][1] @@ -236,6 +239,9 @@ def test_qn_array_two_ufunc(self): ufunc(q2) in1 = [unit_test(q3), unit_test(q4), unit_test(q5)] r = [ufunc(in1[0]), ufunc(in1[1]), ufunc(in1[2])] + elif unit_test is units_check_any: + in1 = [unit_test(q1), unit_test(q2), unit_test(q3), unit_test(q4), unit_test(q5)] + r = [ufunc(i) for i in in1] sd_func = ufunc_dict_one_input[ufunc][0] #(result, vals, sd) units_func = ufunc_dict_one_input[ufunc][2] #(units) @@ -246,42 +252,41 @@ def test_qn_array_two_ufunc(self): self.assertAlmostEqual(result.sd[i], sd_func(result, input1, input1.sd)[i],places = 1) print('{} tested!'.format(ufunc)) - - #~ q4 = np.exp(q3) - #~ q5 = np.sin(q3) - #~ q6 = np.cos(q3) - #~ q7 = np.tan(q3) - #~ q8 = np.arcsin(q33) - #~ q9 = np.arccos(q33) - #~ q10 = np.arctan(q33) - #~ q11 = np.sinh(q33) - #~ q12 = np.cosh(q33) - #~ q13 = np.tanh(q33) - #~ q14 = np.logaddexp(q3,q33) - #~ q15 = np.power(q3,q33) - #~ for i in range(3): - #~ self.assertAlmostEqual(q4[i], np.exp(a1[i])) - #~ self.assertAlmostEqual(q4.sd[i], q4[i]*q3.sd[i]) - #~ self.assertAlmostEqual(q5[i], np.sin(a1[i])) - #~ self.assertAlmostEqual(q5.sd[i], np.cos(a1[i])*sd1[i]) - #~ self.assertAlmostEqual(q6[i], np.cos(a1[i])) - #~ self.assertAlmostEqual(q6.sd[i], np.sin(a1[i])*sd1[i]) - #~ self.assertAlmostEqual(q7[i], np.tan(a1[i])) - #~ #self.assertAlmostEqual(q7.sd[i], np.cos(a1[i])**(-2)*sd1[i]) - #~ self.assertAlmostEqual(q8[i], np.arcsin(a2[i])) - #~ #self.assertAlmostEqual(q8.sd[i], sd2[i]/np.sqrt(1-sd2[i]**2)) - #~ self.assertAlmostEqual(q9[i], np.arccos(a2[i])) - #~ #self.assertAlmostEqual(q9.sd[i], sd2[i]/np.sqrt(1-sd2[i]**2)) - #~ self.assertAlmostEqual(q10[i], np.arctan(a2[i])) - #~ #self.assertAlmostEqual(q10.sd[i], sd2[i]*np.cosh(a2[i])**(-2)) - #~ self.assertAlmostEqual(q11[i], np.sinh(a2[i])) - #~ self.assertAlmostEqual(q11.sd[i], sd2[i]*np.cosh(a2[i])) - #~ self.assertAlmostEqual(q12[i], np.cosh(a2[i])) - #~ self.assertAlmostEqual(q12.sd[i], sd2[i]*np.sinh(a2[i])) - #~ self.assertAlmostEqual(q13[i], np.tanh(a2[i])) - #~ self.assertAlmostEqual(q13.sd[i], sd2[i]*np.cosh(a2[i])**(-2)) - #~ self.assertAlmostEqual(q14[i], np.logaddexp(a1[i], a2[i])) - #~ self.assertAlmostEqual(q15[i], np.power(np.asarray(q3[i]),np.asarray(q33[i]))) + + for ufunc in ufunc_dict_two_inputs: + unit_test = ufunc_dict_two_inputs[ufunc][1] + if unit_test is units_check_unitless: + with self.assertRaises(Exception) as e: + ufunc(q1,q3) + with self.assertRaises(Exception) as e: + ufunc(q2,q6) + with self.assertRaises(Exception) as e: + ufunc(q4,q3) + with self.assertRaises(Exception) as e: + ufunc(q5,q3) + in1 = [unit_test(q3)] + in2 = [unit_test(q6)] + r = [ufunc(i1,i2) for i1,i2 in zip(in1,in2)] + elif unit_test is units_check_any: + in1 = [unit_test(q1), unit_test(q2), unit_test(q3), unit_test(q4), unit_test(q5), unit_test(q6)] + in2 = [unit_test(q6), unit_test(q5), unit_test(q4), unit_test(q3), unit_test(q2), unit_test(q1)] + r = [ufunc(i1,i2) for i1,i2 in zip(in1,in2)] + sd_func = ufunc_dict_two_inputs[ufunc][0] + units_func = ufunc_dict_two_inputs[ufunc][2] + + for result, input1, input2 in zip(r, in1, in2): + self.assertEqual(result.units, units_func(input1.units, input2.units)) + result_got = result + result_wanted = ufunc(np.asarray(input1),np.asarray(input2)) + sd_got = result.sd + sd_wanted = sd_func(np.asarray(result), + np.asarray(input1), np.asarray(input2), + input1.sd, input2.sd) + for i in range(3): + self.assertAlmostEqual(result_got[i], result_wanted[i]) + self.assertAlmostEqual(sd_got[i], sd_wanted[i]) + + print('{} tested!'.format(ufunc)) if __name__ == '__main__': unittest.main() From 00f9cf6ca515250a1a25232922a2931b6a32d8cc Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 26 Jul 2017 15:16:48 +0100 Subject: [PATCH 100/106] add checking of all ufuncs with two inputs --- pyqn/ufunc_dictionaries.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyqn/ufunc_dictionaries.py b/pyqn/ufunc_dictionaries.py index 4993f50..bdb3d67 100644 --- a/pyqn/ufunc_dictionaries.py +++ b/pyqn/ufunc_dictionaries.py @@ -91,12 +91,13 @@ def units_unitless2(u1,u2): #np.arcsinh: (sd_arcsinh, units_check_unitless, units_unitless), #np.arccosh: (sd_arccosh, units_check_unitless, units_unitless), #np.arctanh: (sd_arctanh, units_check_unitless, units_unitless), - #np.negative: (sd_nochange, units_check_any, units_self) + np.negative: (sd_nochange, units_check_any, units_self) } ufunc_dict_two_inputs = {np.logaddexp: (sd_logaddexp, units_check_unitless, units_unitless2), np.logaddexp2: (sd_logaddexp2, units_check_unitless, units_unitless2), np.power: (sd_power, units_check_unitless, units_unitless2), np.true_divide: (sd_mul_div, units_check_any, units_div), - np.floor_divide: (sd_mul_div, units_check_any, units_div)} + np.floor_divide: (sd_mul_div, units_check_any, units_div) + } From 869dffcb7cbf9e89c06b39bcd40c940951299bfd Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 26 Jul 2017 16:16:57 +0100 Subject: [PATCH 101/106] add all math operator ufuncs that make sense in the qnArrayTwo context --- pyqn/ufunc_dictionaries.py | 41 +++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/pyqn/ufunc_dictionaries.py b/pyqn/ufunc_dictionaries.py index bdb3d67..a1a3f5b 100644 --- a/pyqn/ufunc_dictionaries.py +++ b/pyqn/ufunc_dictionaries.py @@ -15,6 +15,8 @@ def sd_power(result, vals1, vals2, sd1, sd2): def sd_exp(result, vals, sd): return result * sd +def sd_exp2(result, vals, sd): + return result * sd * np.log(2) def sd_sin(result, vals, sd): return np.cos(vals) * sd def sd_cos(result, vals, sd): @@ -37,6 +39,22 @@ def sd_arccosh(result, vals, sd): return sd/(np.sqrt(vals-1)*np.sqrt(vals+1)) def sd_arctanh(result, vals, sd): return np.asarray(sd)/(1.0-np.asarray(vals)**2) +def sd_log(result, vals, sd): + return sd/vals +def sd_log2(result, vals, sd): + return sd/(vals*np.log(2)) +def sd_log10(result, vals, sd): + return sd/(vals*np.log(10)) +def sd_log1p(result, vals, sd): + return sd/(1+vals) +def sd_sqrt(result, vals, sd): + return sd/(2*result) +def sd_square(result, vals, sd): + return sd*2*vals +def sd_cbrt(result, vals, sd): + return np.asarray(sd)/(3*np.asarray(vals)**(2/3)) +def sd_reciprocal(result, vals, sd): + return sd/vals**2 def sd_nochange(result, vals, sd): return sd @@ -66,6 +84,14 @@ def units_mul(u1,u2): return u1*u2 def units_div(u1,u2): return u1/u2 +def units_sqrt(u): + return u**(0.5) +def units_square(u): + return u**2 +def units_cbrt(u): + return u**(1/3) +def units_reciprocal(u): + return u**(-1) def units_unitless(u): return Units('1') def units_self(u): @@ -79,6 +105,12 @@ def units_unitless2(u1,u2): np.divide: ('__truediv__', sd_mul_div, units_div, '__rtruediv__')} ufunc_dict_one_input = {np.exp: (sd_exp, units_check_unitless, units_unitless), + np.exp2: (sd_exp2, units_check_unitless, units_unitless), + np.expm1: (sd_exp, units_check_unitless, units_unitless), + np.log: (sd_log, units_check_unitless, units_unitless), + np.log2: (sd_log2, units_check_unitless, units_unitless), + np.log10: (sd_log10, units_check_unitless, units_unitless), + np.log1p: (sd_log1p, units_check_unitless, units_unitless), np.sin: (sd_sin, units_check_unitless_deg_rad, units_unitless), np.cos: (sd_cos, units_check_unitless_deg_rad, units_unitless), np.tan: (sd_tan, units_check_unitless_deg_rad, units_unitless), @@ -91,7 +123,14 @@ def units_unitless2(u1,u2): #np.arcsinh: (sd_arcsinh, units_check_unitless, units_unitless), #np.arccosh: (sd_arccosh, units_check_unitless, units_unitless), #np.arctanh: (sd_arctanh, units_check_unitless, units_unitless), - np.negative: (sd_nochange, units_check_any, units_self) + np.negative: (sd_nochange, units_check_any, units_self), + np.positive: (sd_nochange, units_check_any, units_self), + np.absolute: (sd_nochange, units_check_any, units_self), + np.fabs: (sd_nochange, units_check_any, units_self), + np.sqrt: (sd_sqrt, units_check_any, units_sqrt), + np.square: (sd_square, units_check_any, units_square), + np.cbrt: (sd_cbrt, units_check_any, units_cbrt), + np.reciprocal: (sd_reciprocal, units_check_any, units_reciprocal), } ufunc_dict_two_inputs = {np.logaddexp: (sd_logaddexp, units_check_unitless, units_unitless2), From d440ae6e12966884114d1ef5223722b22d9c53af Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 1 Aug 2017 13:22:52 +0100 Subject: [PATCH 102/106] remove original qnArray and replace with qnArrayTwo as primary array class, add function to generate QnArrays from csv files --- pyqn/qn_array.py | 191 ++++++++++++++---- pyqn/qn_array_two.py | 142 ------------- pyqn/tests/test_qn_array.py | 341 ++++++++++++++++++++++++++------ pyqn/tests/test_qn_array_two.py | 292 --------------------------- pyqn/ufunc_dictionaries.py | 4 +- 5 files changed, 432 insertions(+), 538 deletions(-) delete mode 100644 pyqn/qn_array_two.py delete mode 100644 pyqn/tests/test_qn_array_two.py diff --git a/pyqn/qn_array.py b/pyqn/qn_array.py index 823fbab..d36da07 100644 --- a/pyqn/qn_array.py +++ b/pyqn/qn_array.py @@ -1,52 +1,165 @@ -from .symbol import Symbol import numpy as np -from .quantity import Quantity from .units import Units +from .quantity import Quantity +from .ufunc_dictionaries import * +import matplotlib.pyplot as plt +import csv -class qnArrayError(Exception): +class QnArrayError(Exception): def __init__(self, error_str): self.error_str = error_str def __str__(self): return self.error_str -class qnArray(Symbol): - def __init__(self, name=None, latex=None, html=None, values=None, - units=None, sd=None, definition=None): - Symbol.__init__(self, name, latex, html, definition) - - #validates units +class QnArray(np.ndarray): + def __new__(cls, input_array, info=None, units='1', sd=None): + """ Initialises a qnArray as a child class derived from the + numpy ndarray. + """ + obj = np.asarray(input_array).view(cls) + obj.info = info + if sd is None: + obj.sd = np.zeros(len(input_array)) + else: + obj.sd = np.array(sd) + if type(units) is str: - self.units = Units(units) + obj.units = Units(units) #records units as Unit class elif type(units) is Units: - self.units = units - else: - raise qnArrayError("Units accepted only in str or Units class form") - - #validates values array - if len(values) is not 0: - if type(values) is list or type(values) is np.ndarray: - if type(values[0]) is not str: - self.values = values - else: - raise qnArrayError("Values must be numbers") + obj.units = units + return obj + + def __array_finalize__(self, obj): + if obj is None: return + self.info = getattr(obj, 'info', None) + self.sd = getattr(obj, 'sd', None) + + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): + if ufunc in ufunc_dict_alg: + alg_func = ufunc_dict_alg[ufunc][0] + sd_func = ufunc_dict_alg[ufunc][1] + units_func = ufunc_dict_alg[ufunc][2] + alg_func_reverse = ufunc_dict_alg[ufunc][3] + + if all([hasattr(x, 'units') for x in inputs]): + result_units = units_func(inputs[0].units, inputs[1].units) + + # if both are qn arrays + if (type(inputs[1]) is QnArray) and (type(inputs[0]) is QnArray): + result_val = getattr(np.asarray(inputs[0]), alg_func)(np.asarray(inputs[1])) + result_sd = sd_func(result_val, np.asarray(inputs[0]), + np.asarray(inputs[1]), + inputs[0].sd, + inputs[1].sd) + + # if one input is a quantity + elif type(inputs[1]) is Quantity: + result_val = getattr(np.asarray(inputs[0]), alg_func)(inputs[1].value) + result_sd = sd_func(result_val, np.asarray(inputs[0]), + inputs[1].value, + inputs[0].sd, + inputs[1].sd) + + elif type(inputs[0]) is Quantity: + result_val = getattr(np.asarray(inputs[1]), alg_func_reverse)(inputs[0].value) + result_sd = sd_func(result_val, inputs[0].value, + np.asarray(inputs[1]), + inputs[0].sd, + inputs[1].sd) + + # for all other object types + elif type(inputs[0]) is QnArray: + result_val = getattr(np.asarray(inputs[0]), alg_func)(inputs[1]) + result_sd = sd_func(result_val, np.asarray(inputs[0]), + inputs[1], + inputs[0].sd, 0) + result_units = units_func(inputs[0].units, Units('1')) + else: - raise qnArrayError("Values only an array/list of values") - - if type(values) is list: - self.nparr = np.array(values) - elif type(values) is np.ndarray: - self.nparr = values + result_val = getattr(np.asarray(inputs[1]), alg_func_reverse)(inputs[0]) + result_sd = sd_func(result_val, inputs[0], + np.asarray(inputs[1]), + 0, inputs[1].sd) + result_units = units_func(Units('1'), inputs[1].units) + + return QnArray(result_val, units = result_units, sd = result_sd) + + elif ufunc in ufunc_dict_one_input: + #checks if units of input are valid + unit_test_func = ufunc_dict_one_input[ufunc][1] + inputs_checked = unit_test_func(inputs[0]) + + #extracts functions for finding sd and units + sd_func = ufunc_dict_one_input[ufunc][0] + units_func = ufunc_dict_one_input[ufunc][2] - def __mul__(self, other): - if type(other) is not Quantity: - raise qnArrayError("qnArrays can only be multiplied by Quantity objects") - return qnArray(values = self.nparr*other.value, units = self.units*other.units) - - def __truediv__(self, other): - if type(other) is not Quantity: - raise qnArrayError("qnArrays can only be divided by Quantity objects") - return qnArray(values = self.nparr/other.value, units = self.units/other.units) - + #calculates results + result_val = ufunc(np.asarray(inputs_checked)) + result_sd = sd_func(result_val, np.asarray(inputs_checked), np.asarray(inputs_checked.sd)) + result_units = units_func(inputs[0].units) + return QnArray(result_val, units = result_units, sd = result_sd) + + elif ufunc in ufunc_dict_two_inputs: + unit_test_func = ufunc_dict_two_inputs[ufunc][1] + input1 = unit_test_func(inputs[0]) + input2 = unit_test_func(inputs[1]) + sd_func = ufunc_dict_two_inputs[ufunc][0] + units_func = ufunc_dict_two_inputs[ufunc][2] + result_val = ufunc(np.asarray(input1),np.asarray(input2)) + result_sd = sd_func(result_val, np.asarray(input1), np.asarray(input2), input1.sd, input2.sd) + result_units = units_func(input1.units, input2.units) + return QnArray(result_val, units = result_units, sd = result_sd) + + def __eq__(self, other): + if all(super(QnArray, self).__eq__(super(QnArray, other))) and (self.units == other.units): + return True + else: + return False + + #def __neq__(self, other): + # return all(not self.__eq__(other)) + @property - def units_str(self): - return str(self.units) + def html_str(self): + html_chunks = [] + for i in range(len(self)): + html_chunks.append('{} {}'.format(self[i],self.units)) + return ', '.join(html_chunks) + + def convert_units_to(self, new_units, force=None): + to_units = Units(new_units) + fac = self.units.conversion(to_units, force) + new_vals = np.asarray(self)*fac + new_sd = self.sd*fac + return QnArray(new_vals, units = new_units, sd = new_sd) + + def append(self, input_quantity): + if self.units != input_quantity.units: + raise QnArrayError('Same units expected') + return QnArray(np.append(np.asarray(self),input_quantity.value), units = self.units, sd = np.append(self.sd,input_quantity.sd)) + +def plot_qn_arrays(qn_arr_1, qn_arr_2): + plt.errorbar(np.asarray(qn_arr_1),np.asarray(qn_arr_2),xerr = qn_arr_1.sd, yerr = qn_arr_2.sd) + plt.show() + +def load_data(filename, file_type, errors=False): + vals1 = [] + vals2 = [] + sd1 = [] + sd2 = [] + if file_type is 'csv': + with open(filename,'rb') as f: + reader = csv.reader(f) + if errors is False: + for row in reader: + vals1.append(row[0]) + vals2.append(row[1]) + sd1.append(0) + sd2.append(0) + else: + for row in reader: + vals1.append(row[0]) + sd1.append(row[1]) + vals2.append(row[2]) + sd2.append(row[3]) + return QnArray(vals1, units = '1', sd = sd1), QnArray(vals2, units = '1', sd = sd2) diff --git a/pyqn/qn_array_two.py b/pyqn/qn_array_two.py deleted file mode 100644 index ce81a4d..0000000 --- a/pyqn/qn_array_two.py +++ /dev/null @@ -1,142 +0,0 @@ -import numpy as np -from .units import Units -from .quantity import Quantity -from .ufunc_dictionaries import * -import matplotlib.pyplot as plt - -class qnArrayTwoError(Exception): - def __init__(self, error_str): - self.error_str = error_str - def __str__(self): - return self.error_str - -class qnArrayTwo(np.ndarray): - def __new__(cls, input_array, info=None, units='1', sd=None): - """ Initialises a qnArray as a child class derived from the - numpy ndarray. - """ - obj = np.asarray(input_array).view(cls) - obj.info = info - if sd is None: - obj.sd = np.zeros(len(input_array)) - else: - obj.sd = np.array(sd) - - if type(units) is str: - obj.units = Units(units) #records units as Unit class - elif type(units) is Units: - obj.units = units - return obj - - def __array_finalize__(self, obj): - if obj is None: return - self.info = getattr(obj, 'info', None) - self.sd = getattr(obj, 'sd', None) - - def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): - if ufunc in ufunc_dict_alg: - alg_func = ufunc_dict_alg[ufunc][0] - sd_func = ufunc_dict_alg[ufunc][1] - units_func = ufunc_dict_alg[ufunc][2] - alg_func_reverse = ufunc_dict_alg[ufunc][3] - - if all([hasattr(x, 'units') for x in inputs]): - result_units = units_func(inputs[0].units, inputs[1].units) - - # if both are qn arrays - if (type(inputs[1]) is qnArrayTwo) and (type(inputs[0]) is qnArrayTwo): - result_val = getattr(np.asarray(inputs[0]), alg_func)(np.asarray(inputs[1])) - result_sd = sd_func(result_val, np.asarray(inputs[0]), - np.asarray(inputs[1]), - inputs[0].sd, - inputs[1].sd) - - # if one input is a quantity - elif type(inputs[1]) is Quantity: - result_val = getattr(np.asarray(inputs[0]), alg_func)(inputs[1].value) - result_sd = sd_func(result_val, np.asarray(inputs[0]), - inputs[1].value, - inputs[0].sd, - inputs[1].sd) - - elif type(inputs[0]) is Quantity: - result_val = getattr(np.asarray(inputs[1]), alg_func_reverse)(inputs[0].value) - result_sd = sd_func(result_val, inputs[0].value, - np.asarray(inputs[1]), - inputs[0].sd, - inputs[1].sd) - - # for all other object types - elif type(inputs[0]) is qnArrayTwo: - result_val = getattr(np.asarray(inputs[0]), alg_func)(inputs[1]) - result_sd = sd_func(result_val, np.asarray(inputs[0]), - inputs[1], - inputs[0].sd, 0) - result_units = units_func(inputs[0].units, Units('1')) - - else: - result_val = getattr(np.asarray(inputs[1]), alg_func_reverse)(inputs[0]) - result_sd = sd_func(result_val, inputs[0], - np.asarray(inputs[1]), - 0, inputs[1].sd) - result_units = units_func(Units('1'), inputs[1].units) - - return qnArrayTwo(result_val, units = result_units, sd = result_sd) - - elif ufunc in ufunc_dict_one_input: - #checks if units of input are valid - unit_test_func = ufunc_dict_one_input[ufunc][1] - inputs_checked = unit_test_func(inputs[0]) - - #extracts functions for finding sd and units - sd_func = ufunc_dict_one_input[ufunc][0] - units_func = ufunc_dict_one_input[ufunc][2] - - #calculates results - result_val = ufunc(np.asarray(inputs_checked)) - result_sd = sd_func(result_val, np.asarray(inputs_checked), np.asarray(inputs_checked.sd)) - result_units = units_func(inputs[0].units) - return qnArrayTwo(result_val, units = result_units, sd = result_sd) - - elif ufunc in ufunc_dict_two_inputs: - unit_test_func = ufunc_dict_two_inputs[ufunc][1] - input1 = unit_test_func(inputs[0]) - input2 = unit_test_func(inputs[1]) - sd_func = ufunc_dict_two_inputs[ufunc][0] - units_func = ufunc_dict_two_inputs[ufunc][2] - result_val = ufunc(np.asarray(input1),np.asarray(input2)) - result_sd = sd_func(result_val, np.asarray(input1), np.asarray(input2), input1.sd, input2.sd) - result_units = units_func(input1.units, input2.units) - return qnArrayTwo(result_val, units = result_units, sd = result_sd) - - def __eq__(self, other): - if all(super(qnArrayTwo, self).__eq__(super(qnArrayTwo, other))) and (self.units == other.units): - return True - else: - return False - - #def __neq__(self, other): - # return all(not self.__eq__(other)) - - @property - def html_str(self): - html_chunks = [] - for i in range(len(self)): - html_chunks.append('{} {}'.format(self[i],self.units)) - return ', '.join(html_chunks) - - def convert_units_to(self, new_units, force=None): - to_units = Units(new_units) - fac = self.units.conversion(to_units, force) - new_vals = np.asarray(self)*fac - new_sd = self.sd*fac - return qnArrayTwo(new_vals, units = new_units, sd = new_sd) - - def append(self, input_quantity): - if self.units != input_quantity.units: - raise qnArrayTwoError('Same units expected') - return qnArrayTwo(np.append(np.asarray(self),input_quantity.value), units = self.units, sd = np.append(self.sd,input_quantity.sd)) - -def plot_qn_arrays(qn_arr_1, qn_arr_2): - plt.errorbar(np.asarray(qn_arr_1),np.asarray(qn_arr_2),xerr = qn_arr_1.sd, yerr = qn_arr_2.sd) - plt.show() diff --git a/pyqn/tests/test_qn_array.py b/pyqn/tests/test_qn_array.py index e140502..1262c65 100644 --- a/pyqn/tests/test_qn_array.py +++ b/pyqn/tests/test_qn_array.py @@ -1,79 +1,292 @@ import unittest -from ..qn_array import qnArray, qnArrayError +from ..qn_array import QnArray, QnArrayError +from ..units import Units from ..quantity import Quantity +from ..ufunc_dictionaries import * import numpy as np -class qnArrayTest(unittest.TestCase): - def test_qnarray_init(self): - a1 = [-1,-2,-3,-4,-5] - qnarr1 = qnArray(values = a1, units = 'm') - for i in range(len(a1)): - self.assertEqual(qnarr1.values[i], a1[i]) - self.assertEqual(qnarr1.nparr[i], a1[i]) - self.assertEqual(qnarr1.units_str, 'm') +class QnArrayTest(unittest.TestCase): + def test_qn_array_init(self): + vals1 = [1,2,3,4] + sd1 = [0.1,0.2,0.3,0.4] + qnarr1 = QnArray(vals1,units='m',sd=sd1) + self.assertEqual(qnarr1.units, Units('m')) + for i in range(len(vals1)): + self.assertEqual(qnarr1[i], vals1[i]) + self.assertEqual(qnarr1.sd[i], sd1[i]) + + vals2 = [-10,-20,-30,0,5] + qnarr2 = QnArray(vals2, units = 'J') + self.assertEqual(qnarr2.units, Units('J')) + for i in range(len(vals2)): + self.assertEqual(qnarr2[i], vals2[i]) + self.assertEqual(qnarr2.sd[i], 0) + + def test_qn_array_add(self): + vals1 = [1,2,3,4] + sd1 = [0.1,0.2,0.3,0.4] + qnarr1 = QnArray(vals1,units='m',sd=sd1) - a2 = [5,10] - qnarr2 = qnArray(values = np.array(a2), units = 'J') - for i in range(len(a2)): - self.assertEqual(qnarr2.values[i], a2[i]) - self.assertEqual(qnarr2.nparr[i], a2[i]) - self.assertEqual(qnarr2.units_str, 'J') + vals2 = [2,3,4,1] + sd2 = [0.2,0.3,0.4,0.1] + qnarr2 = QnArray(vals2, units='m',sd=sd2) - with self.assertRaises(qnArrayError) as e1: - qnarr = qnArray(values = "string") - qnarr = qnArray(values = ["a", "b", "c"]) + qnarr3 = qnarr1 + qnarr2 + self.assertEqual(qnarr3.units, qnarr1.units) + for i in range(len(vals2)): + self.assertEqual(qnarr3[i], vals1[i]+vals2[i]) + self.assertAlmostEqual(qnarr3.sd[i], (sd1[i]**2+sd2[i]**2)**0.5) - def test_qnarray_mult(self): - a1 = [-1,-2,-3,-4,-5] - qnarr1 = qnArray(values = a1, units = 'm') - q1 = Quantity(value = 2, units = 's') - result1 = qnarr1*q1 - self.assertEqual(result1.units_str, 'm.s') - for i in range(len(a1)): - self.assertEqual(result1.nparr[i], 2*a1[i]) + vals3 = [1,1,1] + qnarr3 = QnArray(vals3, units='m') + with self.assertRaises(ValueError) as e: + qnarr = qnarr1 + qnarr3 + + q1 = Quantity(value = 10, units = 'm') + qnarr4 = qnarr1 + q1 + qnarr5 = q1 + qnarr1 + qnarr6 = qnarr2 + 15 + qnarr7 = 15 + qnarr2 + self.assertEqual(qnarr4.units, Units('m')) + self.assertEqual(qnarr5.units, Units('m')) + self.assertEqual(qnarr6.units, Units('m')) + self.assertEqual(qnarr7.units, Units('m')) + for i in range(len(qnarr4)): + self.assertEqual(qnarr4[i], qnarr1[i]+10) + self.assertEqual(qnarr5[i], 10+qnarr1[i]) + self.assertEqual(qnarr6[i], qnarr2[i]+15) + self.assertEqual(qnarr7[i], 15+qnarr2[i]) - a2 = [5,10] - qnarr2 = qnArray(values = np.array(a2), units = 'J') - q2 = Quantity(value=0.2, units = 'm-1') - result2 = qnarr2*q2 - self.assertEqual(result2.units_str, 'J.m-1') - for i in range(len(a2)): - self.assertEqual(result2.nparr[i], 0.2*a2[i]) + def test_qn_array_sub(self): + vals1 = [1,2,3,4] + qnarr1 = QnArray(vals1,units='m') + + vals2 = [2,3,4,1] + qnarr2 = QnArray(vals2, units='m') + + qnarr3 = qnarr1 - qnarr2 + for i in range(len(vals2)): + self.assertEqual(qnarr3[i], vals1[i]-vals2[i]) - with self.assertRaises(qnArrayError) as e1: - result = qnarr1*2 - with self.assertRaises(qnArrayError) as e2: - result = qnarr1*"str" - with self.assertRaises(qnArrayError) as e3: - result = qnarr1*np.array([1,2,3]) - with self.assertRaises(qnArrayError) as e4: - result = qnarr1*qnarr2 + vals3 = [1,1,1] + qnarr3 = QnArray(vals3, units='m') + with self.assertRaises(ValueError) as e: + qnarr = qnarr1 - qnarr3 + + q1 = Quantity(value = 10, units = 'm') + qnarr4 = qnarr1 - q1 + qnarr5 = q1 - qnarr1 + qnarr6 = qnarr2 - 15 + qnarr7 = 15 - qnarr2 + self.assertEqual(qnarr4.units, Units('m')) + self.assertEqual(qnarr5.units, Units('m')) + self.assertEqual(qnarr6.units, Units('m')) + self.assertEqual(qnarr7.units, Units('m')) + for i in range(len(qnarr4)): + self.assertEqual(qnarr4[i], qnarr1[i]-10) + self.assertEqual(qnarr5[i], 10-qnarr1[i]) + self.assertEqual(qnarr6[i], qnarr2[i]-15) + self.assertEqual(qnarr7[i], 15-qnarr2[i]) + + def test_qn_array_mul(self): + vals1 = [1,2,3,4] + qnarr1 = QnArray(vals1,units='m') + + vals2 = [2,3,4,1] + qnarr2 = QnArray(vals2, units='s') + + qnarr3 = qnarr1 * qnarr2 + self.assertEqual(qnarr3.units, Units('m.s')) + for i in range(len(vals2)): + self.assertEqual(qnarr3[i], vals1[i]*vals2[i]) - def test_qnarray_div(self): - a1 = [-1,-2,-3,-4,-5] - qnarr1 = qnArray(values = a1, units = 'm') - q1 = Quantity(value = 2, units = 's') - result1 = qnarr1/q1 - self.assertEqual(result1.units_str, 'm.s-1') - for i in range(len(a1)): - self.assertEqual(result1.nparr[i], a1[i]/2) + vals3 = [1,1,1] + qnarr3 = QnArray(vals3, units='m') + with self.assertRaises(ValueError) as e: + qnarr = qnarr1 * qnarr3 + + q1 = Quantity(value = 10, units = 'J') + qnarr4 = qnarr1 * q1 + qnarr5 = q1 * qnarr1 + qnarr6 = qnarr2 * 15 + qnarr7 = 15 * qnarr2 + self.assertEqual(qnarr4.units, Units('m.J')) + self.assertEqual(qnarr5.units, Units('m.J')) + self.assertEqual(qnarr6.units, Units('s')) + self.assertEqual(qnarr7.units, Units('s')) + for i in range(len(qnarr4)): + self.assertEqual(qnarr4[i], qnarr1[i]*10) + self.assertEqual(qnarr5[i], 10*qnarr1[i]) + self.assertEqual(qnarr6[i], qnarr2[i]*15) + self.assertEqual(qnarr7[i], 15*qnarr2[i]) + + def test_qn_array_mul(self): + vals1 = [1,2,3,4] + qnarr1 = QnArray(vals1,units='m') + + vals2 = [2,3,4,1] + qnarr2 = QnArray(vals2, units='s') + + qnarr3 = qnarr1 / qnarr2 + self.assertEqual(qnarr3.units, Units('m.s-1')) + for i in range(len(vals2)): + self.assertEqual(qnarr3[i], vals1[i]/vals2[i]) - a2 = [5,10] - qnarr2 = qnArray(values = np.array(a2), units = 'J') - q2 = Quantity(value=0.2, units = 'm-1') - result2 = qnarr2/q2 - self.assertEqual(result2.units_str, 'J.m') - for i in range(len(a2)): - self.assertEqual(result2.nparr[i], a2[i]/0.2) + vals3 = [1,1,1] + qnarr3 = QnArray(vals3, units='m') + with self.assertRaises(ValueError) as e: + qnarr = qnarr1 / qnarr3 + + q1 = Quantity(value = 10, units = 'J') + qnarr4 = qnarr1 / q1 + qnarr5 = q1 / qnarr1 + qnarr6 = qnarr2 / 15 + qnarr7 = 15 / qnarr2 + self.assertEqual(qnarr4.units, Units('m.J-1')) + self.assertEqual(qnarr5.units, Units('m-1.J')) + self.assertEqual(qnarr6.units, Units('s')) + self.assertEqual(qnarr7.units, Units('s-1')) + for i in range(len(qnarr4)): + self.assertEqual(qnarr4[i], qnarr1[i]/10) + self.assertEqual(qnarr5[i], 10/qnarr1[i]) + self.assertEqual(qnarr6[i], qnarr2[i]/15) + self.assertEqual(qnarr7[i], 15/qnarr2[i]) - with self.assertRaises(qnArrayError) as e1: - result = qnarr1/2 - with self.assertRaises(qnArrayError) as e2: - result = qnarr1/"str" - with self.assertRaises(qnArrayError) as e3: - result = qnarr1/np.array([1,2,3]) - with self.assertRaises(qnArrayError) as e4: - result = qnarr1/qnarr2 + def test_qn_array_conversion(self): + a1 = [1,2,3] + sd1 = [0.1,0.2,0.3] + q1 = QnArray(a1, units = 'm', sd = sd1) + q2 = q1.convert_units_to('inch') + r_wanted = [a*39.37007874 for a in a1] + sd_wanted = [s*39.37007874 for s in sd1] + + self.assertEqual(q2.units, Units('inch')) + for i in range(3): + self.assertAlmostEqual(q2[i], r_wanted[i]) + self.assertAlmostEqual(q2.sd[i], sd_wanted[i]) + def test_qn_array_append(self): + a1 = [1,2,3] + sd1 = [0.1,0.2,0.3] + q1 = QnArray(a1, units = 'm', sd = sd1) + quant1 = Quantity(value=10,units='m') + quant2 = Quantity(value=5,units='m',sd=0.5) + quant3 = Quantity(value=2,units='J',sd=0.1) + + result1 = q1.append(quant1) + result2 = q1.append(quant2) + with self.assertRaises(QnArrayError) as e: + result3 = q1.append(quant3) + self.assertEqual(len(result1),4) + self.assertEqual(result1[-1],10) + self.assertEqual(len(result2),4) + self.assertEqual(result2[-1],5) + + def test_qn_array_ufunc(self): + a1 = [1,2,3] + sd1 = [0.1,0.2,0.3] + a2 = [0.1,0.2,0.3] + sd2 = [0.01,0.02,0.03] + q1 = QnArray(a1,units = 'm', sd = sd1) + q2 = QnArray(a2,units = 'm', sd = sd2) + q3 = QnArray(a2,units = 's', sd = sd2) + + for ufunc in ufunc_dict_alg: + if (ufunc is np.multiply) or (ufunc is np.divide): + in1 = q1 + in2 = q3 + elif (ufunc is np.add) or (ufunc is np.subtract): + in1 = q1 + in2 = q2 + result = ufunc(in1, in2) + + sd_func = ufunc_dict_alg[ufunc][1] + units_func = ufunc_dict_alg[ufunc][2] + + self.assertTrue(result.units, units_func(in1.units, in2.units)) + for i in range(3): + self.assertEqual(result[i], ufunc(np.asarray(in1), np.asarray(in2))[i]) + self.assertEqual(result.sd[i], sd_func(np.asarray(result), np.asarray(in1), np.asarray(in2), in1.sd, in2.sd)[i]) + + print('{} tested!'.format(ufunc)) + + a1 = [0.1,0.2,0.3] + sd1 = [0.01,0.02,0.03] + a2 = [0.4,0.5,0.6] + sd2 = [0.04,0.05,0.06] + q3 = QnArray(a1, units = '1', sd = sd1) + q4 = QnArray(a1, units = 'rad', sd = sd1) + q5 = QnArray(a1, units = 'deg', sd = sd1) + q6 = QnArray(a2, units = '1', sd = sd2) + + for ufunc in ufunc_dict_one_input: + unit_test = ufunc_dict_one_input[ufunc][1] + if unit_test is units_check_unitless: + with self.assertRaises(Exception) as e: + ufunc(q1) + with self.assertRaises(Exception) as e: + ufunc(q2) + with self.assertRaises(Exception) as e: + ufunc(q4) + with self.assertRaises(Exception) as e: + ufunc(q5) + in1 = [unit_test(q3)] + r = [ufunc(in1[0])] + elif unit_test is units_check_unitless_deg_rad: + with self.assertRaises(Exception) as e: + ufunc(q1) + with self.assertRaises(Exception) as e: + ufunc(q2) + in1 = [unit_test(q3), unit_test(q4), unit_test(q5)] + r = [ufunc(in1[0]), ufunc(in1[1]), ufunc(in1[2])] + elif unit_test is units_check_any: + in1 = [unit_test(q1), unit_test(q2), unit_test(q3), unit_test(q4), unit_test(q5)] + r = [ufunc(i) for i in in1] + sd_func = ufunc_dict_one_input[ufunc][0] #(result, vals, sd) + units_func = ufunc_dict_one_input[ufunc][2] #(units) + + for result, input1 in zip(r,in1): + self.assertEqual(result.units, units_func(input1.units)) + for i in range(3): + self.assertAlmostEqual(result[i], ufunc(np.asarray(input1))[i], places = 2) + self.assertAlmostEqual(result.sd[i], sd_func(result, input1, input1.sd)[i],places = 1) + + print('{} tested!'.format(ufunc)) + + for ufunc in ufunc_dict_two_inputs: + unit_test = ufunc_dict_two_inputs[ufunc][1] + if unit_test is units_check_unitless: + with self.assertRaises(Exception) as e: + ufunc(q1,q3) + with self.assertRaises(Exception) as e: + ufunc(q2,q6) + with self.assertRaises(Exception) as e: + ufunc(q4,q3) + with self.assertRaises(Exception) as e: + ufunc(q5,q3) + in1 = [unit_test(q3)] + in2 = [unit_test(q6)] + r = [ufunc(i1,i2) for i1,i2 in zip(in1,in2)] + elif unit_test is units_check_any: + in1 = [unit_test(q1), unit_test(q2), unit_test(q3), unit_test(q4), unit_test(q5), unit_test(q6)] + in2 = [unit_test(q6), unit_test(q5), unit_test(q4), unit_test(q3), unit_test(q2), unit_test(q1)] + r = [ufunc(i1,i2) for i1,i2 in zip(in1,in2)] + sd_func = ufunc_dict_two_inputs[ufunc][0] + units_func = ufunc_dict_two_inputs[ufunc][2] + + for result, input1, input2 in zip(r, in1, in2): + self.assertEqual(result.units, units_func(input1.units, input2.units)) + result_got = result + result_wanted = ufunc(np.asarray(input1),np.asarray(input2)) + sd_got = result.sd + sd_wanted = sd_func(np.asarray(result), + np.asarray(input1), np.asarray(input2), + input1.sd, input2.sd) + for i in range(3): + self.assertAlmostEqual(result_got[i], result_wanted[i]) + self.assertAlmostEqual(sd_got[i], sd_wanted[i]) + + print('{} tested!'.format(ufunc)) + if __name__ == '__main__': unittest.main() diff --git a/pyqn/tests/test_qn_array_two.py b/pyqn/tests/test_qn_array_two.py deleted file mode 100644 index 7f92258..0000000 --- a/pyqn/tests/test_qn_array_two.py +++ /dev/null @@ -1,292 +0,0 @@ -import unittest -from ..qn_array_two import qnArrayTwo, qnArrayTwoError -from ..units import Units -from ..quantity import Quantity -from ..ufunc_dictionaries import * -import numpy as np - -class qnArrayTwoTest(unittest.TestCase): - def test_qn_array_two_init(self): - vals1 = [1,2,3,4] - sd1 = [0.1,0.2,0.3,0.4] - qnarr1 = qnArrayTwo(vals1,units='m',sd=sd1) - self.assertEqual(qnarr1.units, Units('m')) - for i in range(len(vals1)): - self.assertEqual(qnarr1[i], vals1[i]) - self.assertEqual(qnarr1.sd[i], sd1[i]) - - vals2 = [-10,-20,-30,0,5] - qnarr2 = qnArrayTwo(vals2, units = 'J') - self.assertEqual(qnarr2.units, Units('J')) - for i in range(len(vals2)): - self.assertEqual(qnarr2[i], vals2[i]) - self.assertEqual(qnarr2.sd[i], 0) - - def test_qn_array_two_add(self): - vals1 = [1,2,3,4] - sd1 = [0.1,0.2,0.3,0.4] - qnarr1 = qnArrayTwo(vals1,units='m',sd=sd1) - - vals2 = [2,3,4,1] - sd2 = [0.2,0.3,0.4,0.1] - qnarr2 = qnArrayTwo(vals2, units='m',sd=sd2) - - qnarr3 = qnarr1 + qnarr2 - self.assertEqual(qnarr3.units, qnarr1.units) - for i in range(len(vals2)): - self.assertEqual(qnarr3[i], vals1[i]+vals2[i]) - self.assertAlmostEqual(qnarr3.sd[i], (sd1[i]**2+sd2[i]**2)**0.5) - - vals3 = [1,1,1] - qnarr3 = qnArrayTwo(vals3, units='m') - with self.assertRaises(ValueError) as e: - qnarr = qnarr1 + qnarr3 - - q1 = Quantity(value = 10, units = 'm') - qnarr4 = qnarr1 + q1 - qnarr5 = q1 + qnarr1 - qnarr6 = qnarr2 + 15 - qnarr7 = 15 + qnarr2 - self.assertEqual(qnarr4.units, Units('m')) - self.assertEqual(qnarr5.units, Units('m')) - self.assertEqual(qnarr6.units, Units('m')) - self.assertEqual(qnarr7.units, Units('m')) - for i in range(len(qnarr4)): - self.assertEqual(qnarr4[i], qnarr1[i]+10) - self.assertEqual(qnarr5[i], 10+qnarr1[i]) - self.assertEqual(qnarr6[i], qnarr2[i]+15) - self.assertEqual(qnarr7[i], 15+qnarr2[i]) - - def test_qn_array_two_sub(self): - vals1 = [1,2,3,4] - qnarr1 = qnArrayTwo(vals1,units='m') - - vals2 = [2,3,4,1] - qnarr2 = qnArrayTwo(vals2, units='m') - - qnarr3 = qnarr1 - qnarr2 - for i in range(len(vals2)): - self.assertEqual(qnarr3[i], vals1[i]-vals2[i]) - - vals3 = [1,1,1] - qnarr3 = qnArrayTwo(vals3, units='m') - with self.assertRaises(ValueError) as e: - qnarr = qnarr1 - qnarr3 - - q1 = Quantity(value = 10, units = 'm') - qnarr4 = qnarr1 - q1 - qnarr5 = q1 - qnarr1 - qnarr6 = qnarr2 - 15 - qnarr7 = 15 - qnarr2 - self.assertEqual(qnarr4.units, Units('m')) - self.assertEqual(qnarr5.units, Units('m')) - self.assertEqual(qnarr6.units, Units('m')) - self.assertEqual(qnarr7.units, Units('m')) - for i in range(len(qnarr4)): - self.assertEqual(qnarr4[i], qnarr1[i]-10) - self.assertEqual(qnarr5[i], 10-qnarr1[i]) - self.assertEqual(qnarr6[i], qnarr2[i]-15) - self.assertEqual(qnarr7[i], 15-qnarr2[i]) - - def test_qn_array_two_mul(self): - vals1 = [1,2,3,4] - qnarr1 = qnArrayTwo(vals1,units='m') - - vals2 = [2,3,4,1] - qnarr2 = qnArrayTwo(vals2, units='s') - - qnarr3 = qnarr1 * qnarr2 - self.assertEqual(qnarr3.units, Units('m.s')) - for i in range(len(vals2)): - self.assertEqual(qnarr3[i], vals1[i]*vals2[i]) - - vals3 = [1,1,1] - qnarr3 = qnArrayTwo(vals3, units='m') - with self.assertRaises(ValueError) as e: - qnarr = qnarr1 * qnarr3 - - q1 = Quantity(value = 10, units = 'J') - qnarr4 = qnarr1 * q1 - qnarr5 = q1 * qnarr1 - qnarr6 = qnarr2 * 15 - qnarr7 = 15 * qnarr2 - self.assertEqual(qnarr4.units, Units('m.J')) - self.assertEqual(qnarr5.units, Units('m.J')) - self.assertEqual(qnarr6.units, Units('s')) - self.assertEqual(qnarr7.units, Units('s')) - for i in range(len(qnarr4)): - self.assertEqual(qnarr4[i], qnarr1[i]*10) - self.assertEqual(qnarr5[i], 10*qnarr1[i]) - self.assertEqual(qnarr6[i], qnarr2[i]*15) - self.assertEqual(qnarr7[i], 15*qnarr2[i]) - - def test_qn_array_two_mul(self): - vals1 = [1,2,3,4] - qnarr1 = qnArrayTwo(vals1,units='m') - - vals2 = [2,3,4,1] - qnarr2 = qnArrayTwo(vals2, units='s') - - qnarr3 = qnarr1 / qnarr2 - self.assertEqual(qnarr3.units, Units('m.s-1')) - for i in range(len(vals2)): - self.assertEqual(qnarr3[i], vals1[i]/vals2[i]) - - vals3 = [1,1,1] - qnarr3 = qnArrayTwo(vals3, units='m') - with self.assertRaises(ValueError) as e: - qnarr = qnarr1 / qnarr3 - - q1 = Quantity(value = 10, units = 'J') - qnarr4 = qnarr1 / q1 - qnarr5 = q1 / qnarr1 - qnarr6 = qnarr2 / 15 - qnarr7 = 15 / qnarr2 - self.assertEqual(qnarr4.units, Units('m.J-1')) - self.assertEqual(qnarr5.units, Units('m-1.J')) - self.assertEqual(qnarr6.units, Units('s')) - self.assertEqual(qnarr7.units, Units('s-1')) - for i in range(len(qnarr4)): - self.assertEqual(qnarr4[i], qnarr1[i]/10) - self.assertEqual(qnarr5[i], 10/qnarr1[i]) - self.assertEqual(qnarr6[i], qnarr2[i]/15) - self.assertEqual(qnarr7[i], 15/qnarr2[i]) - - def test_qn_array_two_conversion(self): - a1 = [1,2,3] - sd1 = [0.1,0.2,0.3] - q1 = qnArrayTwo(a1, units = 'm', sd = sd1) - q2 = q1.convert_units_to('inch') - r_wanted = [a*39.37007874 for a in a1] - sd_wanted = [s*39.37007874 for s in sd1] - - self.assertEqual(q2.units, Units('inch')) - for i in range(3): - self.assertAlmostEqual(q2[i], r_wanted[i]) - self.assertAlmostEqual(q2.sd[i], sd_wanted[i]) - - def test_qn_array_append(self): - a1 = [1,2,3] - sd1 = [0.1,0.2,0.3] - q1 = qnArrayTwo(a1, units = 'm', sd = sd1) - quant1 = Quantity(value=10,units='m') - quant2 = Quantity(value=5,units='m',sd=0.5) - quant3 = Quantity(value=2,units='J',sd=0.1) - - result1 = q1.append(quant1) - result2 = q1.append(quant2) - with self.assertRaises(qnArrayTwoError) as e: - result3 = q1.append(quant3) - self.assertEqual(len(result1),4) - self.assertEqual(result1[-1],10) - self.assertEqual(len(result2),4) - self.assertEqual(result2[-1],5) - - def test_qn_array_two_ufunc(self): - a1 = [1,2,3] - sd1 = [0.1,0.2,0.3] - a2 = [0.1,0.2,0.3] - sd2 = [0.01,0.02,0.03] - q1 = qnArrayTwo(a1,units = 'm', sd = sd1) - q2 = qnArrayTwo(a2,units = 'm', sd = sd2) - q3 = qnArrayTwo(a2,units = 's', sd = sd2) - - #~ for ufunc in ufunc_dict_alg: - #~ if (ufunc is np.multiply) or (ufunc is np.divide): - #~ in1 = q1 - #~ in2 = q3 - #~ elif (ufunc is np.add) or (ufunc is np.subtract): - #~ in1 = q1 - #~ in2 = q2 - #~ result = ufunc(in1, in2) - - #~ sd_func = ufunc_dict_alg[ufunc][1] - #~ units_func = ufunc_dict_alg[ufunc][2] - - #~ self.assertTrue(result.units, units_func(in1.units, in2.units)) - #~ for i in range(3): - #~ self.assertEqual(result[i], ufunc(np.asarray(in1), np.asarray(in2))[i]) - #~ self.assertEqual(result.sd[i], sd_func(np.asarray(result), np.asarray(in1), np.asarray(in2), in1.sd, in2.sd)[i]) - - #~ print('{} tested!'.format(ufunc)) - - a1 = [0.1,0.2,0.3] - sd1 = [0.01,0.02,0.03] - a2 = [0.4,0.5,0.6] - sd2 = [0.04,0.05,0.06] - q3 = qnArrayTwo(a1, units = '1', sd = sd1) - q4 = qnArrayTwo(a1, units = 'rad', sd = sd1) - q5 = qnArrayTwo(a1, units = 'deg', sd = sd1) - q6 = qnArrayTwo(a2, units = '1', sd = sd2) - - for ufunc in ufunc_dict_one_input: - unit_test = ufunc_dict_one_input[ufunc][1] - if unit_test is units_check_unitless: - with self.assertRaises(Exception) as e: - ufunc(q1) - with self.assertRaises(Exception) as e: - ufunc(q2) - with self.assertRaises(Exception) as e: - ufunc(q4) - with self.assertRaises(Exception) as e: - ufunc(q5) - in1 = [unit_test(q3)] - r = [ufunc(in1[0])] - elif unit_test is units_check_unitless_deg_rad: - with self.assertRaises(Exception) as e: - ufunc(q1) - with self.assertRaises(Exception) as e: - ufunc(q2) - in1 = [unit_test(q3), unit_test(q4), unit_test(q5)] - r = [ufunc(in1[0]), ufunc(in1[1]), ufunc(in1[2])] - elif unit_test is units_check_any: - in1 = [unit_test(q1), unit_test(q2), unit_test(q3), unit_test(q4), unit_test(q5)] - r = [ufunc(i) for i in in1] - sd_func = ufunc_dict_one_input[ufunc][0] #(result, vals, sd) - units_func = ufunc_dict_one_input[ufunc][2] #(units) - - for result, input1 in zip(r,in1): - self.assertEqual(result.units, units_func(input1.units)) - for i in range(3): - self.assertAlmostEqual(result[i], ufunc(np.asarray(input1))[i], places = 2) - self.assertAlmostEqual(result.sd[i], sd_func(result, input1, input1.sd)[i],places = 1) - - print('{} tested!'.format(ufunc)) - - for ufunc in ufunc_dict_two_inputs: - unit_test = ufunc_dict_two_inputs[ufunc][1] - if unit_test is units_check_unitless: - with self.assertRaises(Exception) as e: - ufunc(q1,q3) - with self.assertRaises(Exception) as e: - ufunc(q2,q6) - with self.assertRaises(Exception) as e: - ufunc(q4,q3) - with self.assertRaises(Exception) as e: - ufunc(q5,q3) - in1 = [unit_test(q3)] - in2 = [unit_test(q6)] - r = [ufunc(i1,i2) for i1,i2 in zip(in1,in2)] - elif unit_test is units_check_any: - in1 = [unit_test(q1), unit_test(q2), unit_test(q3), unit_test(q4), unit_test(q5), unit_test(q6)] - in2 = [unit_test(q6), unit_test(q5), unit_test(q4), unit_test(q3), unit_test(q2), unit_test(q1)] - r = [ufunc(i1,i2) for i1,i2 in zip(in1,in2)] - sd_func = ufunc_dict_two_inputs[ufunc][0] - units_func = ufunc_dict_two_inputs[ufunc][2] - - for result, input1, input2 in zip(r, in1, in2): - self.assertEqual(result.units, units_func(input1.units, input2.units)) - result_got = result - result_wanted = ufunc(np.asarray(input1),np.asarray(input2)) - sd_got = result.sd - sd_wanted = sd_func(np.asarray(result), - np.asarray(input1), np.asarray(input2), - input1.sd, input2.sd) - for i in range(3): - self.assertAlmostEqual(result_got[i], result_wanted[i]) - self.assertAlmostEqual(sd_got[i], sd_wanted[i]) - - print('{} tested!'.format(ufunc)) - -if __name__ == '__main__': - unittest.main() diff --git a/pyqn/ufunc_dictionaries.py b/pyqn/ufunc_dictionaries.py index a1a3f5b..d5a0513 100644 --- a/pyqn/ufunc_dictionaries.py +++ b/pyqn/ufunc_dictionaries.py @@ -17,6 +17,8 @@ def sd_exp(result, vals, sd): return result * sd def sd_exp2(result, vals, sd): return result * sd * np.log(2) +def sd_expm1(result, vals, sd): + return sd*np.exp(vals) def sd_sin(result, vals, sd): return np.cos(vals) * sd def sd_cos(result, vals, sd): @@ -106,7 +108,7 @@ def units_unitless2(u1,u2): ufunc_dict_one_input = {np.exp: (sd_exp, units_check_unitless, units_unitless), np.exp2: (sd_exp2, units_check_unitless, units_unitless), - np.expm1: (sd_exp, units_check_unitless, units_unitless), + np.expm1: (sd_expm1, units_check_unitless, units_unitless), np.log: (sd_log, units_check_unitless, units_unitless), np.log2: (sd_log2, units_check_unitless, units_unitless), np.log10: (sd_log10, units_check_unitless, units_unitless), From 17a2cdd7120528d813f745d92396b851be421374 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 1 Aug 2017 14:45:21 +0100 Subject: [PATCH 103/106] add more meaningful commenting of class methods --- pyqn/qn_array.py | 151 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 130 insertions(+), 21 deletions(-) diff --git a/pyqn/qn_array.py b/pyqn/qn_array.py index d36da07..5f1ef4a 100644 --- a/pyqn/qn_array.py +++ b/pyqn/qn_array.py @@ -1,3 +1,29 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# qn_array.py +# A class representing an array of physical quantities, with units and +# uncertainty. +# +# Copyright (C) 2012-2017 Christian Hill +# Department of Physics and Astronomy, University College London +# christian.hill@ucl.ac.uk +# +# This file is part of PyQn +# +# PyQn is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# PyQn is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with PyQn. If not, see + import numpy as np from .units import Units from .quantity import Quantity @@ -6,16 +32,37 @@ import csv class QnArrayError(Exception): + """ + An Exception class for errors that might occur whilst manipulating + QnArray objects. + + """ + def __init__(self, error_str): self.error_str = error_str def __str__(self): return self.error_str class QnArray(np.ndarray): + """ + A Python class representing an array of values, their units and + errors. This class extends the numpy ndarray class such that + QnArray objects can be used with numpy ufuncs and the errors are + propagated using the functions defined in the ufunc_dictionaries.py + file. + + """ + def __new__(cls, input_array, info=None, units='1', sd=None): - """ Initialises a qnArray as a child class derived from the - numpy ndarray. + """ + Initialises a qnArray as a child class derived from the numpy + ndarray. The units are set to default to be unitless, but can + be set to be a string (which will be converted to a Units + object) or set straight away to be a Units object, the standard + deviation is set to default to an array of zeros. + """ + obj = np.asarray(input_array).view(cls) obj.info = info if sd is None: @@ -30,11 +77,24 @@ def __new__(cls, input_array, info=None, units='1', sd=None): return obj def __array_finalize__(self, obj): + """ + Function which is called each time that a function is operated + on the QnArray object. + + """ + if obj is None: return self.info = getattr(obj, 'info', None) self.sd = getattr(obj, 'sd', None) def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): + """ + Function which is called when numpy ufuncs are called on the + QnArray object. It uses predefined equations to calculate the + new errors of the returned QnArray objects. + + """ + if ufunc in ufunc_dict_alg: alg_func = ufunc_dict_alg[ufunc][0] sd_func = ufunc_dict_alg[ufunc][1] @@ -42,11 +102,14 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): alg_func_reverse = ufunc_dict_alg[ufunc][3] if all([hasattr(x, 'units') for x in inputs]): - result_units = units_func(inputs[0].units, inputs[1].units) + result_units = units_func(inputs[0].units, + inputs[1].units) # if both are qn arrays - if (type(inputs[1]) is QnArray) and (type(inputs[0]) is QnArray): - result_val = getattr(np.asarray(inputs[0]), alg_func)(np.asarray(inputs[1])) + if (type(inputs[1]) is QnArray) and \ + (type(inputs[0]) is QnArray): + result_val = getattr(np.asarray(inputs[0]), + alg_func)(np.asarray(inputs[1])) result_sd = sd_func(result_val, np.asarray(inputs[0]), np.asarray(inputs[1]), inputs[0].sd, @@ -54,14 +117,16 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): # if one input is a quantity elif type(inputs[1]) is Quantity: - result_val = getattr(np.asarray(inputs[0]), alg_func)(inputs[1].value) + result_val = getattr(np.asarray(inputs[0]), + alg_func)(inputs[1].value) result_sd = sd_func(result_val, np.asarray(inputs[0]), inputs[1].value, inputs[0].sd, inputs[1].sd) elif type(inputs[0]) is Quantity: - result_val = getattr(np.asarray(inputs[1]), alg_func_reverse)(inputs[0].value) + result_val = getattr(np.asarray(inputs[1]), + alg_func_reverse)(inputs[0].value) result_sd = sd_func(result_val, inputs[0].value, np.asarray(inputs[1]), inputs[0].sd, @@ -69,20 +134,23 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): # for all other object types elif type(inputs[0]) is QnArray: - result_val = getattr(np.asarray(inputs[0]), alg_func)(inputs[1]) + result_val = getattr(np.asarray(inputs[0]), + alg_func)(inputs[1]) result_sd = sd_func(result_val, np.asarray(inputs[0]), inputs[1], inputs[0].sd, 0) result_units = units_func(inputs[0].units, Units('1')) else: - result_val = getattr(np.asarray(inputs[1]), alg_func_reverse)(inputs[0]) + result_val = getattr(np.asarray(inputs[1]), + alg_func_reverse)(inputs[0]) result_sd = sd_func(result_val, inputs[0], np.asarray(inputs[1]), 0, inputs[1].sd) result_units = units_func(Units('1'), inputs[1].units) - return QnArray(result_val, units = result_units, sd = result_sd) + return QnArray(result_val, units = result_units, + sd = result_sd) elif ufunc in ufunc_dict_one_input: #checks if units of input are valid @@ -95,9 +163,12 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): #calculates results result_val = ufunc(np.asarray(inputs_checked)) - result_sd = sd_func(result_val, np.asarray(inputs_checked), np.asarray(inputs_checked.sd)) + result_sd = sd_func(result_val, + np.asarray(inputs_checked), + np.asarray(inputs_checked.sd)) result_units = units_func(inputs[0].units) - return QnArray(result_val, units = result_units, sd = result_sd) + return QnArray(result_val, units = result_units, + sd = result_sd) elif ufunc in ufunc_dict_two_inputs: unit_test_func = ufunc_dict_two_inputs[ufunc][1] @@ -106,27 +177,45 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): sd_func = ufunc_dict_two_inputs[ufunc][0] units_func = ufunc_dict_two_inputs[ufunc][2] result_val = ufunc(np.asarray(input1),np.asarray(input2)) - result_sd = sd_func(result_val, np.asarray(input1), np.asarray(input2), input1.sd, input2.sd) + result_sd = sd_func(result_val, np.asarray(input1), + np.asarray(input2), + input1.sd, input2.sd) result_units = units_func(input1.units, input2.units) - return QnArray(result_val, units = result_units, sd = result_sd) + return QnArray(result_val, units = result_units, + sd = result_sd) def __eq__(self, other): - if all(super(QnArray, self).__eq__(super(QnArray, other))) and (self.units == other.units): + """ + Checks if two QnArray objects are the same, given that their + values and units are the same. + + """ + + if all(super(QnArray, self).__eq__(super(QnArray, other))) and \ + (self.units == other.units): return True else: return False - #def __neq__(self, other): - # return all(not self.__eq__(other)) - @property def html_str(self): + """ + Creates a representation of the array in the HTML format. + + """ + html_chunks = [] for i in range(len(self)): html_chunks.append('{} {}'.format(self[i],self.units)) return ', '.join(html_chunks) def convert_units_to(self, new_units, force=None): + """ + Converts the units of the array given a new unit. It uses the + conversion factor generator of the Units class. + + """ + to_units = Units(new_units) fac = self.units.conversion(to_units, force) new_vals = np.asarray(self)*fac @@ -134,15 +223,34 @@ def convert_units_to(self, new_units, force=None): return QnArray(new_vals, units = new_units, sd = new_sd) def append(self, input_quantity): + """ + Appends a Quantity object to the QnArray object. + + """ + if self.units != input_quantity.units: raise QnArrayError('Same units expected') - return QnArray(np.append(np.asarray(self),input_quantity.value), units = self.units, sd = np.append(self.sd,input_quantity.sd)) + return QnArray(np.append(np.asarray(self), + input_quantity.value), + units = self.units, + sd = np.append(self.sd,input_quantity.sd)) def plot_qn_arrays(qn_arr_1, qn_arr_2): - plt.errorbar(np.asarray(qn_arr_1),np.asarray(qn_arr_2),xerr = qn_arr_1.sd, yerr = qn_arr_2.sd) + """ + Plots two QnArray objects using matplotlib with their errors. + + """ + + plt.errorbar(np.asarray(qn_arr_1),np.asarray(qn_arr_2), + xerr = qn_arr_1.sd, yerr = qn_arr_2.sd) plt.show() def load_data(filename, file_type, errors=False): + """ + Function which generates two QnArray objects given a csv file. + + """ + vals1 = [] vals2 = [] sd1 = [] @@ -162,4 +270,5 @@ def load_data(filename, file_type, errors=False): sd1.append(row[1]) vals2.append(row[2]) sd2.append(row[3]) - return QnArray(vals1, units = '1', sd = sd1), QnArray(vals2, units = '1', sd = sd2) + return QnArray(vals1, units = '1', sd = sd1), \ + QnArray(vals2, units = '1', sd = sd2) From 44a8bf2b74184ec1c9717b3982af5be3f3aac055 Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Tue, 1 Aug 2017 15:32:16 +0100 Subject: [PATCH 104/106] add preamble to file --- pyqn/ufunc_dictionaries.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pyqn/ufunc_dictionaries.py b/pyqn/ufunc_dictionaries.py index d5a0513..2557508 100644 --- a/pyqn/ufunc_dictionaries.py +++ b/pyqn/ufunc_dictionaries.py @@ -1,3 +1,30 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# ufunc_dictionaries.py +# A set of predefined error propagation functions and functions which +# return the resultant units given numpy ufuncs operating on QnArray +# objects. +# +# Copyright (C) 2012-2017 Christian Hill +# Department of Physics and Astronomy, University College London +# christian.hill@ucl.ac.uk +# +# This file is part of PyQn +# +# PyQn is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# PyQn is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with PyQn. If not, see + from .units import Units, UnitsError import numpy as np From c8ba250cf606809c3bcb518c651f9256eecb8b6f Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Mon, 7 Aug 2017 13:11:06 +0100 Subject: [PATCH 105/106] add units checking for addition and subtraction of QnArray objects --- pyqn/ufunc_dictionaries.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyqn/ufunc_dictionaries.py b/pyqn/ufunc_dictionaries.py index 2557508..7dfb611 100644 --- a/pyqn/ufunc_dictionaries.py +++ b/pyqn/ufunc_dictionaries.py @@ -105,10 +105,11 @@ def units_check_any(input_arr): return input_arr def units_add_sub(u1, u2): - if u1.has_units() is True: + if u1 == u2: return u1 else: - return u2 + raise UnitsError('units must match') + def units_mul(u1,u2): return u1*u2 def units_div(u1,u2): From 8dc614693e57ce8aeeaabc0ac5c1e338897a5ced Mon Sep 17 00:00:00 2001 From: mayya-bondarevskaya Date: Wed, 23 Aug 2017 18:46:56 +0100 Subject: [PATCH 106/106] fix conversion to mol --- pyqn/units.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyqn/units.py b/pyqn/units.py index 6e8aada..32a00a3 100644 --- a/pyqn/units.py +++ b/pyqn/units.py @@ -280,7 +280,7 @@ def mol_conversion(self, other): fac = fac/(NA**(from_dims.dims[4]-to_dims.dims[4])) else: fac = fac*(NA**(to_dims.dims[4]-from_dims.dims[4])) - return fac/other.to_si() + return (fac/other.to_si())**(-1) def spec_conversion(self, other): d_wavenumber = d_length**-1