#!/usr/bin/env python
# coding: utf-8
# # Foundations of Computational Economics #8
#
# by Fedor Iskhakov, ANU
#
#
# ## Bundle goods market
#
#
#
#
# [https://youtu.be/Y6CtsI8X914](https://youtu.be/Y6CtsI8X914)
#
# Description: Object oriented programming in modeling consumer choice model.
# Consider the following model of a bundle goods market. A
# bundle of goods is a collection of particular items offered at a
# specified price. For example, Happy Meals at McDonalds is a set
# of items in a meal sold for a particular price.
#
# One other example of bundled goods - subscription packages in theaters,
# for example [La Scala in
# Milan](http://www.teatroallascala.org/en/box-office/subscriptions/types/subscription-types-2018-2019.html)
# or [Mariinsky in
# St.Petersburg](https://www.mariinsky.ru/playbill/subscriptions/2018_2019).
#
# In this task you will write code to implement and operationalize this
# setup.
# ### Bundle_good class
#
# Develop the Python class to represent a bundle good with the following specifications:
#
# - The class attribute (common to all objects of this class) is a
# list of goods
# - The public property is a vector of integers defining how many of each goods are in the bundle
# - The other property is the price for that bundle
#
#
# The following arithmetic operations are defined for the bungles:
#
# - addition:
# 1. sum of two bundles is a bundle with added up items and prices
# 1. sum of a bundle and a number (float or int) increases the price
# - subtraction:
# 1. difference between two bundles should produce a bundle with
# difference in items and difference in prices
# 1. subtracting a number (float or int) from a bundle should only
# decrease its price
# - multiplication is only defined for bundle and an integers, and results in the bundle with all items multiplied by this number, and price increased by the same number
# - devision is only defined for integers, and only such that the all quantities are divisible by this integer, the resulting bundle is a fraction of the original, with the price also decreased by the same number
#
#
# Complete the class definition code, and run the tests in the next cell.
# In[ ]:
class bundle_good():
'''Class of bundled goods with well defined arithmetics'''
items = ('Opera A', 'Opera B', \
'Ballet A', 'Ballet B', \
'Symphonic orchestra concert', \
'Rock opera', \
'Operetta') # 7 different goods
def __init__(self,quantities=[0,],price=0.0):
'''Creates the bundle good object, empty by default'''
pass
# ignore extra quantities if passed
# add zeros for the unspecified items
# ensure all quantities are integers
def __repr__(@@@):
'''String representation of the object'''
pass
def __add__(self,other):
'''Addition for bundle goods'''
pass
# if wrong type pass, raise the TypeError
# raise TypeError('Can only add bundle to bundle, or number to bundle price')
def __sub__(self,other):
'''Subtraction for bundles: subtract items and prices, or decrease price'''
pass
def __mul__(self,num):
'''Multiplication for bundles: proportional increase in nomenclature and price'''
pass
def __truediv__(self,num):
'''Division for bundles: fraction of the original bundle, only if quantities are divisable'''
pass
# ### Tests
#
# To make sure the class is running as it is supposed to, run all the
# tests below and confirm that the output is as expected.
# In[ ]:
# Tests
x=bundle_good([1,2,3,4,5,6,7],11.43)
print(x) #should print "Bundle object [1, 2, 3, 4, 5, 6, 7] with price 11.43"
# In[ ]:
x=bundle_good([1,2])
print(x) #should print "Bundle object [1, 2, 0, 0, 0, 0, 0] with price 0.00"
# In[ ]:
x=bundle_good(range(25),100.2)
print(x) #should print "Bundle object [0, 1, 2, 3, 4, 5, 6] with price 100.20"
# In[ ]:
x=bundle_good([1.5,2.3,3.2,4.1,5.75,6.86,7.97],1.43)
print(x) #should print "Bundle object [1, 2, 3, 4, 5, 6, 7] with price 1.43"
# In[ ]:
x=bundle_good([1,2,3,4,5,6,7],11.43)
y=bundle_good([7,6,5,4,3,2,1],77.45)
z=x+y
print(z) #should print "Bundle object [8, 8, 8, 8, 8, 8, 8] with price 88.88"
# In[ ]:
z=y-x
print(z) #should print "Bundle object [6, 4, 2, 0, -2, -4, -6] with price 66.02"
# In[ ]:
z=x+4.531
print(z) #should print "Bundle object [1, 2, 3, 4, 5, 6, 7] with price 15.96"
# In[ ]:
z=y-77
print(z) #should print "Bundle object [7, 6, 5, 4, 3, 2, 1] with price 0.45"
# In[ ]:
z=x*11
print(z) #should print "Bundle object [11, 22, 33, 44, 55, 66, 77] with price 125.73"
# In[ ]:
try:
z=x*11.5 #should raise a TypeError
except TypeError:
print("Ok 1") #should print "Ok 1"
# In[ ]:
try:
z=x*y #should raise a TypeError
except TypeError:
print("Ok 2") #should print "Ok 2"
# In[ ]:
try:
z=x/y #should raise a TypeError
except TypeError:
print("Ok 3") #should print "Ok 3"
# In[ ]:
z=(x+y)/8
print(z) #should print "Bundle object [1, 1, 1, 1, 1, 1, 1] with price 11.11"
# In[ ]:
try:
(x+y)/7 #should raise a ValueError
except ValueError:
print("Ok 4") #should print "Ok 4"
# In[ ]:
z=x*15-y*2
print(z) #should print "Bundle object [1, 18, 35, 52, 69, 86, 103] with price 16.55"
# ### Solution
# In[ ]:
class bundle_good():
'''Class of bundled goods with well defined arithmetics'''
items = ('Opera A', 'Opera B', \
'Ballet A', 'Ballet B', \
'Symphonic orchestra concert', \
'Rock opera', \
'Operetta') # 7 different goods
def __init__(self,quantities=[0,],price=0.0):
'''Creates the bundle good object
'''
n = len(bundle_good.items) # number of available items
if len(quantities)n:
# ignore extra numbers
quantities = quantities[0:n]
# create public attributes
# ensure the quantities in the object are integer
self.quantities=[int(x) for x in quantities]
self.price=price
def __repr__(self):
'''String representation of the object
'''
return 'Bundle object %r with price %1.2f' % (self.quantities,self.price)
def __add__(self,other):
'''Addition for bundles: add items and sum prices, or increase price
'''
if type(other) is bundle_good:
# add the quantities using list comprehension with one-to-one matching (zip)
q1 = [x+y for x,y in zip(self.quantities, other.quantities)]
# sum of the prices
p1 = self.price + other.price
# return new bundle
return bundle_good(quantities=q1,price=p1)
elif type(other) in (float,int):
# increase the price
p1 = self.price + other
# return new bundle
return bundle_good(quantities=self.quantities,price=p1)
else:
raise TypeError('Can only add bundle to bundle, or number to bundle price')
def __sub__(self,other):
'''Subtraction for bundles: subtract items and prices, or decrease price
'''
if type(other) is bundle_good:
# subtract the quantities using list comprehension with one-to-one matching (zip)
q1 = [x-y for x,y in zip(self.quantities, other.quantities)]
# sum of the prices
p1 = self.price - other.price
# return new bundle
return bundle_good(quantities=q1,price=p1)
elif type(other) in (float,int):
# decrease the price
p1 = self.price - other
# return new bundle
return bundle_good(quantities=self.quantities,price=p1)
else:
raise TypeError('Can only subtract bundle from bundle, or number from bundle price')
def __mul__(self,num):
'''Multiplication for bundles: repetition of the original bundle
'''
if type(num) is int:
# multiply quantities using list comprehension
q1 = [x * num for x in self.quantities]
# multiply the price
p1 = self.price * num
# return new bundle
return bundle_good(price=p1,quantities=q1)
else:
raise TypeError('Can only multiply bundle by an integer')
def __truediv__(self,num):
'''Division for bundles: fraction of the original bundle, only if quantities are devisable
'''
if type(num) is int:
# divide quantities and check for divisibility
q1 = [q//num for q in self.quantities]
if not all(q%num==0 for q in self.quantities):
# if can not be devided without a remainder, raise ValueError
raise ValueError('Can not divide bundle into fractional parts')
# divide the price
p1=self.price / num
# return new bundle
return bundle_good(price=p1,quantities=q1)
else:
raise TypeError('Can only divide bundle by an integer')