From 0b8592918858dfc3af8cb464d475b4dac3df66fc Mon Sep 17 00:00:00 2001 From: Christian Bender Date: Sun, 4 Mar 2018 21:25:38 +0100 Subject: [PATCH] Add files via upload --- linear-algebra-python/README.md | 70 ++++++ linear-algebra-python/src/lib.py | 332 +++++++++++++++++++++++++++++ linear-algebra-python/src/lib.pyc | Bin 0 -> 11098 bytes linear-algebra-python/src/tests.py | 133 ++++++++++++ 4 files changed, 535 insertions(+) create mode 100644 linear-algebra-python/README.md create mode 100644 linear-algebra-python/src/lib.py create mode 100644 linear-algebra-python/src/lib.pyc create mode 100644 linear-algebra-python/src/tests.py diff --git a/linear-algebra-python/README.md b/linear-algebra-python/README.md new file mode 100644 index 000000000..bca0af449 --- /dev/null +++ b/linear-algebra-python/README.md @@ -0,0 +1,70 @@ +# Linear algebra library for Python + +This module contains some useful classes and functions for dealing with linear algebra in python 2. + +--- + +## Overview + +- class Vector + - This class represents a vector of arbitray size and operations on it. + + **Overview about the methods:** + + - constructor(components : list) : init the vector + - set(components : list) : changes the vector components. + - __str__() : toString method + - component(i : int): gets the i-th component (start by 0) + - size() : gets the size of the vector (number of components) + - euclidLength() : returns the eulidean length of the vector. + - operator + : vector addition + - operator - : vector subtraction + - operator * : scalar multiplication and dot product + - copy() : copies this vector and returns it. + - changeComponent(pos,value) : changes the specified component. + +- function zeroVector(dimension) + - returns a zero vector of 'dimension' +- function unitBasisVector(dimension,pos) + - returns a unit basis vector with a One at index 'pos' (indexing at 0) +- function axpy(scalar,vector1,vector2) + - computes the axpy operation +- class Matrix + - This class represents a matrix of arbitrary size and operations on it. + + **Overview about the methods:** + + - __str__() : returns a string representation + - operator * : implements the matrix vector multiplication + implements the matrix-scalar multiplication. + - changeComponent(x,y,value) : changes the specified component. + - component(x,y) : returns the specified component. + - width() : returns the width of the matrix + - height() : returns the height of the matrix + - operator + : implements the matrix-addition. + - operator - _ implements the matrix-subtraction +- function squareZeroMatrix(N) + - returns a square zero-matrix of dimension NxN +--- + +## Documentation + +The module is well documented. You can use the python in-built ```help(...)``` function. +For instance: ```help(Vector)``` gives you all information about the Vector-class. +Or ```help(unitBasisVector)``` gives you all information you needed about the +global function ```unitBasisVector(...)```. If you need informations about a certain +method you type ```help(CLASSNAME.METHODNAME)```. + +--- + +## Usage + +You will find the module in the **src** directory its called ```lib.py```. You need to +import this module in your project. Alternative you can also use the file ```lib.pyc``` in python-bytecode. + +--- + +## Tests + +In the **src** directory you also find the test-suite, its called ```tests.py```. +The test-suite uses the built-in python-test-framework **unittest**. diff --git a/linear-algebra-python/src/lib.py b/linear-algebra-python/src/lib.py new file mode 100644 index 000000000..efded3a2a --- /dev/null +++ b/linear-algebra-python/src/lib.py @@ -0,0 +1,332 @@ +# -*- coding: utf-8 -*- +""" +Created on Mon Feb 26 14:29:11 2018 + +@author: Christian Bender +@license: MIT-license + +This module contains some useful classes and functions for dealing +with linear algebra in python. + +Overview: + +- class Vector +- function zeroVector(dimension) +- function unitBasisVector(dimension,pos) +- function axpy(scalar,vector1,vector2) +- class Matrix +- squareZeroMatrix(N) +""" + + +import math + + +class Vector(object): + """ + This class represents a vector of arbitray size. + You need to give the vector components. + + Overview about the methods: + + constructor(components : list) : init the vector + set(components : list) : changes the vector components. + __str__() : toString method + component(i : int): gets the i-th component (start by 0) + size() : gets the size of the vector (number of components) + euclidLength() : returns the eulidean length of the vector. + operator + : vector addition + operator - : vector subtraction + operator * : scalar multiplication and dot product + copy() : copies this vector and returns it. + changeComponent(pos,value) : changes the specified component. + TODO: compare-operator + """ + def __init__(self,components): + """ + input: components or nothing + simple constructor for init the vector + """ + self.__components = components + def set(self,components): + """ + input: new components + changes the components of the vector. + replace the components with newer one. + """ + if len(components) > 0: + self.__components = components + else: + raise Exception("please give any vector") + def __str__(self): + """ + returns a string representation of the vector + """ + ans = "(" + length = len(self.__components) + for i in range(length): + if i != length-1: + ans += str(self.__components[i]) + "," + else: + ans += str(self.__components[i]) + ")" + if len(ans) == 1: + ans += ")" + return ans + def component(self,i): + """ + input: index (start at 0) + output: the i-th component of the vector. + """ + if i < len(self.__components) and i >= 0: + return self.__components[i] + else: + raise Exception("index out of range") + def size(self): + """ + returns the size of the vector + """ + return len(self.__components) + def eulidLength(self): + """ + returns the eulidean length of the vector + """ + summe = 0 + for c in self.__components: + summe += c**2 + return math.sqrt(summe) + def __add__(self,other): + """ + input: other vector + assumes: other vector has the same size + returns a new vector that represents the sum. + """ + size = self.size() + result = [] + if size == other.size(): + for i in range(size): + result.append(self.__components[i] + other.component(i)) + else: + raise Exception("must have the same size") + return Vector(result) + def __sub__(self,other): + """ + input: other vector + assumes: other vector has the same size + returns a new vector that represents the differenz. + """ + size = self.size() + result = [] + if size == other.size(): + for i in range(size): + result.append(self.__components[i] - other.component(i)) + else: # error case + raise Exception("must have the same size") + return Vector(result) + def __mul__(self,other): + """ + mul implements the scalar multiplication + and the dot-product + """ + ans = [] + if isinstance(other,float) or isinstance(other,int): + for c in self.__components: + ans.append(c*other) + elif (isinstance(other,Vector) and (self.size() == other.size())): + size = self.size() + summe = 0 + for i in range(size): + summe += self.__components[i] * other.component(i) + return summe + else: # error case + raise Exception("invalide operand!") + return Vector(ans) + def copy(self): + """ + copies this vector and returns it. + """ + components = [x for x in self.__components] + return Vector(components) + def changeComponent(self,pos,value): + """ + input: an index (pos) and a value + changes the specified component (pos) with the + 'value' + """ + #precondition + assert (pos >= 0 and pos < len(self.__components)) + self.__components[pos] = value + +def zeroVector(dimension): + """ + returns a zero-vector of size 'dimension' + """ + #precondition + assert(isinstance(dimension,int)) + ans = [] + for i in range(dimension): + ans.append(0) + return Vector(ans) + + +def unitBasisVector(dimension,pos): + """ + returns a unit basis vector with a One + at index 'pos' (indexing at 0) + """ + #precondition + assert(isinstance(dimension,int) and (isinstance(pos,int))) + ans = [] + for i in range(dimension): + if i != pos: + ans.append(0) + else: + ans.append(1) + return Vector(ans) + + +def axpy(scalar,x,y): + """ + input: a 'scalar' and two vectors 'x' and 'y' + output: a vector + computes the axpy operation + """ + # precondition + assert(isinstance(x,Vector) and (isinstance(y,Vector)) \ + and (isinstance(scalar,int) or isinstance(scalar,float))) + return (x*scalar + y) + + +class Matrix(object): + """ + class: Matrix + This class represents a arbitrary matrix. + + Overview about the methods: + + __str__() : returns a string representation + operator * : implements the matrix vector multiplication + implements the matrix-scalar multiplication. + changeComponent(x,y,value) : changes the specified component. + component(x,y) : returns the specified component. + width() : returns the width of the matrix + height() : returns the height of the matrix + operator + : implements the matrix-addition. + operator - _ implements the matrix-subtraction + """ + def __init__(self,matrix,w,h): + """ + simple constructor for initialzes + the matrix with components. + """ + self.__matrix = matrix + self.__width = w + self.__height = h + def __str__(self): + """ + returns a string representation of this + matrix. + """ + ans = "" + for i in range(self.__height): + ans += "|" + for j in range(self.__width): + if j < self.__width -1: + ans += str(self.__matrix[i][j]) + "," + else: + ans += str(self.__matrix[i][j]) + "|\n" + return ans + def changeComponent(self,x,y, value): + """ + changes the x-y component of this matrix + """ + if x >= 0 and x < self.__height and y >= 0 and y < self.__width: + self.__matrix[x][y] = value + else: + raise Exception ("changeComponent: indices out of bounds") + def component(self,x,y): + """ + returns the specified (x,y) component + """ + if x >= 0 and x < self.__height and y >= 0 and y < self.__width: + return self.__matrix[x][y] + else: + raise Exception ("changeComponent: indices out of bounds") + def width(self): + """ + getter for the width + """ + return self.__width + def height(self): + """ + getter for the height + """ + return self.__height + def __mul__(self,other): + """ + implements the matrix-vector multiplication. + implements the matrix-scalar multiplication + """ + if isinstance(other, Vector): # vector-matrix + if (other.size() == self.__width): + ans = zeroVector(self.__height) + for i in range(self.__height): + summe = 0 + for j in range(self.__width): + summe += other.component(j) * self.__matrix[i][j] + ans.changeComponent(i,summe) + summe = 0 + return ans + else: + raise Exception("vector must have the same size as the " + + "number of columns of the matrix!") + elif isinstance(other,int) or isinstance(other,float): # matrix-scalar + matrix = [] + for i in range(self.__height): + row = [] + for j in range(self.__width): + row.append(self.__matrix[i][j] * other) + matrix.append(row) + return Matrix(matrix,self.__width,self.__height) + def __add__(self,other): + """ + implements the matrix-addition. + """ + if (self.__width == other.width() and self.__height == other.height()): + matrix = [] + for i in range(self.__height): + row = [] + for j in range(self.__width): + row.append(self.__matrix[i][j] + other.component(i,j)) + matrix.append(row) + return Matrix(matrix,self.__width,self.__height) + else: + raise Exception("matrix must have the same dimension!") + def __sub__(self,other): + """ + implements the matrix-subtraction. + """ + if (self.__width == other.width() and self.__height == other.height()): + matrix = [] + for i in range(self.__height): + row = [] + for j in range(self.__width): + row.append(self.__matrix[i][j] - other.component(i,j)) + matrix.append(row) + return Matrix(matrix,self.__width,self.__height) + else: + raise Exception("matrix must have the same dimension!") + + +def squareZeroMatrix(N): + """ + returns a square zero-matrix of dimension NxN + """ + ans = [] + for i in range(N): + row = [] + for j in range(N): + row.append(0) + ans.append(row) + return Matrix(ans,N,N) + + \ No newline at end of file diff --git a/linear-algebra-python/src/lib.pyc b/linear-algebra-python/src/lib.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7aeca0e1c6d56244f23a07bdeb3a1cf9cfa4ce82 GIT binary patch literal 11098 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 v>2s_v=3^rr|+Ei`w*zP|7Yf{hL literal 0 HcmV?d00001 diff --git a/linear-algebra-python/src/tests.py b/linear-algebra-python/src/tests.py new file mode 100644 index 000000000..b84612b4c --- /dev/null +++ b/linear-algebra-python/src/tests.py @@ -0,0 +1,133 @@ +# -*- coding: utf-8 -*- +""" +Created on Mon Feb 26 15:40:07 2018 + +@author: Christian Bender +@license: MIT-license + +This file contains the test-suite for the linear algebra library. +""" + +import unittest +from lib import * + +class Test(unittest.TestCase): + def test_component(self): + """ + test for method component + """ + x = Vector([1,2,3]) + self.assertEqual(x.component(0),1) + self.assertEqual(x.component(2),3) + try: + y = Vector() + self.assertTrue(False) + except: + self.assertTrue(True) + def test_str(self): + """ + test for toString() method + """ + x = Vector([0,0,0,0,0,1]) + self.assertEqual(x.__str__(),"(0,0,0,0,0,1)") + def test_size(self): + """ + test for size()-method + """ + x = Vector([1,2,3,4]) + self.assertEqual(x.size(),4) + def test_euclidLength(self): + """ + test for the eulidean length + """ + x = Vector([1,2]) + self.assertAlmostEqual(x.eulidLength(),2.236,3) + def test_add(self): + """ + test for + operator + """ + x = Vector([1,2,3]) + y = Vector([1,1,1]) + self.assertEqual((x+y).component(0),2) + self.assertEqual((x+y).component(1),3) + self.assertEqual((x+y).component(2),4) + def test_sub(self): + """ + test for - operator + """ + x = Vector([1,2,3]) + y = Vector([1,1,1]) + self.assertEqual((x-y).component(0),0) + self.assertEqual((x-y).component(1),1) + self.assertEqual((x-y).component(2),2) + def test_mul(self): + """ + test for * operator + """ + x = Vector([1,2,3]) + a = Vector([2,-1,4]) # for test of dot-product + b = Vector([1,-2,-1]) + self.assertEqual((x*3.0).__str__(),"(3.0,6.0,9.0)") + self.assertEqual((a*b),0) + def test_zeroVector(self): + """ + test for the global function zeroVector(...) + """ + self.assertTrue(zeroVector(10).__str__().count("0") == 10) + def test_unitBasisVector(self): + """ + test for the global function unitBasisVector(...) + """ + self.assertEqual(unitBasisVector(3,1).__str__(),"(0,1,0)") + def test_axpy(self): + """ + test for the global function axpy(...) (operation) + """ + x = Vector([1,2,3]) + y = Vector([1,0,1]) + self.assertEqual(axpy(2,x,y).__str__(),"(3,4,7)") + def test_copy(self): + """ + test for the copy()-method + """ + x = Vector([1,0,0,0,0,0]) + y = x.copy() + self.assertEqual(x.__str__(),y.__str__()) + def test_changeComponent(self): + """ + test for the changeComponent(...)-method + """ + x = Vector([1,0,0]) + x.changeComponent(0,0) + x.changeComponent(1,1) + self.assertEqual(x.__str__(),"(0,1,0)") + def test_str_matrix(self): + A = Matrix([[1,2,3],[2,4,5],[6,7,8]],3,3) + self.assertEqual("|1,2,3|\n|2,4,5|\n|6,7,8|\n",A.__str__()) + def test__mul__matrix(self): + A = Matrix([[1,2,3],[4,5,6],[7,8,9]],3,3) + x = Vector([1,2,3]) + self.assertEqual("(14,32,50)",(A*x).__str__()) + self.assertEqual("|2,4,6|\n|8,10,12|\n|14,16,18|\n",(A*2).__str__()) + def test_changeComponent_matrix(self): + A = Matrix([[1,2,3],[2,4,5],[6,7,8]],3,3) + A.changeComponent(0,2,5) + self.assertEqual("|1,2,5|\n|2,4,5|\n|6,7,8|\n",A.__str__()) + def test_component_matrix(self): + A = Matrix([[1,2,3],[2,4,5],[6,7,8]],3,3) + self.assertEqual(7,A.component(2,1),0.01) + def test__add__matrix(self): + A = Matrix([[1,2,3],[2,4,5],[6,7,8]],3,3) + B = Matrix([[1,2,7],[2,4,5],[6,7,10]],3,3) + self.assertEqual("|2,4,10|\n|4,8,10|\n|12,14,18|\n",(A+B).__str__()) + def test__sub__matrix(self): + A = Matrix([[1,2,3],[2,4,5],[6,7,8]],3,3) + B = Matrix([[1,2,7],[2,4,5],[6,7,10]],3,3) + self.assertEqual("|0,0,-4|\n|0,0,0|\n|0,0,-2|\n",(A-B).__str__()) + def test_squareZeroMatrix(self): + self.assertEqual('|0,0,0,0,0|\n|0,0,0,0,0|\n|0,0,0,0,0|\n|0,0,0,0,0|' + +'\n|0,0,0,0,0|\n',squareZeroMatrix(5).__str__()) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file