開発環境
- macOS Sierra - Apple (OS)
- Emacs (Text Editor)
- Python 3.6 (プログラミング言語)
行列プログラマー(Philip N. Klein (著)、 松田 晃一 (翻訳)、 弓林 司 (翻訳)、 脇本 佑紀 (翻訳)、 中田 洋 (翻訳)、 齋藤 大吾 (翻訳)、オライリージャパン)の2章(ベクトル)、2.14(問題)、Vec クラス用のプロシージャを書く、問題 2.14.10 を取り組んでみる。
問題 2.14.10
コード(Emacs)
# Copyright 2013 Philip N. Klein
def getitem(v, k):
"""
Return the value of entry k in v.
Be sure getitem(v,k) returns 0 if k is not represented in v.f.
>>> v = Vec({'a','b','c', 'd'},{'a':2,'c':1,'d':3})
>>> v['d']
3
>>> v['b']
0
"""
return v.f.get(k, 0)
def setitem(v, k, val):
"""
Set the element of v with label d to be val.
setitem(v,d,val) should set the value for key d even if d
is not previously represented in v.f, and even if val is 0.
>>> v = Vec({'a', 'b', 'c'}, {'b':0})
>>> v['b'] = 5
>>> v['b']
5
>>> v['a'] = 1
>>> v['a']
1
>>> v['a'] = 0
>>> v['a']
0
"""
assert k in v.D
v.f[k] = val
def equal(u, v):
"""
Return true iff u is equal to v.
Because of sparse representation, it is not enough to compare dictionaries
Consider using brackets notation u[...] and v[...] in your procedure
to access entries of the input vectors. This avoids some sparsity bugs.
>>> Vec({'a', 'b', 'c'}, {'a':0}) == Vec({'a', 'b', 'c'}, {'b':0})
True
>>> Vec({'a', 'b', 'c'}, {'a': 0}) == Vec({'a', 'b', 'c'}, {})
True
>>> Vec({'a', 'b', 'c'}, {}) == Vec({'a', 'b', 'c'}, {'a': 0})
True
Be sure that equal(u, v) checks equalities for all keys from u.f and v.f even if
some keys in u.f do not exist in v.f (or vice versa)
>>> Vec({'x','y','z'},{'y':1,'x':2}) == Vec({'x','y','z'},{'y':1,'z':0})
False
>>> Vec({'a','b','c'}, {'a':0,'c':1}) == Vec({'a','b','c'}, {'a':0,'c':1,'b':4})
False
>>> Vec({'a','b','c'}, {'a':0,'c':1,'b':4}) == Vec({'a','b','c'}, {'a':0,'c':1})
False
The keys matter:
>>> Vec({'a','b'},{'a':1}) == Vec({'a','b'},{'b':1})
False
The values matter:
>>> Vec({'a','b'},{'a':1}) == Vec({'a','b'},{'a':2})
False
"""
assert u.D == v.D
return all([getitem(u, k) == getitem(v, k) for k in u.D])
def add(u, v):
"""
Returns the sum of the two vectors.
Consider using brackets notation u[...] and v[...] in your procedure
to access entries of the input vectors. This avoids some sparsity bugs.
Do not seek to create more sparsity than exists in the two input vectors.
Doing so will unnecessarily complicate your code and will hurt performance.
Make sure to add together values for all keys from u.f and v.f even if some keys in u.f do not
exist in v.f (or vice versa)
>>> a = Vec({'a','e','i','o','u'}, {'a':0,'e':1,'i':2})
>>> b = Vec({'a','e','i','o','u'}, {'o':4,'u':7})
>>> c = Vec({'a','e','i','o','u'}, {'a':0,'e':1,'i':2,'o':4,'u':7})
>>> a + b == c
True
>>> a == Vec({'a','e','i','o','u'}, {'a':0,'e':1,'i':2})
True
>>> b == Vec({'a','e','i','o','u'}, {'o':4,'u':7})
True
>>> d = Vec({'x','y','z'}, {'x':2,'y':1})
>>> e = Vec({'x','y','z'}, {'z':4,'y':-1})
>>> f = Vec({'x','y','z'}, {'x':2,'y':0,'z':4})
>>> d + e == f
True
>>> d == Vec({'x','y','z'}, {'x':2,'y':1})
True
>>> e == Vec({'x','y','z'}, {'z':4,'y':-1})
True
>>> b + Vec({'a','e','i','o','u'}, {}) == b
True
"""
assert u.D == v.D
D = u.D | v.D
return Vec(D, {d: getitem(u, d) + getitem(v, d) for d in D
if (getitem(u, d) + getitem(v, d)) != 0})
def dot(u, v):
"""
Returns the dot product of the two vectors.
Consider using brackets notation u[...] and v[...] in your procedure
to access entries of the input vectors. This avoids some sparsity bugs.
>>> u1 = Vec({'a','b'}, {'a':1, 'b':2})
>>> u2 = Vec({'a','b'}, {'b':2, 'a':1})
>>> u1*u2
5
>>> u1 == Vec({'a','b'}, {'a':1, 'b':2})
True
>>> u2 == Vec({'a','b'}, {'b':2, 'a':1})
True
>>> v1 = Vec({'p','q','r','s'}, {'p':2,'s':3,'q':-1,'r':0})
>>> v2 = Vec({'p','q','r','s'}, {'p':-2,'r':5})
>>> v1*v2
-4
>>> w1 = Vec({'a','b','c'}, {'a':2,'b':3,'c':4})
>>> w2 = Vec({'a','b','c'}, {'a':12,'b':8,'c':6})
>>> w1*w2
72
The pairwise products should not be collected in a set before summing
because a set eliminates duplicates
>>> v1 = Vec({1, 2}, {1 : 3, 2 : 6})
>>> v2 = Vec({1, 2}, {1 : 2, 2 : 1})
>>> v1 * v2
12
"""
assert u.D == v.D
return sum([getitem(u, d) * getitem(v, d) for d in u.D | v.D])
def scalar_mul(v, alpha):
"""
Returns the scalar-vector product alpha times v.
Consider using brackets notation v[...] in your procedure
to access entries of the input vector. This avoids some sparsity bugs.
>>> zero = Vec({'x','y','z','w'}, {})
>>> u = Vec({'x','y','z','w'},{'x':1,'y':2,'z':3,'w':4})
>>> 0*u == zero
True
>>> 1*u == u
True
>>> 0.5*u == Vec({'x','y','z','w'},{'x':0.5,'y':1,'z':1.5,'w':2})
True
>>> u == Vec({'x','y','z','w'},{'x':1,'y':2,'z':3,'w':4})
True
"""
return Vec(v.D, {d: x * alpha for d, x in v.f.items()})
def neg(v):
"""
Returns the negation of a vector.
Consider using brackets notation v[...] in your procedure
to access entries of the input vector. This avoids some sparsity bugs.
>>> u = Vec({1,3,5,7},{1:1,3:2,5:3,7:4})
>>> -u
Vec({1, 3, 5, 7},{1: -1, 3: -2, 5: -3, 7: -4})
>>> u == Vec({1,3,5,7},{1:1,3:2,5:3,7:4})
True
>>> -Vec({'a','b','c'}, {'a':1}) == Vec({'a','b','c'}, {'a':-1})
True
"""
return Vec(v.D, {d: -1 * getitem(v, d) for d in v.D})
##########################################################################
class Vec:
"""
A vector has two fields:
D - the domain (a set)
f - a dictionary mapping (some) domain elements to field elements
elements of D not appearing in f are implicitly mapped to zero
"""
def __init__(self, labels, function):
assert isinstance(labels, set)
assert isinstance(function, dict)
self.D = labels
self.f = function
__getitem__ = getitem
__setitem__ = setitem
__neg__ = neg
__rmul__ = scalar_mul # if left arg of * is primitive, assume it's a scalar
def __mul__(self, other):
# If other is a vector, returns the dot product of self and other
if isinstance(other, Vec):
return dot(self, other)
else:
# Will cause other.__rmul__(self) to be invoked
return NotImplemented
def __truediv__(self, other): # Scalar division
return (1 / other) * self
__add__ = add
def __radd__(self, other):
"Hack to allow sum(...) to work with vectors"
if other == 0:
return self
def __sub__(a, b):
"Returns a vector which is the difference of a and b."
return a + (-b)
__eq__ = equal
def is_almost_zero(self):
s = 0
for x in self.f.values():
if isinstance(x, int) or isinstance(x, float):
s += x * x
elif isinstance(x, complex):
y = abs(x)
s += y * y
else:
return False
return s < 1e-20
def __str__(v):
"pretty-printing"
D_list = sorted(v.D, key=repr)
numdec = 3
wd = dict([(k, (1 + max(len(str(k)), len('{0:.{1}G}'.format(v[k], numdec))))) if isinstance(
v[k], int) or isinstance(v[k], float) else (k, (1 + max(len(str(k)), len(str(v[k]))))) for k in D_list])
s1 = ''.join(['{0:>{1}}'.format(str(k), wd[k]) for k in D_list])
s2 = ''.join(['{0:>{1}.{2}G}'.format(v[k], wd[k], numdec) if isinstance(
v[k], int) or isinstance(v[k], float) else '{0:>{1}}'.format(v[k], wd[k]) for k in D_list])
return "\n" + s1 + "\n" + '-' * sum(wd.values()) + "\n" + s2
def __hash__(self):
"Here we pretend Vecs are immutable so we can form sets of them"
h = hash(frozenset(self.D))
for k, v in sorted(self.f.items(), key=lambda x: repr(x[0])):
if v != 0:
h = hash((h, hash(v)))
return h
def __repr__(self):
return "Vec(" + str(self.D) + "," + str(self.f) + ")"
def copy(self):
"Don't make a new copy of the domain D"
return Vec(self.D, self.f.copy())
def __iter__(self):
raise TypeError('%r object is not iterable' % self.__class__.__name__)
入出力結果(Terminal, IPython)
$ python3 -m doctest vec.py -v
Trying:
a = Vec({'a','e','i','o','u'}, {'a':0,'e':1,'i':2})
Expecting nothing
ok
Trying:
b = Vec({'a','e','i','o','u'}, {'o':4,'u':7})
Expecting nothing
ok
Trying:
c = Vec({'a','e','i','o','u'}, {'a':0,'e':1,'i':2,'o':4,'u':7})
Expecting nothing
ok
Trying:
a + b == c
Expecting:
True
ok
Trying:
a == Vec({'a','e','i','o','u'}, {'a':0,'e':1,'i':2})
Expecting:
True
ok
Trying:
b == Vec({'a','e','i','o','u'}, {'o':4,'u':7})
Expecting:
True
ok
Trying:
d = Vec({'x','y','z'}, {'x':2,'y':1})
Expecting nothing
ok
Trying:
e = Vec({'x','y','z'}, {'z':4,'y':-1})
Expecting nothing
ok
Trying:
f = Vec({'x','y','z'}, {'x':2,'y':0,'z':4})
Expecting nothing
ok
Trying:
d + e == f
Expecting:
True
ok
Trying:
d == Vec({'x','y','z'}, {'x':2,'y':1})
Expecting:
True
ok
Trying:
e == Vec({'x','y','z'}, {'z':4,'y':-1})
Expecting:
True
ok
Trying:
b + Vec({'a','e','i','o','u'}, {}) == b
Expecting:
True
ok
Trying:
u1 = Vec({'a','b'}, {'a':1, 'b':2})
Expecting nothing
ok
Trying:
u2 = Vec({'a','b'}, {'b':2, 'a':1})
Expecting nothing
ok
Trying:
u1*u2
Expecting:
5
ok
Trying:
u1 == Vec({'a','b'}, {'a':1, 'b':2})
Expecting:
True
ok
Trying:
u2 == Vec({'a','b'}, {'b':2, 'a':1})
Expecting:
True
ok
Trying:
v1 = Vec({'p','q','r','s'}, {'p':2,'s':3,'q':-1,'r':0})
Expecting nothing
ok
Trying:
v2 = Vec({'p','q','r','s'}, {'p':-2,'r':5})
Expecting nothing
ok
Trying:
v1*v2
Expecting:
-4
ok
Trying:
w1 = Vec({'a','b','c'}, {'a':2,'b':3,'c':4})
Expecting nothing
ok
Trying:
w2 = Vec({'a','b','c'}, {'a':12,'b':8,'c':6})
Expecting nothing
ok
Trying:
w1*w2
Expecting:
72
ok
Trying:
v1 = Vec({1, 2}, {1 : 3, 2 : 6})
Expecting nothing
ok
Trying:
v2 = Vec({1, 2}, {1 : 2, 2 : 1})
Expecting nothing
ok
Trying:
v1 * v2
Expecting:
12
ok
Trying:
Vec({'a', 'b', 'c'}, {'a':0}) == Vec({'a', 'b', 'c'}, {'b':0})
Expecting:
True
ok
Trying:
Vec({'a', 'b', 'c'}, {'a': 0}) == Vec({'a', 'b', 'c'}, {})
Expecting:
True
ok
Trying:
Vec({'a', 'b', 'c'}, {}) == Vec({'a', 'b', 'c'}, {'a': 0})
Expecting:
True
ok
Trying:
Vec({'x','y','z'},{'y':1,'x':2}) == Vec({'x','y','z'},{'y':1,'z':0})
Expecting:
False
ok
Trying:
Vec({'a','b','c'}, {'a':0,'c':1}) == Vec({'a','b','c'}, {'a':0,'c':1,'b':4})
Expecting:
False
ok
Trying:
Vec({'a','b','c'}, {'a':0,'c':1,'b':4}) == Vec({'a','b','c'}, {'a':0,'c':1})
Expecting:
False
ok
Trying:
Vec({'a','b'},{'a':1}) == Vec({'a','b'},{'b':1})
Expecting:
False
ok
Trying:
Vec({'a','b'},{'a':1}) == Vec({'a','b'},{'a':2})
Expecting:
False
ok
Trying:
v = Vec({'a','b','c', 'd'},{'a':2,'c':1,'d':3})
Expecting nothing
ok
Trying:
v['d']
Expecting:
3
ok
Trying:
v['b']
Expecting:
0
ok
Trying:
u = Vec({1,3,5,7},{1:1,3:2,5:3,7:4})
Expecting nothing
ok
Trying:
-u
Expecting:
Vec({1, 3, 5, 7},{1: -1, 3: -2, 5: -3, 7: -4})
ok
Trying:
u == Vec({1,3,5,7},{1:1,3:2,5:3,7:4})
Expecting:
True
ok
Trying:
-Vec({'a','b','c'}, {'a':1}) == Vec({'a','b','c'}, {'a':-1})
Expecting:
True
ok
Trying:
zero = Vec({'x','y','z','w'}, {})
Expecting nothing
ok
Trying:
u = Vec({'x','y','z','w'},{'x':1,'y':2,'z':3,'w':4})
Expecting nothing
ok
Trying:
0*u == zero
Expecting:
True
ok
Trying:
1*u == u
Expecting:
True
ok
Trying:
0.5*u == Vec({'x','y','z','w'},{'x':0.5,'y':1,'z':1.5,'w':2})
Expecting:
True
ok
Trying:
u == Vec({'x','y','z','w'},{'x':1,'y':2,'z':3,'w':4})
Expecting:
True
ok
Trying:
v = Vec({'a', 'b', 'c'}, {'b':0})
Expecting nothing
ok
Trying:
v['b'] = 5
Expecting nothing
ok
Trying:
v['b']
Expecting:
5
ok
Trying:
v['a'] = 1
Expecting nothing
ok
Trying:
v['a']
Expecting:
1
ok
Trying:
v['a'] = 0
Expecting nothing
ok
Trying:
v['a']
Expecting:
0
ok
13 items had no tests:
vec
vec.Vec
vec.Vec.__hash__
vec.Vec.__init__
vec.Vec.__iter__
vec.Vec.__mul__
vec.Vec.__radd__
vec.Vec.__repr__
vec.Vec.__str__
vec.Vec.__sub__
vec.Vec.__truediv__
vec.Vec.copy
vec.Vec.is_almost_zero
7 items passed all tests:
13 tests in vec.add
14 tests in vec.dot
8 tests in vec.equal
3 tests in vec.getitem
4 tests in vec.neg
6 tests in vec.scalar_mul
7 tests in vec.setitem
55 tests in 20 items.
55 passed and 0 failed.
Test passed.
$
0 コメント:
コメントを投稿