Why is the result of trigonometric function calculation different? - numpy

I calculated three methods of the following with Numpy.
Avoiding the circle periodicity, I given the range is 0 to +180.
The calculation results of the three methods should match.
However, all calculation results are different.
Why is this?
degAry = []
sumDeg = 0
cosRad = 0
sinRad = 0
LEN = 300
RAD2DEG = 180.0 / PI # 57.2957795
for i in range(LEN):
deg = random.uniform(0,180)
rad = np.deg2rad(deg)
degAry.append(deg)
sumDeg += deg
cosRad += np.cos(rad)
sinRad += np.sin(rad)
print(np.arctan2( sinRad/LEN, cosRad/LEN ) * RAD2DEG) # 88.39325364335279
print(np.sum(degAry)/LEN) # 88.75448888951954
print(sumDeg/LEN) # 88.75448888951951

What makes you think that the mean angle and the angle of the mean vector should be the same? This is correct only for n = 1,2, for n = 3 degAry = [0, 90, 90] is easily verified to be a counter example: mean of the angles is 60 with tan = sqrt(3), mean vector is (1/3 2/3) corresponding to tan = 2.

EDIT
Mean of circular quantities
suggesting that the sin, cos approach is best.
Refactoring your code to use numpy exclusively. The two methods are different, however, the first two using RAD2DEG or the np.degrees yield the same results. The latter which used the sum of degrees divided by sample size differs.
It doesn't appear to be a summation issue (N=3000, sum in normal order, ascending then descending). They yield the same results
np.sum(deg) # 134364.25172174018
np.sum(np.sort(deg)) # 134364.25172174018
np.sum(np.sort(deg)[::-1]) # 134364.25172174018
I didn't carry it out with the summation for the cos and sin in radian form. I will leave that for others.
PI = np.pi
sumDeg = 0.
cosRad = 0.
sinRad = 0.
N = 30
RAD2DEG = 180.0 / PI # 57.2957795
deg = np.random.uniform(0, 90.0, N)
rad = np.deg2rad(deg)
sumDeg = np.sum(deg)
cosRad = np.sum(np.cos(rad))
sinRad = np.sum(np.sin(rad))
print(np.arctan2(sinRad/N, cosRad/N) * RAD2DEG)
print(np.degrees(np.arctan2(sinRad/N, cosRad/N)))
print(sumDeg/N)
Results for
> N = 1
> 22.746571717879792
> 22.746571717879792
> 22.746571717879792
>
> N= 30
> 48.99636699165551
> 48.99636699165551
> 49.000295118106884
>
> N = 300
> 44.39333460088003
> 44.39333460088003
> 44.44513528547155
>
> N = 3000
> 44.984167020219175
> 44.984167020219175
> 44.97574462726241

Related

Pulp solves multiple combinatorial problems

As the title says,
I want to solve a problem similar to the summation of multiple schemes into a fixed constant, However, when I suggest the constrained optimization model, I can't get all the basic schemes well. Part of the opinion is to add a constraint when I get a solution. However, the added constraint leads to incomplete solution and no addition leads to a dead cycle.
Here is my problem description
I have a list of benchmark data detail_list ,My goal is to select several numbers from the benchmark data list(detail_list), but not all of them, so that the sum of these data can reach the sum of the number(plan_amount) I want.
For Examle
detail_list = [50, 100, 80, 40, 120, 25],
plan_amount = 20,
The feasible schemes are:
detail_list[2]=20 can be satisfied, detail_list[1](noly 10) + detail_list[3](only 10) = plan_amount(20) , detail_list[1](only 5) + detail_list[3](only 15) = plan_amount(20) also can be satisfied, and detail_list1 + detail_list2 + detail_list3 = plan_amount(20). But you can't take four elements in the detail_list are combined, because number = 3, indicating that a maximum of three elements are allowed to be combined.
from pulp import *
num = 6 # the list max length
number_max = 3 # How many combinations can there be at most
plan_amount = 20
detail_list = [50, 100, 80, 40, 120, 25] # Basic data
plan_model = LpProblem("plan_model")
alpha = [LpVariable("alpha_{0}".format(i+1), cat="Binary") for i in range(num)]
upBound_num = [int(detail_list_money) for detail_list_money in detail_list]
num_channel = [
LpVariable("fin_money_{0}".format(i+1), lowBound=0, upBound=upBound_num[i], cat="Integer") for i
in range(num)]
plan_model += lpSum(num_channel) == plan_amount
plan_model += lpSum(alpha) <= number_max
for i in range(num):
plan_model += num_channel[i] >= alpha[i] * 5
plan_model += num_channel[i] <= alpha[i] * detail_list[i]
plan_model.writeLP("2222.lp")
test_dd = open("2222.txt", "w", encoding="utf-8")
i = 0
while True:
plan_model.solve()
if LpStatus[plan_model.status] == "Optimal":
test_dd.write(str(i + 1) + "times result\n")
for v in plan_model.variables():
test_dd.write(v.name + "=" + str(v.varValue))
test_dd.write("\n")
test_dd.write("============================\n\n")
alpha_0_num = 0
alpha_1_num = 0
for alpha_value in alpha:
if value(alpha_value) == 0:
alpha_0_num += 1
if value(alpha_value) == 1:
alpha_1_num += 1
plan_model += (lpSum(
alpha[k] for k in range(num) if value(alpha[k]) == 1)) <= alpha_1_num - 1
plan_model.writeLP("2222.lp")
i += 1
else:
break
test_dd.close()
I don't know how to change my constraints to achieve this goal. Can you help me

