Multivariable Cumulants and Moments in python - python

In Mathematica I can convert multivariable moments in cumulants and back using MomentConvert:
MomentConvert[Cumulant[{2, 2,1}], "Moment"] // TraditionalForm
as one can try in wolframcloud.
I would like to do exactly the same in python. Is there any library in python capable of this?

At least the one direction I now programmed by myself:
# from http://code.activestate.com/recipes/577211-generate-the-partitions-of-a-set-by-index/
from collections import defaultdict
class Partition:
def __init__(self, S):
self.data = list(S)
self.m = len(S)
self.table = self.rgf_table()
def __getitem__(self, i):
#generates set partitions by index
if i > len(self) - 1:
raise IndexError
L = self.unrank_rgf(i)
result = self.as_set_partition(L)
return result
def __len__(self):
return self.table[self.m,0]
def as_set_partition(self, L):
# Transform a restricted growth function into a partition
n = max(L[1:]+[1])
m = self.m
data = self.data
P = [[] for _ in range(n)]
for i in range(m):
P[L[i+1]-1].append(data[i])
return P
def rgf_table(self):
# Compute the table values
m = self.m
D = defaultdict(lambda:1)
for i in range(1,m+1):
for j in range(0,m-i+1):
D[i,j] = j * D[i-1,j] + D[i-1,j+1]
return D
def unrank_rgf(self, r):
# Unrank a restricted growth function
m = self.m
L = [1 for _ in range(m+1)]
j = 1
D = self.table
for i in range(2,m+1):
v = D[m-i,j]
cr = j*v
if cr <= r:
L[i] = j + 1
r -= cr
j += 1
else:
L[i] = r // v + 1
r %= v
return L
# S = set(range(4))
# P = Partition(S)
# for x in P:
# print (x)
# using https://en.wikipedia.org/wiki/Cumulant#Joint_cumulants
import math
def Cum2Mom(arr, state):
def E(op):
return qu.expect(op, state)
def Arr2str(arr,sep):
r = ''
for i,x in enumerate(arr):
r += str(x)
if i<len(arr)-1:
r += sep
return r
if isinstance( arr[0],str):
myprod = lambda x: Arr2str(x,'*')
mysum = lambda x: Arr2str(x,'+')
E=lambda x: 'E('+str(x)+')'
myfloat = str
else:
myfloat = lambda x: x
myprod = np.prod
mysum = sum
S = set(range(len(arr)))
P = Partition(S)
return mysum([
myprod([myfloat(math.factorial(len(pi)-1) * (-1)**(len(pi)-1))
,myprod([
E(myprod([
arr[i]
for i in B
]))
for B in pi])])
for pi in P])
print(Cum2Mom(['a','b','c','d'],1) )
import qutip as qu
print(Cum2Mom([qu.qeye(3) for i in range(3)],qu.qeye(3)) )
It's designed to work with qutip opjects and it also works with strings to verify the correct separation and prefactors.
Exponents of the variables can be represented by repeating the variable.

Related

Errors in a class when trying to call it

