Merge pull request #260 from christianbender/added_linearAlgebra

Added a linear algebra library
This commit is contained in:
Harshil 2018-03-05 11:08:50 +05:30 committed by GitHub
commit f6d7998335
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 535 additions and 0 deletions

View File

@ -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**.

View File

@ -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)

Binary file not shown.

View File

@ -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()