How to shorten this code or make it more efficient?

I want to know if there is any more efficient/shorter way to give the same result.
The function get_action_strength(action) returns a boolean if the key is pressed,
Thanks.
var degValue = 0
if (Input.get_action_strength("move_forward")):
degValue = 0
if (Input.get_action_strength("move_right")):
degValue += -45
if (Input.get_action_strength("move_left")):
degValue += 45
elif (Input.get_action_strength("move_backward")):
degValue = 180
if (Input.get_action_strength("move_right")):
degValue -= -45
if (Input.get_action_strength("move_left")):
degValue -= 45
else:
if (Input.get_action_strength("move_right")):
degValue = -90
if (Input.get_action_strength("move_left")):
degValue = 90
The function get_action_strength(action) returns a boolean if the key is pressed
No, it doesn't. get_action_strength returns float. You can use that to your advantage.
You can do this:
var x = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
var y = Input.get_action_strength("move_forward") - Input.get_action_strength("move_backward")
Furthermore, atan2 will return 0 if the parameters are 0. That is one of the benefit of using atan2 instead of atan: You don't have to worry about a division by 0. Thus, you don't need to check if x and y are not 0, just use them.
By the way, y comes before x in atan2.
One more thing, there is a rad2deg function, if you have radians and want degrees:
var x = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
var y = Input.get_action_strength("move_forward") - Input.get_action_strength("move_backward")
var degValue = rad2deg(atan2(y, x))
If you really want, you can inline the variables, and it would be a one-liner.
Ah, sorry, I may have misunderstood. You want it to be discrete, right? You want ceil:
var x = ceil(Input.get_action_strength("move_right")) - ceil(Input.get_action_strength("move_left"))
var y = ceil(Input.get_action_strength("move_forward")) - ceil(Input.get_action_strength("move_backward"))
var degValue = rad2deg(atan2(y, x))
Second branch of if's can be changed to smth like that:
degValue += -45 * int(Input.get_action_strength("move_right")) + 45 * int(Input.get_action_strength("move_left"))
When the value is False and you convert it to int, it becomes 0, and the multiply result is 0. So only one of the values is added.
Also, if the question is tagged 'python', why are you declaring variable with 'var' keyword? =)
You can use vectors and compute the angle from its components:
motion_vec_x = 0
motion_vec_y = 0
if (Input.get_action_strength("move_forward")):
motion_vec_y = 1
if (Input.get_action_strength("move_backward")):
motion_vec_y = -1
if (Input.get_action_strength("move_left")):
motion_vec_x = -1
if (Input.get_action_strength("move_right")):
motion_vec_x = 1
degValue = None
if abs(motion_vec_x) > 0 or abs(motion_vec_y) > 0:
degValue = np.arctan2(motion_vec_x, motion_vec_y) / np.pi * 180
print(degValue
This will yield (depending on the arctan2 implementation) 0° for up, negative degrees for a vector tilted to the left and positive values for the vector tilted to the right. Pointing straight down is going to be 180°. You will easily be able to convert this to any angle values you need and deem fit.

RGB to HSV in numpy

I'm trying to implement RGB to HSV conversion from opencv in pure numpy using formula from here:
def rgb2hsv_opencv(img_rgb):
img_hsv = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2HSV)
return img_hsv
def rgb2hsv_np(img_rgb):
assert img_rgb.dtype == np.float32
height, width, c = img_rgb.shape
r, g, b = img_rgb[:,:,0], img_rgb[:,:,1], img_rgb[:,:,2]
t = np.min(img_rgb, axis=-1)
v = np.max(img_rgb, axis=-1)
s = (v - t) / (v + 1e-6)
s[v==0] = 0
# v==r
hr = 60 * (g - b) / (v - t + 1e-6)
# v==g
hg = 120 + 60 * (b - r) / (v - t + 1e-6)
# v==b
hb = 240 + 60 * (r - g) / (v - t + 1e-6)
h = np.zeros((height, width), np.float32)
h = h.flatten()
hr = hr.flatten()
hg = hg.flatten()
hb = hb.flatten()
h[(v==r).flatten()] = hr[(v==r).flatten()]
h[(v==g).flatten()] = hg[(v==g).flatten()]
h[(v==b).flatten()] = hb[(v==b).flatten()]
h[h<0] += 360
h = h.reshape((height, width))
img_hsv = np.stack([h, s, v], axis=-1)
return img_hsv
img_bgr = cv2.imread('00000.png')
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
img_rgb = img_rgb / 255.0
img_rgb = img_rgb.astype(np.float32)
img_hsv1 = rgb2hsv_np(img_rgb)
img_hsv2 = rgb2hsv_opencv(img_rgb)
print('max diff:', np.max(np.fabs(img_hsv1 - img_hsv2)))
print('min diff:', np.min(np.fabs(img_hsv1 - img_hsv2)))
print('mean diff:', np.mean(np.fabs(img_hsv1 - img_hsv2)))
But I get big diff:
max diff: 240.0
min diff: 0.0
mean diff: 0.18085355
Do I missing something?
Also maybe it's possible to write numpy code more efficient, for example without flatten?
Also I have hard time finding original C++ code for cvtColor function, as I understand it should be actually function cvCvtColor from C code, but I can't find actual source code with formula.
From the fact that the max difference is exactly 240, I'm pretty sure that what's happening is in the case when both or either of v==r, v==g are simultaneously true alongside v==b, which gets executed last.
If you change the order from:
h[(v==r).flatten()] = hr[(v==r).flatten()]
h[(v==g).flatten()] = hg[(v==g).flatten()]
h[(v==b).flatten()] = hb[(v==b).flatten()]
To:
h[(v==r).flatten()] = hr[(v==r).flatten()]
h[(v==b).flatten()] = hb[(v==b).flatten()]
h[(v==g).flatten()] = hg[(v==g).flatten()]
The max difference may start showing up as 120, because of that added 120 in that equation. So ideally, you would want to execute these three lines in the order b->g->r. The difference should be negligible then (still noticing a max difference of 0.01~, chalking it up to some round off somewhere).
h[(v==b).flatten()] = hb[(v==b).flatten()]
h[(v==g).flatten()] = hg[(v==g).flatten()]
h[(v==r).flatten()] = hr[(v==r).flatten()]