I have this code consisting of a class and a subclass. The class is Euler forward, while the second one is Eulers midpoint method. These are for solving an ODE (x'=x(1/2-x)). Now it doesn't seem to work because when I am to call the function, by typing:
Euler=H.solve(6)
where the 6 is the amount of steps, I get attributeerror.
AttributeError: 'int' object has no attribute 'size'
Could anyone help me make my code more robust and working so I could plot the values later on, really don't see whats wrong. My code below:
import numpy as np
class H:
def __init__(self, f):
self._f = f
def initial(self, u0):
self._u0 = u0
def solve(self, time_points):
n = time_points.size
self._t = time_points
self._u = np.zeros(n)
self._u[0] = self._u0
for k in range(n-1):
self._k = k
self._u[k+1] = self.advance()
return self._u, self._t
class F(H):
def ad(self):
u = self._u; t = self._t; f = self._f; k = self._k
dt = t[k+1] - t[k]
u_k12 = u[k] + dt/2 * f(u[k], t[k])
return u[k] + dt * f(u_k12, (t[k] + dt/2) )
I think what's wrong is the way you use the class. Initial value is set with initial method (u0), then you give solve method the list of points. You can use np.linscape to generate midpoint.
np.linspace(0, 3, 31) # 30 points evenly spaced between 0 and 3
So it's like this:
def func(x, y):
return x * y
midpoint = np.linspace(0, 3, 31)
F_ = F(func)
F_.initial(6)
F_.solve(midpoint)
Code:
class H:
def __init__(self, f):
self._f = f
def initial(self, u0):
self._u0 = u0
def solve(self, time_points):
n = time_points.size
self._t = time_points
self._u = np.zeros(n)
self._u[0] = self._u0
for k in range(n-1):
self._u[k+1] = self.advance(k)
return self._u, self._t
def advance(self, k):
....
class F(H):
def advance(self, k):
dt = self._t[k+1] + self._t[k]
u_k12 = self._u[k] + dt/2 * self._f(self._u[k], self._t[k])
return self._u[k] + dt * self._f(u_k12, (self._t[k] + dt/2))

TypeError: 'list' object is not callable , problem with passing generated array to second iteration

I am trying to run 500 iterations in optimization problem. I am doing some changes on pop array and than I am trying to pass it again to the next iteration, however run into error, tho the first iteration is working all fine, I get pop array and then pass it to created_moved_pop and create_star_pop and get some problems. Will be very thankful if someone could explain my why this happens
error trace
C:\Users\yuliy\PycharmProjects\method_deform_stars\venv\Scripts\python.exe C:/Users/yuliy/PycharmProjects/method_deform_stars/DS.py
[0.8575697060274371, 0.8802225709314421, 0.6098937002728221, 0.5482650148523068, 0.5395302259903021, 0.6330576538506912, 0.734280095260012, 0.6826885236666879, 0.5797401283594749, 0.8381278588403586, 0.4983449567579089, 0.37081148554598065, 0.19916270916904044, 0.7590390380364216, 0.8272752130297748, 0.8837021413140848, 0.9750382019031415, 0.5436068899712437, 0.6490739970397773, 0.3014768191053475]
Traceback (most recent call last):
File "C:/Users/yuliy/PycharmProjects/method_deform_stars/DS.py", line 70, in
star_pop = create_star_pop(pop)
[(0.11503376215798591, 6.794025806650792), (0.5133530350808552, 1.0230252795290697), (0.37081148554598065, 0.8887201815324006), (0.4201038734097051, 0.8215339609930865), (0.6098937002728221, 0.7952234761836543), (0.19916270916904044, 0.7689552603259296), (0.250319764137194, 0.7111682294644993), (0.3014768191053475, 0.7008819653567403), (0.6582300480283956, 0.6632231712798371), (0.6666685334677784, 0.658688271415733), (0.7646482839856097, 0.6322183223530311), (0.8120560994714594, 0.6155315414048562), (0.7590390380364216, 0.59962403681057), (0.8609150000772217, 0.569512653796447), (0.8083043720319294, 0.5354111445749077), (0.620024614496207, 0.4887918787850577), (0.5035114962372264, 0.4844464118877576), (0.8670977366853939, 0.48321853250106644), (0.5541193285153655, 0.4821747663938167), (0.8575697060274371, 0.47491541406252397)]
File "C:/Users/yuliy/PycharmProjects/method_deform_stars/DS.py", line 60, in create_star_pop
new_element = star_pop(population)
TypeError: 'list' object is not callable
[0.11503376215798591, 0.5133530350808552, 0.37081148554598065, 0.4201038734097051, 0.6098937002728221, 0.19916270916904044, 0.250319764137194, 0.3014768191053475, 0.6582300480283956, 0.6666685334677784, 0.7646482839856097, 0.8120560994714594, 0.7590390380364216, 0.8609150000772217, 0.8083043720319294, 0.620024614496207, 0.5035114962372264, 0.8670977366853939, 0.5541193285153655, 0.8575697060274371]
Process finished with exit code 1
import numpy as np
import math
import random
import operator
# Global variables
a = 0.1
b = 1
def function(x):
return (math.sin(40*math.pi*x)+math.pow(x-1, 4))/(2*x)
def initial_pop():
pop = np.random.uniform(a, b, 20)
pop = pop.tolist()
return pop
def moving_pop(population):
# e c
rand_item = population[random.randrange(len(population))]
# print(rand_item)
direction_arr = [-1, 1]
direction = direction_arr[random.randrange(len(direction_arr))]
# print(direction)
new_element = rand_item + direction * np.random.normal(0, 0.2)
if new_element > b:
extra = new_element - b
new_element = a + extra
if new_element < a:
extra = abs(new_element - a)
new_element = b - extra
# print(new_element)
return new_element
def create_moved_pop(population):
new_population = []
for x in range(0, 20):
new_element = moving_pop(population)
new_population.append(new_element)
# print(new_population)
return new_population
def star_pop(population):
random_item1 = population[random.randrange(len(population))]
random_item2 = population[random.randrange(len(population))]
while random_item2 == random_item1:
random_item2 = population[random.randrange(len(population))]
e_star = (random_item1 + random_item2)/2
return e_star
def create_star_pop(population):
star_population = []
for x in range(0, 20):
new_element = star_pop(population)
star_population.append(new_element)
# print(new_population)
return star_population
pop = initial_pop()
print(pop)
for i in range(0, 500):
moved_pop = create_moved_pop(pop)
star_pop = create_star_pop(pop)
pop_combined = sorted(sorted(pop) + sorted(moved_pop) +
sorted(star_pop))
y_array = []
for x in range(0, len(pop_combined)):
y_array.append(function(pop_combined[x]))
x_y_array = dict(zip(pop_combined, y_array))
sorted_x_y_array = sorted(x_y_array.items(), key=operator.itemgetter(1), reverse=True)
sorted_x_y_array = sorted_x_y_array[0:20]
print(sorted_x_y_array)
pop.clear()
for x in sorted_x_y_array:
pop.append(x[0])
print(pop)
you are re-defining star_pop as list
star_pop = create_star_pop(pop)
find the below fixed code
import numpy as np
import math
import random
import operator
# Global variables
a = 0.1
b = 1
def function(x):
return (math.sin(40*math.pi*x)+math.pow(x-1, 4))/(2*x)
def initial_pop():
pop = np.random.uniform(a, b, 20)
pop = pop.tolist()
return pop
def moving_pop(population):
# e c
rand_item = population[random.randrange(len(population))]
# print(rand_item)
direction_arr = [-1, 1]
direction = direction_arr[random.randrange(len(direction_arr))]
# print(direction)
new_element = rand_item + direction * np.random.normal(0, 0.2)
if new_element > b:
extra = new_element - b
new_element = a + extra
if new_element < a:
extra = abs(new_element - a)
new_element = b - extra
# print(new_element)
return new_element
def create_moved_pop(population):
new_population = []
for x in range(0, 20):
new_element = moving_pop(population)
new_population.append(new_element)
# print(new_population)
return new_population
def star_pop(population):
random_item1 = population[random.randrange(len(population))]
random_item2 = population[random.randrange(len(population))]
while random_item2 == random_item1:
random_item2 = population[random.randrange(len(population))]
e_star = (random_item1 + random_item2)/2
return e_star
def create_star_pop(population):
star_population = []
for x in range(0, 20):
new_element = star_pop(population)
star_population.append(new_element)
# print(new_population)
return star_population
pop = initial_pop()
print(pop)
for i in range(0, 500):
moved_pop = create_moved_pop(pop)
star_pop_ = create_star_pop(pop)
pop_combined = sorted(sorted(pop) + sorted(moved_pop) +
sorted(star_pop_))
y_array = []
for x in range(0, len(pop_combined)):
y_array.append(function(pop_combined[x]))
x_y_array = dict(zip(pop_combined, y_array))
sorted_x_y_array = sorted(x_y_array.items(), key=operator.itemgetter(1), reverse=True)
sorted_x_y_array = sorted_x_y_array[0:20]
print(sorted_x_y_array)
pop.clear()
for x in sorted_x_y_array:
pop.append(x[0])
print(pop)
You got a method called star_pop and an object called star_pop, in the 2nd iteration of the for loop you are trying
new_element = star_pop(population)
after doing
star_pop = create_star_pop(pop)
which returns a list
I think you mixed up your names. You can fix it by renaming either the function or the star_pop list.
Unrelated to that, you dont need to include the 0 in range(0, 500). Ranges always start at 0 by default.

AttributeError: 'tuple' object has no attribute 'times_scalar'

This is my Linear System code. The times_scalar function is defined in the Vector object. When executing the multiply_coefficient_and_row function, I get AttributeError: 'tuple' object has no attribute 'times_scalar'. I tried different things including converting the tuple into a list and back to a tuple but had no success.
from decimal import Decimal, getcontext
from copy import deepcopy
from Vector import Vector
from Plane import Plane
getcontext().prec = 30
class LinearSystem(object):
ALL_PLANES_MUST_BE_IN_SAME_DIM_MSG = 'All planes in the system should live in the same dimension'
NO_SOLUTIONS_MSG = 'No solutions'
INF_SOLUTIONS_MSG = 'Infinitely many solutions'
def __init__(self, planes):
try:
d = planes[0].dimension
for p in planes:
assert p.dimension == d
self.planes = planes
self.dimension = d
except AssertionError:
raise Exception(self.ALL_PLANES_MUST_BE_IN_SAME_DIM_MSG)
def swap_rows(self, row1, row2):
self[row1], self[row2] = self[row2], self[row1]
def multiply_coefficient_and_row(self, coefficient, row):
n = self[row].normal_vector.coordinates
k = self[row].constant_term
new_normal_vector = n.times_scalar(coefficient)
new_constant_term = k * coefficient
self[row] = Plane(normal_vector = new_normal_vector, constant_term = new_constant_term)
def add_multiple_times_row_to_row(self, coefficient, row_to_add, row_to_be_added_to):
n1 = self[row_to_add].normal_vector.coordinates
n2 = self[row_to_be_added_to].normal_vector.coordinates
k1 = self[row_to_add].constant_term
k2 = self[row_to_be_added_to].constant_term
new_normal_vector = n1.times_scalar(coefficient).plus(n2)
new_constant_term = (k1 * coefficient) + k2
self[row_to_be_added_to] = Plane(normal_vector = new_normal_vector, constant_term = new_constant_term)
def indices_of_first_nonzero_terms_in_each_row(self):
num_equations = len(self)
num_variables = self.dimension
indices = [-1] * num_equations
for i,p in enumerate(self.planes):
try:
indices[i] = p.first_nonzero_index(p.normal_vector.coordinates)
except Exception as e:
if str(e) == Plane.NO_NONZERO_ELTS_FOUND_MSG:
continue
else:
raise e
return indices
def __len__(self):
return len(self.planes)
def __getitem__(self, i):
return self.planes[i]
def __setitem__(self, i, x):
try:
assert x.dimension == self.dimension
self.planes[i] = x
except AssertionError:
raise Exception(self.ALL_PLANES_MUST_BE_IN_SAME_DIM_MSG)
def __str__(self):
ret = 'Linear System:\n'
temp = ['Equation {}: {}'.format(i+1,p) for i,p in enumerate(self.planes)]
ret += '\n'.join(temp)
return ret
class MyDecimal(Decimal):
def is_near_zero(self, eps=1e-10):
return abs(self) < eps
and from the Vector class this times_scalar function:
def times_scalar(self, c):
new_coordinates = [Decimal(c) * x for x in self.coordinates]
return Vector(new_coordinates)

Python Knapsack Branch and Bound

I have spent a week working on this branch and bound code for the knapsack problem, and I have looked at numerous articles and books on the subject. However, when I am running my code I don't get the result I expect. Input is received from a text file, such as this:
12
4 1
1 1
3 2
2 3
where the first line is the capacity, and each subsequent line are value/weight pairs. The result I get from using this file is '8' instead of '10' (unless I am mistaken and all the items won't fit in the knapsack). Here is my code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import Queue
from collections import namedtuple
Item = namedtuple("Item", ['index', 'value', 'weight', 'level', 'bound', 'contains'])
class Node:
def __init__(self, level, value, weight, bound, contains):
self.level = level
self.value = value
self.weight = weight
self.bound = bound
self.contains = contains
def upper_bound(u, k, n, v, w):
if u.weight > k:
return 0
else:
bound = u.value
wt = u.weight
j = u.level + 1
while j < n and wt + w[j] <= k:
bound += v[j]
wt += w[j]
j += 1
# fill knapsack with fraction of a remaining item
if j < n:
bound += (k - wt) * (v[j] / w[j])
return bound
def knapsack(items, capacity):
item_count = len(items)
v = [0]*item_count
w = [0]*item_count
# sort items by value to weight ratio
items = sorted(items, key=lambda k: k.value/k.weight, reverse = True)
for i,item in enumerate(items, 0):
v[i] = int(item.value)
w[i] = int(item.weight)
q = Queue.Queue()
root = Node(0, 0, 0, 0.0, [])
root.bound = upper_bound(root, capacity, item_count, v, w)
q.put(root)
value = 0
taken = [0]*item_count
best = set()
while not q.empty():
c = q.get()
if c.bound > value:
level = c.level+1
# check 'left' node (if item is added to knapsack)
left = Node(c.value + v[level], c.weight + w[level], level, 0.0, c.contains[:])
left.contains.append(level)
if left.weight <= capacity and left.value > value:
value = left.value
best |= set(left.contains)
left.bound = upper_bound(left, capacity, item_count, v, w)
if left.bound > value:
q.put(left)
# check 'right' node (if items is not added to knapsack)
right = Node(c.value, c.weight, level, 0.0, c.contains[:])
right.contains.append(level)
right.bound = upper_bound(right, capacity, item_count, v, w)
if right.bound > value:
q.put(right)
for b in best:
taken[b] = 1
value = sum([i*j for (i,j) in zip(v,taken)])
return str(value)
Are my indices off? Am I not traversing the tree or calculating the bounds correctly?
def upper_bound(u, k, n, v, w):
if u.weight > k:
return 0
else:
bound = u.value
wt = u.weight
j = u.level
while j < n and wt + w[j] <= k:
bound += v[j]
wt += w[j]
j += 1
# fill knapsack with fraction of a remaining item
if j < n:
bound += (k - wt) * float(v[j])/ w[j]
return bound
def knapsack(items, capacity):
item_count = len(items)
v = [0]*item_count
w = [0]*item_count
# sort items by value to weight ratio
items = sorted(items, key=lambda k: float(k.value)/k.weight, reverse = True)
for i,item in enumerate(items, 0):
v[i] = int(item.value)
w[i] = int(item.weight)
q = Queue.Queue()
root = Node(0, 0, 0, 0.0,[])
root.bound = upper_bound(root, capacity, item_count, v, w)
q.put(root)
value = 0
taken = [0]*item_count
best = set()
while not q.empty():
c = q.get()
if c.bound > value:
level = c.level+1
# check 'left' node (if item is added to knapsack)
left = Node(level,c.value + v[level-1], c.weight + w[level-1], 0.0, c.contains[:])
left.bound = upper_bound(left, capacity, item_count, v, w)
left.contains.append(level)
if left.weight <= capacity:
if left.value > value:
value = left.value
best = set(left.contains)
if left.bound > value:
q.put(left)
# check 'right' node (if items is not added to knapsack)
right = Node(level,c.value, c.weight, 0.0, c.contains[:])
right.bound = upper_bound(right, capacity, item_count, v, w)
if right.weight <= capacity:
if right.value > value:
value = right.value
best = set(right.contains)
if right.bound > value:
q.put(right)
for b in best:
taken[b-1] = 1
value = sum([i*j for (i,j) in zip(v,taken)])
return str(value)
I think you only want to calculate the bound if you're not taking the item. If you take the item, that means that your bound is still attainable. If you don't, you have to readjust your expectations.
import functools
class solver():
def __init__(self, Items, capacity):
self.sortedItems = list(filter(lambda x: x.value > 0, Items))
self.sortedItems = sorted(self.sortedItems, key=lambda x:float(x.weight)/float(x.value))
self.numItems = len(Items)
self.capacity = capacity
self.bestSolution = solution(0, self.capacity)
def isOptimisitcBetter(self, sol, newItemIdx):
newItem = self.sortedItems[newItemIdx]
rhs = (sol.value + (sol.capacity/newItem.weight)*newItem.value)
return rhs > self.bestSolution.value
def explore(self, sol, itemIndex):
if itemIndex < self.numItems:
if self.isOptimisitcBetter(sol, itemIndex):
self.exploreLeft(sol, itemIndex)
self.exploreRight(sol, itemIndex)
def exploreLeft(self, sol, itemIndex):
newItem = self.sortedItems[itemIndex]
thisSol = sol.copy()
if thisSol.addItem(newItem):
if thisSol.value > self.bestSolution.value:
self.bestSolution = thisSol
self.explore(thisSol, itemIndex+1)
def exploreRight(self, sol, itemIndex):
self.explore(sol, itemIndex+1)
def solveWrapper(self):
self.explore(solution(0, self.capacity), 0)
class solution():
def __init__(self, value, capacity, items=set()):
self.value, self.capacity = value, capacity
self.items = items.copy()
def copy(self):
return solution(self.value, self.capacity, self.items)
def addItem(self, newItem):
remainingCap = self.capacity-newItem.weight
if remainingCap < 0:
return False
self.items.add(newItem)
self.capacity = remainingCap
self.value+=newItem.value
return True
solver = solver(items, capacity)
solver.solveWrapper()
bestSol = solver.bestSolution

Matrix Multiplication in pure Python?

I'm trying to multiply two matrices together using pure Python. Input (X1 is a 3x3 and Xt is a 3x2):
X1 = [[1.0016, 0.0, -16.0514],
[0.0, 10000.0, -40000.0],
[-16.0514, -40000.0, 160513.6437]]
Xt = [(1.0, 1.0),
(0.0, 0.25),
(0.0, 0.0625)]
where Xt is the zip transpose of another matrix. Now here is the code:
def matrixmult (A, B):
C = [[0 for row in range(len(A))] for col in range(len(B[0]))]
for i in range(len(A)):
for j in range(len(B[0])):
for k in range(len(B)):
C[i][j] += A[i][k]*B[k][j]
return C
The error that python gives me is this:
IndexError: list index out of range.
Now I'm not sure if Xt is recognised as an matrix and is still a list object, but technically this should work.
If you really don't want to use numpy you can do something like this:
def matmult(a,b):
zip_b = zip(*b)
# uncomment next line if python 3 :
# zip_b = list(zip_b)
return [[sum(ele_a*ele_b for ele_a, ele_b in zip(row_a, col_b))
for col_b in zip_b] for row_a in a]
x = [[1,2,3],[4,5,6],[7,8,9],[10,11,12]]
y = [[1,2],[1,2],[3,4]]
import numpy as np # I want to check my solution with numpy
mx = np.matrix(x)
my = np.matrix(y)
Result:
>>> matmult(x,y)
[[12, 18], [27, 42], [42, 66], [57, 90]]
>>> mx * my
matrix([[12, 18],
[27, 42],
[42, 66],
[57, 90]])
This is incorrect initialization. You interchanged row with col!
C = [[0 for row in range(len(A))] for col in range(len(B[0]))]
Correct initialization would be
C = [[0 for col in range(len(B[0]))] for row in range(len(A))]
Also I would suggest using better naming conventions. Will help you a lot in debugging. For example:
def matrixmult (A, B):
rows_A = len(A)
cols_A = len(A[0])
rows_B = len(B)
cols_B = len(B[0])
if cols_A != rows_B:
print "Cannot multiply the two matrices. Incorrect dimensions."
return
# Create the result matrix
# Dimensions would be rows_A x cols_B
C = [[0 for row in range(cols_B)] for col in range(rows_A)]
print C
for i in range(rows_A):
for j in range(cols_B):
for k in range(cols_A):
C[i][j] += A[i][k] * B[k][j]
return C
You can do a lot more, but you get the idea...
One liner:
def dot(m1, m2):
return [
[sum(x * y for x, y in zip(m1_r, m2_c)) for m2_c in zip(*m2)] for m1_r in m1
]
Explanation:
zip(*m2) - gets a column from the second matrix
zip(m1_r, m2_c) - creates tuple from m1 row and m2 column
sum(...) - sums multiplication row * col
Test:
m1 = [[1, 2, 3], [4, 5, 6]]
m2 = [[7, 8], [9, 10], [11, 12]]
result = dot(m1, m2)
assert result == [[58, 64], [139, 154]]
Here's some short and simple code for matrix/vector routines in pure Python that I wrote many years ago:
'''Basic Table, Matrix and Vector functions for Python 2.2
Author: Raymond Hettinger
'''
Version = 'File MATFUNC.PY, Ver 183, Date 12-Dec-2002,14:33:42'
import operator, math, random
NPRE, NPOST = 0, 0 # Disables pre and post condition checks
def iszero(z): return abs(z) < .000001
def getreal(z):
try:
return z.real
except AttributeError:
return z
def getimag(z):
try:
return z.imag
except AttributeError:
return 0
def getconj(z):
try:
return z.conjugate()
except AttributeError:
return z
separator = [ '', '\t', '\n', '\n----------\n', '\n===========\n' ]
class Table(list):
dim = 1
concat = list.__add__ # A substitute for the overridden __add__ method
def __getslice__( self, i, j ):
return self.__class__( list.__getslice__(self,i,j) )
def __init__( self, elems ):
list.__init__( self, elems )
if len(elems) and hasattr(elems[0], 'dim'): self.dim = elems[0].dim + 1
def __str__( self ):
return separator[self.dim].join( map(str, self) )
def map( self, op, rhs=None ):
'''Apply a unary operator to every element in the matrix or a binary operator to corresponding
elements in two arrays. If the dimensions are different, broadcast the smaller dimension over
the larger (i.e. match a scalar to every element in a vector or a vector to a matrix).'''
if rhs is None: # Unary case
return self.dim==1 and self.__class__( map(op, self) ) or self.__class__( [elem.map(op) for elem in self] )
elif not hasattr(rhs,'dim'): # List / Scalar op
return self.__class__( [op(e,rhs) for e in self] )
elif self.dim == rhs.dim: # Same level Vec / Vec or Matrix / Matrix
assert NPRE or len(self) == len(rhs), 'Table operation requires len sizes to agree'
return self.__class__( map(op, self, rhs) )
elif self.dim < rhs.dim: # Vec / Matrix
return self.__class__( [op(self,e) for e in rhs] )
return self.__class__( [op(e,rhs) for e in self] ) # Matrix / Vec
def __mul__( self, rhs ): return self.map( operator.mul, rhs )
def __div__( self, rhs ): return self.map( operator.div, rhs )
def __sub__( self, rhs ): return self.map( operator.sub, rhs )
def __add__( self, rhs ): return self.map( operator.add, rhs )
def __rmul__( self, lhs ): return self*lhs
def __rdiv__( self, lhs ): return self*(1.0/lhs)
def __rsub__( self, lhs ): return -(self-lhs)
def __radd__( self, lhs ): return self+lhs
def __abs__( self ): return self.map( abs )
def __neg__( self ): return self.map( operator.neg )
def conjugate( self ): return self.map( getconj )
def real( self ): return self.map( getreal )
def imag( self ): return self.map( getimag )
def flatten( self ):
if self.dim == 1: return self
return reduce( lambda cum, e: e.flatten().concat(cum), self, [] )
def prod( self ): return reduce(operator.mul, self.flatten(), 1.0)
def sum( self ): return reduce(operator.add, self.flatten(), 0.0)
def exists( self, predicate ):
for elem in self.flatten():
if predicate(elem):
return 1
return 0
def forall( self, predicate ):
for elem in self.flatten():
if not predicate(elem):
return 0
return 1
def __eq__( self, rhs ): return (self - rhs).forall( iszero )
class Vec(Table):
def dot( self, otherVec ): return reduce(operator.add, map(operator.mul, self, otherVec), 0.0)
def norm( self ): return math.sqrt(abs( self.dot(self.conjugate()) ))
def normalize( self ): return self / self.norm()
def outer( self, otherVec ): return Mat([otherVec*x for x in self])
def cross( self, otherVec ):
'Compute a Vector or Cross Product with another vector'
assert len(self) == len(otherVec) == 3, 'Cross product only defined for 3-D vectors'
u, v = self, otherVec
return Vec([ u[1]*v[2]-u[2]*v[1], u[2]*v[0]-u[0]*v[2], u[0]*v[1]-u[1]*v[0] ])
def house( self, index ):
'Compute a Householder vector which zeroes all but the index element after a reflection'
v = Vec( Table([0]*index).concat(self[index:]) ).normalize()
t = v[index]
sigma = 1.0 - t**2
if sigma != 0.0:
t = v[index] = t<=0 and t-1.0 or -sigma / (t + 1.0)
v /= t
return v, 2.0 * t**2 / (sigma + t**2)
def polyval( self, x ):
'Vec([6,3,4]).polyval(5) evaluates to 6*x**2 + 3*x + 4 at x=5'
return reduce( lambda cum,c: cum*x+c, self, 0.0 )
def ratval( self, x ):
'Vec([10,20,30,40,50]).ratfit(5) evaluates to (10*x**2 + 20*x + 30) / (40*x**2 + 50*x + 1) at x=5.'
degree = len(self) / 2
num, den = self[:degree+1], self[degree+1:] + [1]
return num.polyval(x) / den.polyval(x)
class Matrix(Table):
__slots__ = ['size', 'rows', 'cols']
def __init__( self, elems ):
'Form a matrix from a list of lists or a list of Vecs'
Table.__init__( self, hasattr(elems[0], 'dot') and elems or map(Vec,map(tuple,elems)) )
self.size = self.rows, self.cols = len(elems), len(elems[0])
def tr( self ):
'Tranpose elements so that Transposed[i][j] = Original[j][i]'
return Mat(zip(*self))
def star( self ):
'Return the Hermetian adjoint so that Star[i][j] = Original[j][i].conjugate()'
return self.tr().conjugate()
def diag( self ):
'Return a vector composed of elements on the matrix diagonal'
return Vec( [self[i][i] for i in range(min(self.size))] )
def trace( self ): return self.diag().sum()
def mmul( self, other ):
'Matrix multiply by another matrix or a column vector '
if other.dim==2: return Mat( map(self.mmul, other.tr()) ).tr()
assert NPRE or self.cols == len(other)
return Vec( map(other.dot, self) )
def augment( self, otherMat ):
'Make a new matrix with the two original matrices laid side by side'
assert self.rows == otherMat.rows, 'Size mismatch: %s * %s' % (`self.size`, `otherMat.size`)
return Mat( map(Table.concat, self, otherMat) )
def qr( self, ROnly=0 ):
'QR decomposition using Householder reflections: Q*R==self, Q.tr()*Q==I(n), R upper triangular'
R = self
m, n = R.size
for i in range(min(m,n)):
v, beta = R.tr()[i].house(i)
R -= v.outer( R.tr().mmul(v)*beta )
for i in range(1,min(n,m)): R[i][:i] = [0] * i
R = Mat(R[:n])
if ROnly: return R
Q = R.tr().solve(self.tr()).tr() # Rt Qt = At nn nm = nm
self.qr = lambda r=0, c=`self`: not r and c==`self` and (Q,R) or Matrix.qr(self,r) #Cache result
assert NPOST or m>=n and Q.size==(m,n) and isinstance(R,UpperTri) or m<n and Q.size==(m,m) and R.size==(m,n)
assert NPOST or Q.mmul(R)==self and Q.tr().mmul(Q)==eye(min(m,n))
return Q, R
def _solve( self, b ):
'''General matrices (incuding) are solved using the QR composition.
For inconsistent cases, returns the least squares solution'''
Q, R = self.qr()
return R.solve( Q.tr().mmul(b) )
def solve( self, b ):
'Divide matrix into a column vector or matrix and iterate to improve the solution'
if b.dim==2: return Mat( map(self.solve, b.tr()) ).tr()
assert NPRE or self.rows == len(b), 'Matrix row count %d must match vector length %d' % (self.rows, len(b))
x = self._solve( b )
diff = b - self.mmul(x)
maxdiff = diff.dot(diff)
for i in range(10):
xnew = x + self._solve( diff )
diffnew = b - self.mmul(xnew)
maxdiffnew = diffnew.dot(diffnew)
if maxdiffnew >= maxdiff: break
x, diff, maxdiff = xnew, diffnew, maxdiffnew
#print >> sys.stderr, i+1, maxdiff
assert NPOST or self.rows!=self.cols or self.mmul(x) == b
return x
def rank( self ): return Vec([ not row.forall(iszero) for row in self.qr(ROnly=1) ]).sum()
class Square(Matrix):
def lu( self ):
'Factor a square matrix into lower and upper triangular form such that L.mmul(U)==A'
n = self.rows
L, U = eye(n), Mat(self[:])
for i in range(n):
for j in range(i+1,U.rows):
assert U[i][i] != 0.0, 'LU requires non-zero elements on the diagonal'
L[j][i] = m = 1.0 * U[j][i] / U[i][i]
U[j] -= U[i] * m
assert NPOST or isinstance(L,LowerTri) and isinstance(U,UpperTri) and L*U==self
return L, U
def __pow__( self, exp ):
'Raise a square matrix to an integer power (i.e. A**3 is the same as A.mmul(A.mmul(A))'
assert NPRE or exp==int(exp) and exp>0, 'Matrix powers only defined for positive integers not %s' % exp
if exp == 1: return self
if exp&1: return self.mmul(self ** (exp-1))
sqrme = self ** (exp/2)
return sqrme.mmul(sqrme)
def det( self ): return self.qr( ROnly=1 ).det()
def inverse( self ): return self.solve( eye(self.rows) )
def hessenberg( self ):
'''Householder reduction to Hessenberg Form (zeroes below the diagonal)
while keeping the same eigenvalues as self.'''
for i in range(self.cols-2):
v, beta = self.tr()[i].house(i+1)
self -= v.outer( self.tr().mmul(v)*beta )
self -= self.mmul(v).outer(v*beta)
return self
def eigs( self ):
'Estimate principal eigenvalues using the QR with shifts method'
origTrace, origDet = self.trace(), self.det()
self = self.hessenberg()
eigvals = Vec([])
for i in range(self.rows-1,0,-1):
while not self[i][:i].forall(iszero):
shift = eye(i+1) * self[i][i]
q, r = (self - shift).qr()
self = r.mmul(q) + shift
eigvals.append( self[i][i] )
self = Mat( [self[r][:i] for r in range(i)] )
eigvals.append( self[0][0] )
assert NPOST or iszero( (abs(origDet) - abs(eigvals.prod())) / 1000.0 )
assert NPOST or iszero( origTrace - eigvals.sum() )
return Vec(eigvals)
class Triangular(Square):
def eigs( self ): return self.diag()
def det( self ): return self.diag().prod()
class UpperTri(Triangular):
def _solve( self, b ):
'Solve an upper triangular matrix using backward substitution'
x = Vec([])
for i in range(self.rows-1, -1, -1):
assert NPRE or self[i][i], 'Backsub requires non-zero elements on the diagonal'
x.insert(0, (b[i] - x.dot(self[i][i+1:])) / self[i][i] )
return x
class LowerTri(Triangular):
def _solve( self, b ):
'Solve a lower triangular matrix using forward substitution'
x = Vec([])
for i in range(self.rows):
assert NPRE or self[i][i], 'Forward sub requires non-zero elements on the diagonal'
x.append( (b[i] - x.dot(self[i][:i])) / self[i][i] )
return x
def Mat( elems ):
'Factory function to create a new matrix.'
m, n = len(elems), len(elems[0])
if m != n: return Matrix(elems)
if n <= 1: return Square(elems)
for i in range(1, len(elems)):
if not iszero( max(map(abs, elems[i][:i])) ):
break
else: return UpperTri(elems)
for i in range(0, len(elems)-1):
if not iszero( max(map(abs, elems[i][i+1:])) ):
return Square(elems)
return LowerTri(elems)
def funToVec( tgtfun, low=-1, high=1, steps=40, EqualSpacing=0 ):
'''Compute x,y points from evaluating a target function over an interval (low to high)
at evenly spaces points or with Chebyshev abscissa spacing (default) '''
if EqualSpacing:
h = (0.0+high-low)/steps
xvec = [low+h/2.0+h*i for i in range(steps)]
else:
scale, base = (0.0+high-low)/2.0, (0.0+high+low)/2.0
xvec = [base+scale*math.cos(((2*steps-1-2*i)*math.pi)/(2*steps)) for i in range(steps)]
yvec = map(tgtfun, xvec)
return Mat( [xvec, yvec] )
def funfit( (xvec, yvec), basisfuns ):
'Solves design matrix for approximating to basis functions'
return Mat([ map(form,xvec) for form in basisfuns ]).tr().solve(Vec(yvec))
def polyfit( (xvec, yvec), degree=2 ):
'Solves Vandermonde design matrix for approximating polynomial coefficients'
return Mat([ [x**n for n in range(degree,-1,-1)] for x in xvec ]).solve(Vec(yvec))
def ratfit( (xvec, yvec), degree=2 ):
'Solves design matrix for approximating rational polynomial coefficients (a*x**2 + b*x + c)/(d*x**2 + e*x + 1)'
return Mat([[x**n for n in range(degree,-1,-1)]+[-y*x**n for n in range(degree,0,-1)] for x,y in zip(xvec,yvec)]).solve(Vec(yvec))
def genmat(m, n, func):
if not n: n=m
return Mat([ [func(i,j) for i in range(n)] for j in range(m) ])
def zeroes(m=1, n=None):
'Zero matrix with side length m-by-m or m-by-n.'
return genmat(m,n, lambda i,j: 0)
def eye(m=1, n=None):
'Identity matrix with side length m-by-m or m-by-n'
return genmat(m,n, lambda i,j: i==j)
def hilb(m=1, n=None):
'Hilbert matrix with side length m-by-m or m-by-n. Elem[i][j]=1/(i+j+1)'
return genmat(m,n, lambda i,j: 1.0/(i+j+1.0))
def rand(m=1, n=None):
'Random matrix with side length m-by-m or m-by-n'
return genmat(m,n, lambda i,j: random.random())
if __name__ == '__main__':
import cmath
a = Table([1+2j,2,3,4])
b = Table([5,6,7,8])
C = Table([a,b])
print 'a+b', a+b
print '2+a', 2+a
print 'a/5.0', a/5.0
print '2*a+3*b', 2*a+3*b
print 'a+C', a+C
print '3+C', 3+C
print 'C+b', C+b
print 'C.sum()', C.sum()
print 'C.map(math.cos)', C.map(cmath.cos)
print 'C.conjugate()', C.conjugate()
print 'C.real()', C.real()
print zeroes(3)
print eye(4)
print hilb(3,5)
C = Mat( [[1,2,3], [4,5,1,], [7,8,9]] )
print C.mmul( C.tr()), '\n'
print C ** 5, '\n'
print C + C.tr(), '\n'
A = C.tr().augment( Mat([[10,11,13]]).tr() ).tr()
q, r = A.qr()
assert q.mmul(r) == A
assert q.tr().mmul(q)==eye(3)
print 'q:\n', q, '\nr:\n', r, '\nQ.tr()&Q:\n', q.tr().mmul(q), '\nQ*R\n', q.mmul(r), '\n'
b = Vec([50, 100, 220, 321])
x = A.solve(b)
print 'x: ', x
print 'b: ', b
print 'Ax: ', A.mmul(x)
inv = C.inverse()
print '\ninverse C:\n', inv, '\nC * inv(C):\n', C.mmul(inv)
assert C.mmul(inv) == eye(3)
points = (xvec,yvec) = funToVec(lambda x: math.sin(x)+2*math.cos(.7*x+.1), low=0, high=3, EqualSpacing=1)
basis = [lambda x: math.sin(x), lambda x: math.exp(x), lambda x: x**2]
print 'Func coeffs:', funfit( points, basis )
print 'Poly coeffs:', polyfit( points, degree=5 )
points = (xvec,yvec) = funToVec(lambda x: math.sin(x)+2*math.cos(.7*x+.1), low=0, high=3)
print 'Rational coeffs:', ratfit( points )
print polyfit(([1,2,3,4], [1,4,9,16]), 2)
mtable = Vec([1,2,3]).outer(Vec([1,2]))
print mtable, mtable.size
A = Mat([ [2,0,3], [1,5,1], [18,0,6] ])
print 'A:'
print A
print 'eigs:'
print A.eigs()
print 'Should be:', Vec([11.6158, 5.0000, -3.6158])
print 'det(A)'
print A.det()
c = Mat( [[1,2,30],[4,5,10],[10,80,9]] ) # Failed example from Konrad Hinsen
print 'C:\n', c
print c.eigs()
print 'Should be:', Vec([-8.9554, 43.2497, -19.2943])
A = Mat([ [1,2,3,4], [4,5,6,7], [2,1,5,0], [4,2,1,0] ] ) # Kincaid and Cheney p.326
print 'A:\n', A
print A.eigs()
print 'Should be:', Vec([3.5736, 0.1765, 11.1055, -3.8556])
A = rand(3)
q,r = A.qr()
s,t = A.qr()
print q is s # Test caching
print r is t
A[1][1] = 1.1 # Invalidate the cache
u,v = A.qr()
print q is u # Verify old result not used
print r is v
print u.mmul(v) == A # Verify new result
print 'Test qr on 3x5 matrix'
a = rand(3,5)
q,r = a.qr()
print q.mmul(r) == a
print q.tr().mmul(q) == eye(3)
When I had to do some matrix arithmetic I defined a new class to help. Within such a class you can define magic methods like __add__, or, in your use-case, __matmul__, allowing you to define x = a # b or a #= b rather than matrixMult(a,b). __matmul__ was added in Python 3.5 per PEP 465.
I have included some code which implements this below (I excluded the prohibitively long __init__ method, which essentially creates a two-dimensional list self.mat and a tuple self.order according to what is passed to it)
class Matrix:
def __matmul__(self, multiplier):
if self.order[1] != multiplier.order[0]:
raise ValueError("The multiplier was non-conformable under multiplication.")
return [[sum(a*b for a,b in zip(srow,mcol)) for mcol in zip(*multiplier.mat)] for srow in self.mat]
def __imatmul__(self, multiplier):
self.mat = self # multiplier
return self.mat
def __rmatmul__(self, multiplicand):
if multiplicand.order[1] != self.order[0]:
raise ValueError("The multiplier was non-conformable under multiplication.")
return [[sum(a*b for a,b in zip(mrow,scol)) for scol in zip(*self.mat)] for mrow in multiplicand.mat]
Note:
__rmatmul__ is used if b # a is called and b does not implement __matmul__ (e.g. if I wanted to implement premultiplying by a 2D list)
__imatmul__ is required for a #= b to work correctly;
If a matrix is non-conformable under multiplication it means that it cannot be multiplied, usually because it has more or less rows than there are columns in the multiplicand
Matrix Multiplication in pure python.
def matmult(m1,m2):
r=[]
m=[]
for i in range(len(m1)):
for j in range(len(m2[0])):
sums=0
for k in range(len(m2)):
sums=sums+(m1[i][k]*m2[k][j])
r.append(sums)
m.append(r)
r=[]
return m
The fault occurs here:
C[i][j]+=A[i][k]*B[k][j]
It crashes when k=2. This is because the tuple A[i] has only 2 values, and therefore you can only call it up to A[i][1] before it errors.
EDIT: Listen to Gerard's answer too, your C is wrong. It should be C=[[0 for row in range(len(A))] for col in range(len(A[0]))].
Just a tip: you could replace the first loop with a multiplication, so it would be C=[[0]*len(A) for col in range(len(A[0]))]
The shape of your matrix C is wrong; it's the transpose of what you actually want it to be. (But I agree with ulmangt: the Right Thing is almost certainly to use numpy, really.)
All the below answers would return you the list.Your need to convert it to matrix
def MATMUL(X, Y):
rows_A = len(X)
cols_A = len(X[0])
rows_B = len(Y)
cols_B = len(Y[0])
if cols_A != rows_B:
print "Matrices are not compatible to Multiply. Check condition C1==R2"
return
# Create the result matrix
# Dimensions would be rows_A x cols_B
C = [[0 for row in range(cols_B)] for col in range(rows_A)]
print C
for i in range(rows_A):
for j in range(cols_B):
for k in range(cols_A):
C[i][j] += A[i][k] * B[k][j]
C = numpy.matrix(C).reshape(len(A),len(B[0]))
return C
def matrixmult (A, B):
C = [[0 for row in range(len(A))] for col in range(len(B[0]))]
for i in range(len(A)):
for j in range(len(B[0])):
for k in range(len(B)):
C[i][j] += A[i][k]*B[k][j]
return C
at second line you should change
C = [[0 for row in range(len(B[0]))] for col in range(len(A))]
m=input("row")
n=input("col")
X=[]
for i in range (m):
m1=[]
for j in range (n):
m1.append(input("num"))
X.append(m1)
Y=[]
for i in range (m):
n1=[]
for j in range (n):
n1.append(input("num"))
Y.append(n1)
# result is 3x3
result = [[0,0,0],
[0,0,0],
[0,0,0]]
# iterate through rows of X
for i in range(len(X)):
# iterate through columns of Y
for j in range(len(Y[0])):
# iterate through rows of Y
for k in range(len(Y)):
result[i][j] += X[i][k] * Y[k][j]
for r in result:
print(r)
Had to delete the first post because I noticed an error but this should work fine for multiplying two matrixes.
from numpy import*
A = matrix([[1.0016, 0.0, -16.0514],[0.0, 10000.0, -40000.0],[-16.0514, -40000.0, 160513.6437]])
B = matrix([(1.0, 1.0),(0.0, 0.25),(0.0, 0.0625)])
n,m = shape(B)
C = ones((n,m*n))
index=0
matrixA=ones(shape(A))
for i in range(n):
if (i==1):
for y in range(n):
for z in range(n):
matrixA[y,z]=matrixA[y,z]*A[y,z]
elif(i>1):
matrixA=matrixA*A
if (i==0):
result=B
else:
result = matrixA * B
for x in range (n):
for y in range(m):
C[x,index] = result[x,y]
index+=1
index=index-m
index=index+m
print(C)

Categories