0

I have a class of objects called Vector. I am going to include the class early on as I think it is necessary, if not, please tell me so i can delete it immediately (to avoid DV).

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):
        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:
            return NotImplemented  #  Will cause other.__rmul__(self) to be invoked

    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):
                s += x*x.conjugate()
            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())

I now have to write procedures so that, it works?. I have completed this assignment, i had 8/9. This is great but i need 9/9 because its being used in another assignment. (This is to clarify that i'm not mindlessly posting homework questions on here.)

def getitem(v,k):
    kthelement = 0
    try:
        kthelement = v.f[k]
    except Exception:
        kthelement = 0
    return kthelement



def setitem(v,k,val):
    v.f[k] = val


def equal(u,v):
    result = False
    unmatched_item = set(v.f.items()) ^ set(u.f.items())
    if len(unmatched_item) == 0:
        result = True
    return result

The first 2 are fine and work. This third one is the problem. It works sometimes, then some some comparisons it returns False when True or the converse.

Also if,

D = {'a','b','c'}
v1 = Vec(D, {'a': 1})
v2 = Vec(D, {'a':1, 'b':0}

Then v1 == v2

Could someone help me out on this last one please.

  • Nevermind this comment, sorry, I get what you mean. – Paul Mar 01 '15 at 16:25
  • Why are you defining `__getitem__`, `__setitem__`, `__eq__`, etc outside the class like that? – martineau Mar 01 '15 at 16:54
  • `v1 == v2` --> `False` because `unmatched_item` is `{('b', 0)}` which has a `len()` of `1`, so `len(unmatched_item) == 0` is `False`. – martineau Mar 01 '15 at 17:09
  • In my code it does return False, but in terms of vectors, v1 == v2 is actually true, because technically speaking my domain is 3d space. by default, if an element is not specified a map then it is mapped to 0.( i.e (x,y,0) 2d plane in 3d space) I think i should have mentioned this in my post. For the procedure to be marked as correct, Vec({'a', 'b', 'c'}, {'a':0}) == Vec({'a', 'b', 'c'}, {'b':0}) has to return True. – Adam Thompson Mar 01 '15 at 19:27

2 Answers2

0

The problem you are having is that, as far as I can tell, you never implemented the mechanism by which 0 is returned for items in the domain. There are probably many ways to fix this, one way is to construct the dictionary in the constructor:

def __init__(self, labels, function):
    self.D = labels
    self.f = {label: function.get(label, 0) for label in D}

I haven't fully thought through all the implications on the other parts of your function though, but if you intend f to store a dict containing only the parts of the dict function which are in D, then this implements that.

That said, if you intend for f to be something the user can manipulate directly, you may want to implement it as a property (see this question), in which case your original __init__ would work, and you'd move the dictionary comprehension from my version of __init__ into the f property setter.

Also, I should add that I'm assuming from the comment that you want to exclude anything in function that is not in D, so you'll notice that using your original code:

D = {'a','b','c'}
v1 = Vec(D, {'a': 1})
v2 = Vec(D, {'a':1, 'b':0})

print(v1 == v2)

v3 = Vec(D, {'a': 1, 'e': 4})
print(v1 == v3)

Returns:

False
False

But with the dict comprehension, it returns:

True
True

If you would prefer to throw an error if labels not in the domain are found (or allow them in the .f property), you'll have to handle that situation as well.

Paul
  • 10,381
  • 13
  • 48
  • 86
0

I have solved it. This returns the desired result.

def equal(u,v):
    counter = 0
    for k in u.D:
        if v[k] == u[k]:
            counter += 1
    return counter == len(u.D)