Shifting HSV pixel values in python using Numpy

I'm trying to convert (shift) the values of every pixel in an HSV image (taken from a frame of a video).
The idea is to invert yellow and red colours into blue colour (to avoid using three threshold later in the program, when I can use just one) by inverting the red and yellow values into blue values using following equation.
(Hue + 90) % 180 (in OpenCV 3 Hue is in range [0,180])
Here's what I came up with:
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV);
H = hsv[:,:,0]
mask= [H<75 and H>128]
print("orig",hsv[mask])
hsv[mask] = ((hsv[mask]+90) % 180)
Unfortunately It doesn't work as by this approach Im selecting the whole hue channel not its pixel values
There's two different possibilities here, and I'm not sure which you want, but they're both trivial to implement. You can invert (reverse may be a better word) the hue rainbow, which you can just do by using 180 - hue. Or you can shift the color by 180 degrees by using (hue + 90) % 180 like you mention.
Reversing the colors:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
rev_h = 180 - h
rev_hsv = cv2.merge([rev_h, s, v])
rev_img = cv2.cvtColor(rev_hsv, cv2.COLOR_HSV2BGR)
Shifting the colors:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
shift_h = (h + 90) % 180
shift_hsv = cv2.merge([shift_h, s, v])
shift_img = cv2.cvtColor(shift_hsv, cv2.COLOR_HSV2BGR)
Those are the idiomatic ways to do it in OpenCV.
Now you want to do the same thing as above but only for some masked subset of pixels that meet a condition. This is not too hard to do; if you want to shift some masked pixels:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
h_mask = (h < 75) | (h > 128)
h[h_mask] = (h[h_mask] + 90) % 180
shift_hsv = cv2.merge([h, s, v])
shift_img = cv2.cvtColor(shift_hsv, cv2.COLOR_HSV2BGR)
Hue channel is uint8 type, value range is [0, 179]. Therefore, when add with a large number or a negative number, Python returns a garbage number. Here is my solution base on #alkasm color shifting code:
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(img_hsv)
shift_h = random.randint(-50, 50)
h = ((h.astype('int16') + shift_h) % 180).astype('uint8')
shift_hsv = cv2.merge([h, s, v])
For random hue, saturation, and value shifting. Shift channel base on #bill-grates:
def shift_channel(c, amount):
if amount > 0:
lim = 255 - amount
c[c >= lim] = 255
c[c < lim] += amount
elif amount < 0:
amount = -amount
lim = amount
c[c <= lim] = 0
c[c > lim] -= amount
return c
rand_h, rand_s, rand_v = 50, 50, 50
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(img_hsv)
# Random shift hue
shift_h = random.randint(-rand_h, rand_h)
h = ((h.astype('int16') + shift_h) % 180).astype('uint8')
# Random shift saturation
shift_s = random.randint(-rand_s, rand_s)
s = shift_channel(s, shift_s)
# Random shift value
shift_v = random.randint(-rand_v, rand_v)
v = shift_channel(v, shift_v)
shift_hsv = cv2.merge([h, s, v])
print(shift_h, shift_s, shift_v)
img_rgb = cv2.cvtColor(shift_hsv, cv2.COLOR_HSV2RGB)

