Related
If you have two sets a and b and intersect them, there are three interesting parts (which may be empty): h(ead) elements of a not in b, i(ntersection) elements in both a and b, and t(ail) elements of b not in a.
For example: {1, 2, 3} & {2, 3, 4} -> h:{1}, i:{2, 3}, t:{4} (not actual Python code, clearly)
One very clean way to code that in Python:
h, i, t = a - b, a & b, b - a
I figure that this can be slightly more efficient though:
h, t = a - (i := a & b), b - i
Since it first computes the intersection and then subtracts only that from a and then b, which would help if i is small and a and b are large - although I suppose it depends on the implementation of the subtraction whether it's truly faster. It's not likely to be worse, as far as I can tell.
I was unable to find such an operator or function, but since I can imagine efficient implementations that would perform the three-way split of a and b into h, i, and t in fewer iterations, am I missing something like this, which may already exist?
from magical_set_stuff import hit
h, i, t = hit(a, b)
It's not in Python, and I haven't seen such a thing in a 3rd-party library either.
Here's a perhaps unexpected approach that's largely insensitive to which sets are bigger than others, and to how much overlap among inputs there may be. I dreamed it up when facing a related problem: suppose you had 3 input sets, and wanted to derive the 7 interesting sets of overlaps (in A only, B only, C only, both A and B, both A and C, both B and C, or in all 3). This version strips that down to the 2-input case. In general, assign a unique power of 2 to each input, and use those as bit flags:
def hit(a, b):
x2flags = defaultdict(int)
for x in a:
x2flags[x] = 1
for x in b:
x2flags[x] |= 2
result = [None, set(), set(), set()]
for x, flag in x2flags.items():
result[flag].add(x)
return result[1], result[3], result[2]
I won't accept my own answer unless nobody manages to beat my own solution or any of the good and concise Python ones.
But for anyone interested in some numbers:
from random import randint
from timeit import timeit
def grismar(a: set, b: set):
h, i, t = set(), set(), b.copy()
for x in a:
if x in t:
i.add(x)
t.remove(x)
else:
h.add(x)
return h, i, t
def good(a: set, b: set):
return a - b, a & b, b - a
def better(a: set, b: set):
h, t = a - (i := a & b), b - i
return h, i, t
def ok(a: set, b: set):
return a - (a & b), a & b, b - (a & b)
from collections import defaultdict
def tim(a, b):
x2flags = defaultdict(int)
for x in a:
x2flags[x] = 1
for x in b:
x2flags[x] |= 2
result = [None, set(), set(), set()]
for x, flag in x2flags.items():
result[flag].add(x)
return result[1], result[3], result[2]
def pychopath(a, b):
h, t = set(), b.copy()
h_add = h.add
t_remove = t.remove
i = {x for x in a
if x in t and not t_remove(x) or h_add(x)}
return h, i, t
def enke(a, b):
t = b - (i := a - (h := a - b))
return h, i, t
xs = set(randint(0, 10000) for _ in range(10000))
ys = set(randint(0, 10000) for _ in range(10000))
# validation
g = (f(xs, ys) for f in (grismar, good, better, ok, tim, enke))
l = set(tuple(tuple(sorted(s)) for s in t) for t in g)
assert len(l) == 1, 'functions are equivalent'
# warmup, not competing
timeit(lambda: grismar(xs, ys), number=500)
# competition
print('a - b, a & b, b - a ', timeit(lambda: good(xs, ys), number=10000))
print('a - (i := a & b), b - i ', timeit(lambda: better(xs, ys), number=10000))
print('a - (a & b), a & b, b - (a & b) ', timeit(lambda: ok(xs, ys), number=10000))
print('tim ', timeit(lambda: tim(xs, ys), number=10000))
print('grismar ', timeit(lambda: grismar(xs, ys), number=10000))
print('pychopath ', timeit(lambda: pychopath(xs, ys), number=10000))
print('b - (i := a - (h := a - b)) ', timeit(lambda: enke(xs, ys), number=10000))
Results:
a - b, a & b, b - a 5.6963334
a - (i := a & b), b - i 5.3934624
a - (a & b), a & b, b - (a & b) 9.7732018
tim 16.3080373
grismar 7.709292500000004
pychopath 6.76331460000074
b - (i := a - (h := a - b)) 5.197220600000001
So far, the optimisation proposed by #enke in the comments appears to win out:
t = b - (i := a - (h := a - b))
return h, i, t
Edit: added #Pychopath's results, which is indeed substantially faster than my own, although #enke's result is still the one to beat (and likely won't be with just Python). If #enke posts their own answer, I'd happily accept it as the answer.
Optimized version of yours, seems to be about 20% faster than yours in your benchmark:
def hit(a, b):
h, t = set(), b.copy()
h_add = h.add
t_remove = t.remove
i = {x for x in a
if x in t and not t_remove(x) or h_add(x)}
return h, i, t
And you might want to do this at the start, especially if the two sets can have significantly different sizes:
if len(a) > len(b):
return hit(b, a)[::-1]
I am trying to make a tic-tac-toe game however when I try implement two players, the printed out result (current game state) is not as expected.
for example when I try to put the letter 'x' in box 1 it will add random letters/numbers in different spots. I have already tried this with only one player and it wrks perfectly.
import random
a = ' '
b = ' '
c = ' '
d = ' '
e = ' '
f = ' '
g = ' '
h = ' '
i = ' '
def gamestateboard(a, b, c, d, e, f, g, h, i):
x = [a, b, c]
y = [d, e, f]
z = [g, h, i]
print(x)
print(y)
print(z)
gamestateboard(a, b, c, d, e, f, g, h, i)
def checkwin():
if a == 0 and b == 0 and c == 0:
print('Winner')
if a == 0 and d == 0 and g == 0:
print('Winner')
if g == 0 and h == 0 and i == 0:
print('Winner')
if c == 0 and e == 0 and g == 0:
print('Winner')
if a == 0 and e == 0 and i == 0:
print('Winner')
if c == 0 and f == 0 and i == 0:
print('Winner')
for i in range(1000000):
inputs = str(input('Enter a position: '))
if i%2 == 0:
if inputs == '1':
a = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '2':
b = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '3':
c = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '4':
d = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '5':
e = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '6':
f = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '7':
g = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '8':
h = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '9':
i = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
else:
if inputs == '1':
a = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '2':
b = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '3':
c = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '4':
d = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '5':
e = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '6':
f = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '7':
g = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '8':
h = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '9':
i = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
You are using i as your loop variable but also the name of a variable you use to draw in your game world.
I recommend moving away from having these variables and using indexes.
gameworld =[ [' ',' ',' '] for i in range(3)]
def draw_world():
for i in range(3):
print(gameworld[i])
then you can ask for coordinates or divide and use the modulus to use a single value like you did before. 4 // 3 = 1 4 % 3 = 1 position 4 is at [1][1]
This means you don't need your giant if input == list.
edit: Oh yeah you probably also want to do a loop with something like
no_winner = True
while no_winner:
...
you can set no_winner to False if check_win returns true and then you game doens't go on forever
edit 2:
Almost forgot you have an indenting error with the else for i%2==0 though I'm guessing that may be just from when you copied and pasted into your question. You also never check to see if someone else has already taken a square so when your code does actually work a player can overwrite another player's move.
I want to create a function called multipoly(x,y) which takes two lists as input, multiplies the lists and returns the answers.
Polynomial is represented as follows: for instance x^4+2X^3 is represented as [(1,4),(2,3)].
Here is something I get but it returns wrong answer for some test cases:
def multipoly(p1,p2):
x=max(p1,p2)
y=min(p1,p2)
p1=x
p2=y
for i in range(len(x)):
for item in p2:
p1[i] = ((p1[i][0] * item[0]), (p1[i][1] + item[1]))
p2.remove(item)
return p1
print(multipoly([(1,1),(-1,0)],[(1,2),(1,1),(1,0)]))
You are probably better off to implement this as a class to encapsulate all the operations on a polynomial:
maybe something like this as a basis to start?
Here, I chose to represent the polynomial via a sequence of coefficients where the indices are the corresponding exponents of x
Caveat, the results look okay, but I did not write tests, so it may be brittle on some corner cases.
class Polynomial:
def __init__(self, coefficients:list):
"""represents polynomials as a list of parameters where
the indices are the exponents"""
self.coefficients = coefficients
def __len__(self):
return len(self.coefficients)
def __getitem__(self, idx):
return self.coefficients[idx]
def __iter__(self):
for coeff in self.coefficients:
yield coeff
def __str__(self):
res = [str(self.coefficients[0]) + ' + '] if self.coefficients[0] != 0 else []
for exponent, coeff in enumerate(self.coefficients[1:]):
e = exponent + 1
if coeff != 0:
if e == 1:
if coeff == 1:
res.append('x + ')
else:
res.append(f'({coeff})*x + ')
elif coeff == 1:
res.append(f'x**{e} + ')
else:
res.append(f'({coeff})*x**{e} + ')
return ''.join(res)[:-3]
def __add__(self, other):
result = [0] * max(len(self), len(other))
for idx in range(len(result)):
try:
a = self[idx]
except IndexError:
a = 0
try:
b = other[idx]
except IndexError:
b = 0
result[idx] = a + b
return Polynomial(result)
def __mul__(self, other):
result = [0] * (len(self) + len(other))
for exponent_a, coeff_a in enumerate(self):
for exponent_b, coeff_b in enumerate(other):
result[exponent_a + exponent_b] += coeff_a * coeff_b
return Polynomial(result)
def d_dx(self):
return Polynomial([expo * coeff for expo, coeff in enumerate(self)][1:])
a = Polynomial([1, 2, 3, 0, 0, 6])
b = Polynomial([1, 2, 3, 1, 1, 0])
print(a, '\n', b, '\n', a + b, '\n', a * b, '\n', a.d_dx(), '\n', b.d_dx(), '\n', (a*b).d_dx())
print()
c = Polynomial([1, 1])
d = Polynomial([1, -1])
print(c, '\n', d, '\n', c + d, '\n', c * d)
output:
1 + (2)*x + (3)*x**2 + (6)*x**5
1 + (2)*x + (3)*x**2 + x**3 + x**4
2 + (4)*x + (6)*x**2 + x**3 + x**4 + (6)*x**5
1 + (4)*x + (10)*x**2 + (13)*x**3 + (12)*x**4 + (11)*x**5 + (15)*x**6 + (18)*x**7 + (6)*x**8 + (6)*x**9
2 + (6)*x + (30)*x**4
2 + (6)*x + (3)*x**2 + (4)*x**3
4 + (20)*x + (39)*x**2 + (48)*x**3 + (55)*x**4 + (90)*x**5 + (126)*x**6 + (48)*x**7 + (54)*x**8
1 + x
1 + (-1)*x
2
1 + (-1)*x**2
You can use a dictionary to store the result of the multiplication ,So that the exponents which are already calculated can directly be added to the previous calculated value
The following code works
def multipoly(p1,p2):
mul = dict()
for m in p1:
for n in p2:
if m[1] + n[1] in mul:
mul[m[1] + n[1]] += m[0] * n[0]
else:
mul[m[1] + n[1]] = m[0] * n[0]
m_res = []
for p, q in mul.items():
m_res.append((q, p))
return m_res
print(multipoly([(1,1),(-1,0)],[(1,2),(1,1),(1,0)]))
It takes less than your solution. Because in your solution you are removing an element in p2 which takes O(sizeof(p2)) time.
Yet another way. Using itertools groupby to combine similar terms:
from itertools import groupby
def multipoly(poly1,poly2):
#multiply two polynolials
temp = [(p1[0]*p2[0], p1[1]+p2[1]) for p1 in poly1 for p2 in poly2]
#sort to use for groupby
temp = sorted(temp, key= lambda x: x[1])
#groupby second term
g = groupby(temp, lambda x: x[1])
#combine terms
result = []
for k,v in g:
result.append((sum([i[0] for i in v]), k))
result.sort(key=lambda x: -x[1])
return result
If you simply want a function to multiply two polynomials, represented as a list of tuples [(coef, expn) ...] you can start by multiplying term by term the two polynomials p1, p2 like this
p3 = [(c1*c2, e1+e2) for c1, e1 in p1 for c2, e2 in p2]
but you have a problem because, in general, you will have more than one term with the same exponent, to normalize the result in p3 we can use a dictionary
d = {}
for c, e in p3:
d[e] = d.get(e, 0) + c
note that d.get(e, 0) returns d[e] if the exponent is already present in d or returns 0.
Finally, you want back your results as a list of tuples
p3 = [(c, e) for e, c in d.items()]
but this list is not guaranteed to be sorted in order of decreasing exponent
p3 = sorted(p3, key=lambda t: -t[1])
It is possible to put all this in a single callable
def pmult(p1, p2):
d = {}
for coef, expn in [(c1*c2, e1+e2) for c1, e1 in p1 for c2, e2 in p2]:
d[expn] = d.get(expn,0)+coef
return sorted([(c, e) for e, c in d.items()], key=lambda t: -t[1])
A test:
In [25]: a = [(1,2),(3,0)]
In [26]: b = [(1,4),(2,3),(3,2),(4,1),(5,0)]
In [27]: def pmult(p1, p2):
...: d = {}
...: for coef, expn in [(c1*c2, e1+e2) for c1, e1 in p1 for c2, e2 in p2]:
...: d[expn] = d.get(expn,0)+coef
...: return sorted([(c, e) for e, c in d.items()], key=lambda t: -t[1])
In [28]: pmult(a, b)
Out[28]: [(1, 6), (2, 5), (6, 4), (10, 3), (14, 2), (12, 1), (15, 0)]
pow(a,b,c) operator in python returns (a**b)%c . If I have values of b, c, and the result of this operation (res=pow(a,b,c)), how can I find the value of a?
Despite the statements in the comments this is not the discrete logarithm problem. This more closely resembles the RSA problem in which c is the product of two large primes, b is the encrypt exponent, and a is the unknown plaintext. I always like to make x the unknown variable you want to solve for, so you have y= xb mod c where y, b, and c are known, you want to solve for x. Solving it involves the same basic number theory as in RSA, namely you must compute z=b-1 mod λ(c), and then you can solve for x via x = yz mod c. λ is Carmichael's lambda function, but you can also use Euler's phi (totient) function instead. We have reduced the original problem to computing an inverse mod λ(c). This is easy to do if c is easy to factor or we already know the factorization of c, and hard otherwise. If c is small then brute-force is an acceptable technique and you can ignore all the complicated math.
Here is some code showing these steps:
import functools
import math
def egcd(a, b):
"""Extended gcd of a and b. Returns (d, x, y) such that
d = a*x + b*y where d is the greatest common divisor of a and b."""
x0, x1, y0, y1 = 1, 0, 0, 1
while b != 0:
q, a, b = a // b, b, a % b
x0, x1 = x1, x0 - q * x1
y0, y1 = y1, y0 - q * y1
return a, x0, y0
def inverse(a, n):
"""Returns the inverse x of a mod n, i.e. x*a = 1 mod n. Raises a
ZeroDivisionError if gcd(a,n) != 1."""
d, a_inv, n_inv = egcd(a, n)
if d != 1:
raise ZeroDivisionError('{} is not coprime to {}'.format(a, n))
else:
return a_inv % n
def lcm(*x):
"""
Returns the least common multiple of its arguments. At least two arguments must be
supplied.
:param x:
:return:
"""
if not x or len(x) < 2:
raise ValueError("at least two arguments must be supplied to lcm")
lcm_of_2 = lambda x, y: (x * y) // math.gcd(x, y)
return functools.reduce(lcm_of_2, x)
def carmichael_pp(p, e):
phi = pow(p, e - 1) * (p - 1)
if (p % 2 == 1) or (e >= 2):
return phi
else:
return phi // 2
def carmichael_lambda(pp):
"""
pp is a sequence representing the unique prime-power factorization of the
integer whose Carmichael function is to be computed.
:param pp: the prime-power factorization, a sequence of pairs (p,e) where p is prime and e>=1.
:return: Carmichael's function result
"""
return lcm(*[carmichael_pp(p, e) for p, e in pp])
a = 182989423414314437
b = 112388918933488834121
c = 128391911110189182102909037 * 256
y = pow(a, b, c)
lam = carmichael_lambda([(2,8), (128391911110189182102909037, 1)])
z = inverse(b, lam)
x = pow(y, z, c)
print(x)
The best you can do is something like this:
a = 12
b = 5
c = 125
def is_int(a):
return a - int(a) <= 1e-5
# ============= Without C ========== #
print("Process without c")
rslt = pow(a, b)
print("a**b:", rslt)
print("a:", pow(rslt, (1.0 / b)))
# ============= With C ========== #
print("\nProcess with c")
rslt = pow(a, b, c)
i = 0
while True:
a = pow(rslt + i*c, (1.0 / b))
if is_int(a):
break
else:
i += 1
print("a**b % c:", rslt)
print("a:", a)
You can never be sure that you have found the correct modulo value, it is the first value that is compatible with your settings. The algorithm is based on the fact that a, b and c are integers. If they are not you have no solution a likely combination that was the original one.
Outputs:
Process without c
a**b: 248832
a: 12.000000000000002
Process with c
a**b % c: 82
a: 12.000000000000002
I want to create something like this programmatically:
a = (_vec, T.set_subtensor(_vec[0], _init[0]))[1]
b = (a, T.set_subtensor( a[1], a[0] * 2))[1]
c = (b, T.set_subtensor( b[2], b[1] * 2))[1]
vec_update = (c, T.set_subtensor(c[3], c[2] * 2))
test_vector = function([], outputs=vec_update)
subt = test_vector()
We got a = (_vec, T.set_subtensor(_vec[0], _init[0]))[1] so a is that whole statement. This is not doing anything yet. Then there is b = (a, T.set_subtensor( a[1], a[0] * 2))[1] which is depending on a and is another statement itself.This goes on until vec_update. I know it looks ugly but it just updates the column of a vector like col[n] = col[n-1] * 2 for col[0] = 1 returning a vector looking like this:
[[ 1. 2. 4. ..., 32. 64. 128.]]
Now Imagine I would want to do this a thousand times.. therefore I am wondering if I could generate such statements since they follow an easy pattern.
These "concatenated" statements are not evaluated until
test_vector = function([], outputs=vec_update)
which is when they are getting compiled to CUDA-code and
subt = test_vector()
does execute everything.
You can use function nesting:
def nest(f, g):
def h(x):
return f(g(x), x)
return h
expr = lambda (a,b) : a
expr = nest((lambda x, (a, b): x + (a - b)), expr)
expr = nest((lambda x, (a, b): x + (a - b)), expr)
print expr((1,2)) # prints -1
Regarding the example code, you could do something like (modifying nest to use no arguments):
def nest(f, g):
def h():
return f(g())
return h
expr = lambda: (_vec, _init)[1]
expr = nest(lambda x: T.set_subtensor(x[1], x[0] * 2)[1], expr)
expr = nest(lambda x: T.set_subtensor(x[2], x[1] * 2)[1], expr)
expr = nest(lambda x: T.set_subtensor(x[3], x[2] * 2)[1], expr)
expr = nest(lambda x: T.set_subtensor(x[4], x[3] * 2)[1], expr)
test_vector = function([], outputs=expr)
subt = test_vector()