I am experimenting with the representation of a trivial statistics problem in Sympy:
For a sample space S, there are 6 possible distinct outcomes
a,b,c,d,e,f. We can define event A as having occurred if any of
a,b,c have, and event B as having ocurred if any of b,c,d have.
Given a probability mass function pmf defined over S, what is the
probability of event A?
When attempting to implement this symbolically, I receive the following error:
~/project/.envs/dev/lib/python3.6/site-packages/sympy/stats/frv.py in _test(self, elem)
164 elif val.is_Equality:
165 return val.lhs == val.rhs
--> 166 raise ValueError("Undecidable if %s" % str(val))
167
168 def __contains__(self, other):
ValueError: Undecidable if Eq(d, a) | Eq(d, b) | Eq(d, c)
The problem is implemented as follows with comments on the failing lines of code:
from sympy import Eq, Function, symbols
from sympy.logic import Or
from sympy.sets import FiniteSet, Union
from sympy.stats import FiniteRV, P
# 1. Define a sample space S with outcomes: a,b,c,d,e,f; Define events A, B
A = FiniteSet(*symbols('a b c'))
B = FiniteSet(*symbols('b c d'))
S = Union(A, B, FiniteSet(*symbols('e f')))
display("Sample Space", S)
pmfFunc = Function("pmf")
pmfDict = {v: pmfFunc(v) for v in S}
X = FiniteRV('X', pmfDict)
a,b = symbols('a b')
# 2. P(X = a) = pmf(a)
display(P(Eq(X,a)))
# 3. A.as_relational(X) yields `(X=a) \lor (X=b) \lor (X=c)`
display(A.as_relational(X))
# 4. P(X = a \lor X = b) = pmf(a) + pmf(b)
# - Actual Output: ValueError: Undecidable if Eq(c, a) | Eq(c, b)
display(P(Or(Eq(X,a), Eq(X,b)))) # [FAILS]
# 5. P(A) = pmf(a) + pmf(b) + pmf(c)
# - Actual Output: ValueError: Undecidable if Eq(d, a) | Eq(d, b) | Eq(d, c)
display(P(A.as_relational(X))) # [FAILS]
I obtain expected output up to display(A.as_relational(X)):
Interpreting the failure message suggests that Sympy is unable to tell that the set members are distinct. Replacing the symbols with integers resolves the error and I get output similar to what I desire.
A = FiniteSet(1, 2, 3)
B = FiniteSet(2, 3, 4)
S = Union(A, B, FiniteSet(5, 6))
If I am not misunderstanding the error or the fundamental use of the library, is there a way to tell Sympy that a collection of symbols is entirely distinct? I have attempted to replace the symbols with Dummy instances without success, and I have also attempted to leverage the assumptions module without success:
facts = [Eq(a,b) if a is b else Not(Eq(a,b)) for a, b in itertools.product(S, S)]
with assuming(*facts):
I would like to avoid confusing mappings between integers and symbolic forms, as user error may not be apparent when the results are printed as latex. I am willing to adopt some burden in a workaround (e.g., as it would have been maintaining a collection of Dummy instances), but I have yet to find an acceptable workaround.
Interesting question. Maybe it can be done with with assuming(Ne(a,b), ...): context but I take a more pragmatic approach: replace symbols with cos(non-zero integer) which SymPy can easily distinguish as equal or not:
>>> reps = dict(zip(var('a:f'),(cos(i) for i in range(1,7))))
>>> ireps = {v:k for k,v in reps.items()}
>>> a,b,c,d,e,f = [reps[i] for i in var('a:f')]
Then remove your a, b = symbols... line and replace display(x) with display(x.subs(ireps) to get
('Sample Space', FiniteSet(a, b, c, d, e, f))
(pmf(a),)
(Eq(X, a) | Eq(X, b) | Eq(X, c),)
(pmf(a) + pmf(b),)
(I use cos(int) instead of int because I am not sure whether any computation would result in addition of two elements and I want to make sure they stay distinct.)
Another approach would be to define a constant class that derives from Symbol:
class con(Symbol):
def __hash__(self):
return id(self)
def __eq__(a,b):
if isinstance(b, con):
return a.name == b.name
_eval_Eq = __eq__
a,b,c,d,e,f=map(con,'abcdef')
display=lambda*x:print(x)
from sympy import Eq, Function, symbols
from sympy.logic import Or
from sympy.sets import FiniteSet, Union
from sympy.stats import FiniteRV, P
A = FiniteSet(a,b,c)
B = FiniteSet(b,c,d)
S = Union(A, B, FiniteSet(e,f))
pmfFunc = Function("pmf")
pmfDict = {v: pmfFunc(v) for v in S}
X = FiniteRV('X', pmfDict)
display("Sample Space", S)
display(P(Eq(X,a)))
display(A.as_relational(X))
display(P(Or(Eq(X,a), Eq(X,b))))
display(P(A.as_relational(X)))
gives
('Sample Space', FiniteSet(a, b, c, d, e, f))
(pmf(a),)
(Eq(X, a) | Eq(X, b) | Eq(X, c),)
(pmf(a) + pmf(b),)
(pmf(a) + pmf(b) + pmf(c),)
I'm trying an ultra simple novice exercise.
The objective of the exercise was to create a fibonacci pattern, I tried two methods that I thought were going to give the same result. But fires some reason they don't, I can't understand why.
Any ideas?
CODE 1
a = 0
b = 1
while b < 100:
print(b)
a = b
b = a + b
CODE 2:
a, b = 0, 1
while b < 100:
print(b)
a, b = b, a + b
In "CODE 1", a = b makes the next line equivalent to b = b + b, which is not correct.
In "CODE 2", a,b=b,a+b is essentially new_a = old_b; new_b = old_a + old_b. The new values are computed from the old values, then the new values are assigned to the variables. This computes the fibonacci series correctly.
To do it correctly in "CODE 1" a temporary variable is needed:
t = a
a = b
b = t + b # use original a saved in t to compute b
a,b=b,a+b eliminates the need for the temporary variable.
I'm having difficulties with this task in python 3.7:
"Define a function that given two integers, a and b, returns the value of their sum. However, if the difference of a and b is an even number, the value of the sum is doubled, on the other hand, if the difference is an odd number, the value of the product of a and b gets added to the value of the sum.
For now, do not use conditionals (if)."
I don't know how to do it without using if statements. I would be thankful if anyone could help me.
If a=2 and b=2, the output should be 8.
If a=1 and b=4, the output should be 9.
To determine if the sum of the two integers is even, we use the modulo operator. The following will only evaluate to 0 or 1: (a - b) % 2. 0 = even, 1 = odd.
Knowing this, we can use this value to index into a list which contains 2 functions.
At index 0 we have the double function, which will be called when the value is even, and at index 1 we have the add_product function, called when it's odd.
def process_numbers(a, b):
def double(c):
c *= 2
return c
def add_product(c):
c += a * b
return c
functions = [double, add_product]
c = a + b
c = functions[(a - b) % 2](c)
print(c)
return c
Here is another solution using anonymous (lambda) functions, and taking advantage of the fact that c & 1 will always evaluate to 0 if the difference between a and b is even, and 1 if it's odd.
def process_numbers(a, b):
functions = (lambda: c*2, lambda: c + a*b)
c = a + b
return functions[c & 1]()
And a one-line monstrosity (avert your eyes!):
>>> (lambda a, b: (lambda: (a + b) * 2, lambda: a + b + a * b)[a + b & 1]())(1, 4)
9
>>> (lambda a, b: (lambda: (a + b) * 2, lambda: a + b + a * b)[a + b & 1]())(2, 2)
8
It's a nice little puzzle. Where did you come across it?
Another solution, based off Demi-Lune's functionless solution.
>>> a, b = 2, 2
>>> (a + b & 1)*(a + b + a*b) + (1 - a + b & 1)*(a + b)*2
8
>>> a, b = 1, 4
>>> (a + b & 1)*(a + b + a*b) + (1 - a + b & 1)*(a + b)*2
9
If the sum of a and b is even, the left half evaluates to 0, and the right half evaluates to the sum being doubled.
If the sum of a and b is odd, the right half evaluates to 0, and the left half evaluates to the sum plus the product.
I am supposed to code this pattern:
[1]
[0][0]
[1][1][1]
[0][0][0][0]
[1][1][1][1][1]
[0][0][0][0][0][0]
[1][1][1][1][1][1][1]
[0][0][0][0][0][0][0][0]
[1][1][1][1][1][1][1][1][1]
However, i am only able to give a output like this:
[1]
[0][0]
[1][1][1]
[0][0][0][0]
[1][1][1][1][1]
[0][0][0][0][0][0]
[1][1][1][1][1][1][1]
[0][0][0][0][0][0][0][0]
[1][1][1][1][1][1][1][1][1]
[0][0][0][0][0][0][0][0][0][0]
this is my current code:
a = '[1]'
b = '[0][0]'
for c in range(1,10,2):
print(a)
a = a + '[1][1]'
print(b)
b = b + '[0][0]'
Please help! I am supposed to the pattern with a while loop and for loop. Thanks in advance!
You're printing both a and b in every iteration, so naturally you can't get odd number of lines in your output.
Instead, use a normal range iterator of 9 and alternate between printing and appending to a and b depending on the counter's remainder of 2.
a = '[1]'
b = '[0][0]'
for c in range(9):
if c % 2 == 0:
print(a)
a = a + '[1][1]'
else:
print(b)
b = b + '[0][0]'
This outputs:
[1]
[0][0]
[1][1][1]
[0][0][0][0]
[1][1][1][1][1]
[0][0][0][0][0][0]
[1][1][1][1][1][1][1]
[0][0][0][0][0][0][0][0]
[1][1][1][1][1][1][1][1][1]
I am interested in figuring out how many times each number occurs once in a numberrange of 5 digits, like 01234, 01243, 01324, etc ....
I know that the occurence is 120 unique times
At the moment I have programmed it with a lot of for loops and a lot of ands.
as you can see in the code
number = 5
for a in range(number):
for b in range(number):
for c in range(number):
for d in range(number):
for e in range(number):
if (a != b and a != c and a != d and a != e and
b != c and b != d and b != e and c != d and
c != e and d != e):
print ('{}{}{}{}{}'.format(a, b, c, d, e))
Is there a different and a nicer way to program the code above?
Greets,
Superfly
Someone suggested using itertools. Here is the code to use:
from itertools import permutations
#generator
factorials = permutations(set(range(5)))
for fact in factorials:
print(fact)
If you would not like to use itertools, but would like to generate every string, you can use a list comprehension to put it all in one line.
rn = range(number)
number= 5
sequences = [(a,b,c,d,e) for a in rn for b in rn for c in rn for d in rn for e in rn if a != b and a!= c and a!= d and a!= e and b!= c and b!=d and b!=e and c!=d and c!= e and d!= e]
Alternatively, you could define a method to recursively create new lists and append items
def rGenFactorials(L, leng=5, collected = [], restrictions=set()):
# base case
if len(L) == leng:
collected.append(L)
return
#induction
options = set(range(leng))
options -= restrictions
for op in options:
# copy restrictions
r = set(restrictions)
# add new restriction
r.add(op)
# copy list
l = L[:]
# append unused int
l.append(op)
# recursive invocation
rGenFactorials(L=l,collected = collected, restrictions=r)
C = []
rGenFactorials([], collected = C)
for c in C:
print(c)