Fastest way to create a sparse matrix of the form A.T * diag(b) * A + C?

I'm trying to optimize a piece of code that solves a large sparse nonlinear system using an interior point method. During the update step, this involves computing the Hessian matrix H, the gradient g, then solving for d in H * d = -g to get the new search direction.
The Hessian matrix has a symmetric tridiagonal structure of the form:
A.T * diag(b) * A + C
I've run line_profiler on the particular function in question:
Line # Hits Time Per Hit % Time Line Contents
==================================================
386 def _direction(n, res, M, Hsig, scale_var, grad_lnprior, z, fac):
387
388 # gradient
389 44 1241715 28220.8 3.7 g = 2 * scale_var * res - grad_lnprior + z * np.dot(M.T, 1. / n)
390
391 # hessian
392 44 3103117 70525.4 9.3 N = sparse.diags(1. / n ** 2, 0, format=FMT, dtype=DTYPE)
393 44 18814307 427597.9 56.2 H = - Hsig - z * np.dot(M.T, np.dot(N, M)) # slow!
394
395 # update direction
396 44 10329556 234762.6 30.8 d, fac = my_solver(H, -g, fac)
397
398 44 111 2.5 0.0 return d, fac
Looking at the output it's clear that constructing H is by far the most costly step - it takes considerably longer than actually solving for the new direction.
Hsig and M are both CSC sparse matrices, n is a dense vector and z is a scalar. The solver I'm using requires H to be either a CSC or CSR sparse matrix.
Here's a function that produces some toy data with the same formats, dimensions and sparseness as my real matrices:
import numpy as np
from scipy import sparse
def make_toy_data(nt=200000, nc=10):
d0 = np.random.randn(nc * (nt - 1))
d1 = np.random.randn(nc * (nt - 1))
M = sparse.diags((d0, d1), (0, nc), shape=(nc * (nt - 1), nc * nt),
format='csc', dtype=np.float64)
d0 = np.random.randn(nc * nt)
Hsig = sparse.diags(d0, 0, shape=(nc * nt, nc * nt), format='csc',
dtype=np.float64)
n = np.random.randn(nc * (nt - 1))
z = np.random.randn()
return Hsig, M, n, z
And here's my original approach for constructing H:
def original(Hsig, M, n, z):
N = sparse.diags(1. / n ** 2, 0, format='csc')
H = - Hsig - z * np.dot(M.T, np.dot(N, M)) # slow!
return H
Timing:
%timeit original(Hsig, M, n, z)
# 1 loops, best of 3: 483 ms per loop
Is there a faster way to construct this matrix?
I get close to a 4x speed-up in computing the product M.T * D * M out of the three diagonal arrays. If d0 and d1 are the main and upper diagonal of M, and d is the main diagonal of D, then the following code creates M.T * D * M directly:
def make_tridi_bis(d0, d1, d, nc=10):
d00 = d0*d0*d
d11 = d1*d1*d
d01 = d0*d1*d
len_ = d0.size
data = np.empty((3*len_ + nc,))
indices = np.empty((3*len_ + nc,), dtype=np.int)
# Fill main diagonal
data[:2*nc:2] = d00[:nc]
indices[:2*nc:2] = np.arange(nc)
data[2*nc+1:-2*nc:3] = d00[nc:] + d11[:-nc]
indices[2*nc+1:-2*nc:3] = np.arange(nc, len_)
data[-2*nc+1::2] = d11[-nc:]
indices[-2*nc+1::2] = np.arange(len_, len_ + nc)
# Fill top diagonal
data[1:2*nc:2] = d01[:nc]
indices[1:2*nc:2] = np.arange(nc, 2*nc)
data[2*nc+2:-2*nc:3] = d01[nc:]
indices[2*nc+2:-2*nc:3] = np.arange(2*nc, len_+nc)
# Fill bottom diagonal
data[2*nc:-2*nc:3] = d01[:-nc]
indices[2*nc:-2*nc:3] = np.arange(len_ - nc)
data[-2*nc::2] = d01[-nc:]
indices[-2*nc::2] = np.arange(len_ - nc ,len_)
indptr = np.empty((len_ + nc + 1,), dtype=np.int)
indptr[0] = 0
indptr[1:nc+1] = 2
indptr[nc+1:len_+1] = 3
indptr[-nc:] = 2
np.cumsum(indptr, out=indptr)
return sparse.csr_matrix((data, indices, indptr), shape=(len_+nc, len_+nc))
If your matrix M were in CSR format, you can extract d0 and d1 as d0 = M.data[::2] and d1 = M.data[1::2], I modified you toy data making routine to return those arrays as well, and here's what I get:
In [90]: np.allclose((M.T * sparse.diags(d, 0) * M).A, make_tridi_bis(d0, d1, d).A)
Out[90]: True
In [92]: %timeit make_tridi_bis(d0, d1, d)
10 loops, best of 3: 124 ms per loop
In [93]: %timeit M.T * sparse.diags(d, 0) * M
1 loops, best of 3: 501 ms per loop
The whole purpose of the above code is to take advantage of the structure of the non-zero entries. If you draw a diagram of the matrices you are multiplying together, it is relatively easy to convince yourself that the main (d_0) and top and bottom (d_1) diagonals of the resulting tridiagonal matrix are simply:
d_0 = np.zeros((len_ + nc,))
d_0[:len_] = d00
d_0[-len_:] += d11
d_1 = d01
The rest of the code in that function is simply building the tridiagonal matrix directly, as calling sparse.diags with the above data is several times slower.
I tried running your test case and had problems with the np.dot(N, M). I didn't dig into it, but I think my numpy/sparse combo (both pretty new) had problems using np.dot on sparse arrays.
But H = -Hsig - z*M.T.dot(N.dot(M)) runs just fine. This uses the sparse dot.
I haven't run a profile, but here are Ipython timings for several parts. It takes longer to generate the data than to do that double dot.
In [37]: timeit Hsig,M,n,z=make_toy_data()
1 loops, best of 3: 2 s per loop
In [38]: timeit N = sparse.diags(1. / n ** 2, 0, format='csc')
1 loops, best of 3: 377 ms per loop
In [39]: timeit H = -Hsig - z*M.T.dot(N.dot(M))
1 loops, best of 3: 1.55 s per loop
H is a
<2000000x2000000 sparse matrix of type '<type 'numpy.float64'>'
with 5999980 stored elements in Compressed Sparse Column format>