How to interpret the result of cvxopt.solvers.qp? - convex-optimization

There is no enough documentation and my math knowledge is limited.
The model
sol = solvers.qp(P=P, q=q,G=G,h=h, A=L, b=t)
pcost dcost gap pres dres
0: 6.3316e+08 6.3316e+08 7e+00 3e+00 7e-10
1: 6.3316e+08 6.3316e+08 2e+00 1e+00 3e-10
2: 6.3316e+08 6.3316e+08 2e+00 1e+00 3e-10
3: 1.3393e+10 -3.5020e+09 2e+10 9e-01 2e-10
4: 7.6898e+08 -1.7925e+10 4e+10 8e-01 2e-10
5: 2.1728e+09 -3.8363e+09 6e+09 6e-16 2e-14
6: 2.1234e+09 2.0310e+09 9e+07 2e-16 3e-16
7: 2.0908e+09 2.0899e+09 1e+06 1e-18 2e-16
8: 2.0905e+09 2.0905e+09 1e+04 7e-21 9e-17
9: 2.0905e+09 2.0905e+09 1e+02 2e-16 3e-16
Optimal solution found.
The result
{'dual infeasibility': 2.538901219845834e-16,
'dual objective': 2090476416.743256,
'dual slack': 59.256743485146764,
'gap': 95.35084344459145,
'iterations': 9,
'primal infeasibility': 2.220446049250331e-16,
'primal objective': 2090476512.0941,
'primal slack': 1.0136346108956689e-08,
'relative gap': 4.561201584523881e-08,
's': <2x1 matrix, tc='d'>,
'status': 'optimal',
'x': <2x1 matrix, tc='d'>,
'y': <1x1 matrix, tc='d'>,
'z': <2x1 matrix, tc='d'>}
How can I inteprert s,x,z which one is the result of my variable ?
If I print s and x, I always get something near to 1 and another near to 0, which seems to be infinitely incorrect.
>>> np.array(sol['x'])
>>> array([[ 9.99999990e-01],[ 1.01363461e-08]])

I think this short text from Stanford might be helpful for you. Highlighting the quoted section about the result:
Many properties about the solution can be extracted from the sol variable >
(dictionary).
In particular, the ‘status’, ‘x’, and ‘primal objective’ are probably the most >important. If status is optimal, then the latter two give the optimal solution and >its objective
value. You can access these fields as you would with a regular Python dictionary:
Also, this documentation provides a in-depth explanation. For understanding the result, please go to page 69

#full explain here
https://blog.dominodatalab.com/fitting-support-vector-machines-quadratic-programming
#full example here
import numpy as np
import pandas as pd
import cvxopt
import matplotlib
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
cvxopt.solvers.options['show_progress'] = True
if __name__ == '__main__':
x_min = 0
x_max = 5.5
y_min = 0
y_max = 2
iris = load_iris()
iris_df = pd.DataFrame(data=np.c_[iris['data'], iris['target']], columns=iris['feature_names'] + ['target'])
#Retain only 2 linearly separable classes
iris_df = iris_df[iris_df["target"].isin([0,1])]
iris_df["target"] = iris_df[["target"]].replace(0,-1)
#Select only 2 attributes
iris_df = iris_df[["petal length (cm)", "petal width (cm)", "target"]]
print(iris_df.head())
print()
X = iris_df[["petal length (cm)", "petal width (cm)"]].to_numpy()
y = iris_df[["target"]].to_numpy()
n = X.shape[0]
H = np.dot(y * X, (y * X).T)
q = np.repeat([-1.0], n)[..., None]
A = y.reshape(1, -1)
b = 0.0
G = np.negative(np.eye(n))
h = np.zeros(n)
P = cvxopt.matrix(H)
q = cvxopt.matrix(q)
G = cvxopt.matrix(G)
h = cvxopt.matrix(h)
A = cvxopt.matrix(A)
b = cvxopt.matrix(b)
solved = cvxopt.solvers.qp(P, q, G, h, A, b)
print()
alphas = np.array(solved["x"])
w = np.dot((y * alphas).T, X)[0]
S = (alphas > 1e-5).flatten()
b = np.mean(y[S] - np.dot(X[S], w.reshape(-1, 1)))
print("W:", w)
print("b:", b)
xx = np.linspace(x_min, x_max)
a = -w[0] / w[1]
yy = a * xx - (b) / w[1]
margin = 1 / np.sqrt(np.sum(w ** 2))
yy_neg = yy - np.sqrt(1 + a ** 2) * margin
yy_pos = yy + np.sqrt(1 + a ** 2) * margin
plt.figure(figsize=(8, 8))
plt.plot(xx, yy, "b-")
plt.plot(xx, yy_neg, "m--")
plt.plot(xx, yy_pos, "m--")
colors = ["steelblue", "orange"]
plt.scatter(X[:, 0],
X[:, 1],
c=y.ravel(),
alpha=0.5,
cmap=matplotlib.colors.ListedColormap(colors),
edgecolors="black")
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.title('svm line')
plt.show()

Related

How do you find outer points in a circle from a point mathematically?

Trying to find a set of points that would allow a point to seemingly connect to a circle, like the image below however there is no overlap and it lines up with the edge of the circle. Apologies if this is hard to understand it is hard to explain.
If you want something like this:
then the python code below does this.
import numpy as np
# function that calcuates the points at which the lines are tangent to the circle
def tangent_points(Point, Circle):
Rot_90 = np.array([[0, -1],
[1, 0]])
O = Circle[0]
r = Circle[1]
unit_OP = Point - O
OP = np.sqrt( unit_OP.dot(unit_OP) )
unit_OP = unit_OP / OP
a = r**2 / OP
unit_perp = Rot_90.dot(unit_OP)
b = np.sqrt(r**2 - a**2)
return O + a*unit_OP + b*unit_perp, O + a*unit_OP - b*unit_perp
# Test example
O = np.array([0,0])
r = 2
P = np.array([7,5])
Circ = (O, r)
T1, T2 = tangent_points(P, Circ)
# plotting preparations:
# prepare circle
s = np.linspace( 0 , 2 * np.pi , 150 )
xc = O[0] + r*np.cos( s )
yc = O[1] + r*np.sin( s )
# prepare tangents
s = np.linspace( 0, 1, 150)
L1 = P[:, np.newaxis]*(1-s[np.newaxis, :]) + T1[:, np.newaxis]*s[np.newaxis, :]
L2 = P[:, np.newaxis]*(1-s[np.newaxis, :]) + T2[:, np.newaxis]*s[np.newaxis, :]
# actual plotting
# setup a figure environment
figure, axes = plt.subplots()
axes.set_aspect( 1 )
# plotting circle and center
axes.plot( xc, yc )
axes.plot(O[0], O[1], 'bo')
# plotting point ouside circle
axes.plot(P[0], P[1], 'bo')
# plotting tagnetn lines
axes.plot( L1[0], L1[1] )
axes.plot( L2[0], L2[1] )
# plotting tangent points
axes.plot(T1[0], T1[1], 'ro')
axes.plot(T2[0], T2[1], 'ro')
plt.show()

Find the bisection of two 3D lines

I would like to calculate the bisection of two 3D lines which have an intersecting point. The lines are sympy lines defined by a point and a direction vector. How can I find the equation of the two lines which are the bisection of them?
Let lines are defined as A + t * dA, B + s * dB where A, B are base points and dA, dB are normalized direction vectors.
If it is guaranteed that lines have intersection, it could be found using dot product approach (adapted from skew line minimal distance algorithm):
u = A - B
b = dot(dA, dB)
if abs(b) == 1: # better check with some tolerance
lines are parallel
d = dot(dA, u)
e = dot(dB, u)
t_intersect = (b * e - d) / (1 - b * b)
P = A + t_intersect * dA
Now about bisectors:
bis1 = P + v * normalized(dA + dB)
bis2 = P + v * normalized(dA - dB)
Quick check for 2D case
k = Sqrt(1/5)
A = (3,1) dA = (-k,2k)
B = (1,1) dB = (k,2k)
u = (2,0)
b = -k^2+4k2 = 3k^2=3/5
d = -2k e = 2k
t = (b * e - d) / (1 - b * b) =
(6/5*k+2*k) / (16/25) = 16/5*k * 25/16 = 5*k
Px = 3 - 5*k^2 = 2
Py = 1 + 10k^2 = 3
normalized(dA+dB=(0,4k)) = (0,1)
normalized(dA-dB=(-2k,0)) = (-1,0)
Python implementation:
from sympy.geometry import Line3D, Point3D, intersection
# Normalize direction vectors:
def normalize(vector: list):
length = (vector[0]**2 + vector[1]**2 + vector[2]**2)**0.5
vector = [i/length for i in vector]
return vector
# Example points for creating two lines which intersect at A
A = Point3D(1, 1, 1)
B = Point3D(0, 2, 1)
l1 = Line3D(A, direction_ratio=[1, 0, 0])
l2 = Line3D(A, B)
d1 = normalize(l1.direction_ratio)
d2 = normalize(l2.direction_ratio)
p = intersection(l1, l2)[0] # Point3D of intersection between the two lines
bis1 = Line3D(p, direction_ratio=[d1[i]+d2[i] for i in range(3)])
bis2 = Line3D(p, direction_ratio=[d1[i]-d2[i] for i in range(3)])

Time-dependent events in ODE

I recently started with Julia and wanted to implement one of my usual problems - implement time-depended events.
For now I have:
# Packages
using Plots
using DifferentialEquations
# Parameters
k21 = 0.14*24
k12 = 0.06*24
ke = 1.14*24
α = 0.5
β = 0.05
η = 0.477
μ = 0.218
k1 = 0.5
V1 = 6
# Time
maxtime = 10
tspan = (0.0, maxtime)
# Dose
stim = 100
# Initial conditions
x0 = [0 0 2e11 8e11]
# Model equations
function system(dy, y, p, t)
dy[1] = k21*y[2] - (k12 + ke)*y[1]
dy[2] = k12*y[1] - k21*y[2]
dy[3] = (α - μ - η)*y[3] + β*y[4] - k1/V1*y[1]*y[3]
dy[4] = μ*y[3] - β*y[4]
end
# Events
eventtimes = [2, 5]
function condition(y, t, integrator)
t - eventtimes
end
function affect!(integrator)
x0[1] = stim
end
cb = ContinuousCallback(condition, affect!)
# Solve
prob = ODEProblem(system, x0, tspan)
sol = solve(prob, Rodas4(), callback = cb)
# Plotting
plot(sol, layout = (2, 2))
But the output that is give is not correct. More specifically, the events are not taken into account and the initial condition doesn't seems to be 0 for y1 but stim.
Any help would be greatly appreciated.
t - eventtimes doesn't work because one's a scalar and the other is a vector. But for this case, it's much easier to just use a DiscreteCallback. When you make it a DiscreteCallback you should pre-set the stop times so that to it hits 2 and 5 for the callback. Here's an example:
# Packages
using Plots
using DifferentialEquations
# Parameters
k21 = 0.14*24
k12 = 0.06*24
ke = 1.14*24
α = 0.5
β = 0.05
η = 0.477
μ = 0.218
k1 = 0.5
V1 = 6
# Time
maxtime = 10
tspan = (0.0, maxtime)
# Dose
stim = 100
# Initial conditions
x0 = [0 0 2e11 8e11]
# Model equations
function system(dy, y, p, t)
dy[1] = k21*y[2] - (k12 + ke)*y[1]
dy[2] = k12*y[1] - k21*y[2]
dy[3] = (α - μ - η)*y[3] + β*y[4] - k1/V1*y[1]*y[3]
dy[4] = μ*y[3] - β*y[4]
end
# Events
eventtimes = [2.0, 5.0]
function condition(y, t, integrator)
t ∈ eventtimes
end
function affect!(integrator)
integrator.u[1] = stim
end
cb = DiscreteCallback(condition, affect!)
# Solve
prob = ODEProblem(system, x0, tspan)
sol = solve(prob, Rodas4(), callback = cb, tstops = eventtimes)
# Plotting
plot(sol, layout = (2, 2))
This avoids rootfinding altogether so it should be a much nicer solution that hacking time choices into a rootfinding system.
Either way, notice that the affect was changed to
function affect!(integrator)
integrator.u[1] = stim
end
It needs to be modifying the current u value otherwise it won't do anything.

Super-ellipse Point Picking

https://en.wikipedia.org/wiki/Superellipse
I have read the SO questions on how to point-pick from a circle and an ellipse.
How would one uniformly select random points from the interior of a super-ellipse?
More generally, how would one uniformly select random points from the interior of the curve described by an arbitrary super-formula?
https://en.wikipedia.org/wiki/Superformula
The discarding method is not considered a solution, as it is mathematically unenlightening.
In order to sample the superellipse, let's assume without loss of generality that a = b = 1. The general case can be then obtained by rescaling the corresponding axis.
The points in the first quadrant (positive x-coordinate and positive y-coordinate) can be then parametrized as:
x = r * ( cos(t) )^(2/n)
y = r * ( sin(t) )^(2/n)
with 0 <= r <= 1 and 0 <= t <= pi/2:
Now, we need to sample in r, t so that the sampling transformed into x, y is uniform. To this end, let's calculate the Jacobian of this transform:
dx*dy = (2/n) * r * (sin(2*t)/2)^(2/n - 1) dr*dt
= (1/n) * d(r^2) * d(f(t))
Here, we see that as for the variable r, it is sufficient to sample uniformly the value of r^2 and then transform back with a square root. The dependency on t is a bit more complicated. However, with some effort, one gets
f(t) = -(n/2) * 2F1(1/n, (n-1)/n, 1 + 1/n, cos(t)^2) * cos(t)^(2/n)
where 2F1 is the hypergeometric function.
In order to obtain uniform sampling in x,y, we need now to sample uniformly the range of f(t) for t in [0, pi/2] and then find the t which corresponds to this sampled value, i.e., to solve for t the equation u = f(t) where u is a uniform random variable sampled from [f(0), f(pi/2)]. This is essentially the same method as for r, nevertheless in that case one can calculate the inverse directly.
One small issue with this approach is that the function f is not that well-behaved near zero - the infinite slope makes it quite challenging to find a root of u = f(t). To circumvent this, we can sample only the "upper part" of the first quadrant (i.e., area between lines x=y and x=0) and then obtain all the other points by symmetry (not only in the first quadrant but also for all the other ones).
An implementation of this method in Python could look like:
import numpy as np
from numpy.random import uniform, randint, seed
from scipy.optimize import brenth, ridder, bisect, newton
from scipy.special import gamma, hyp2f1
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
seed(100)
def superellipse_area(n):
#https://en.wikipedia.org/wiki/Superellipse#Mathematical_properties
inv_n = 1. / n
return 4 * ( gamma(1 + inv_n)**2 ) / gamma(1 + 2*inv_n)
def sample_superellipse(n, num_of_points = 2000):
def f(n, x):
inv_n = 1. / n
return -(n/2)*hyp2f1(inv_n, 1 - inv_n, 1 + inv_n, x)*(x**inv_n)
lb = f(n, 0.5)
ub = f(n, 0.0)
points = [None for idx in range(num_of_points)]
for idx in range(num_of_points):
r = np.sqrt(uniform())
v = uniform(lb, ub)
w = bisect(lambda w: f(n, w**n) - v, 0.0, 0.5**(1/n))
z = w**n
x = r * z**(1/n)
y = r * (1 - z)**(1/n)
if uniform(-1, 1) < 0:
y, x = x, y
x = (2*randint(0, 2) - 1)*x
y = (2*randint(0, 2) - 1)*y
points[idx] = [x, y]
return points
def plot_superellipse(ax, n, points):
coords_x = [p[0] for p in points]
coords_y = [p[1] for p in points]
ax.set_xlim(-1.25, 1.25)
ax.set_ylim(-1.25, 1.25)
ax.text(-1.1, 1, '{n:.1f}'.format(n = n), fontsize = 12)
ax.scatter(coords_x, coords_y, s = 0.6)
params = np.array([[0.5, 1], [2, 4]])
fig = plt.figure(figsize = (6, 6))
gs = gridspec.GridSpec(*params.shape, wspace = 1/32., hspace = 1/32.)
n_rows, n_cols = params.shape
for i in range(n_rows):
for j in range(n_cols):
n = params[i, j]
ax = plt.subplot(gs[i, j])
if i == n_rows-1:
ax.set_xticks([-1, 0, 1])
else:
ax.set_xticks([])
if j == 0:
ax.set_yticks([-1, 0, 1])
else:
ax.set_yticks([])
#ensure that the ellipses have similar point density
num_of_points = int(superellipse_area(n) / superellipse_area(2) * 4000)
points = sample_superellipse(n, num_of_points)
plot_superellipse(ax, n, points)
fig.savefig('fig.png')
This produces:

How to algebraically solve a system of equations?

I am not sure whether this is right place to ask. Here N, L, H, p, and d are parameters. I need to solve this system of equations. Specifically, I need to solve for b(t) and e(t).
Variables | t=1 | t>1
----------|--------|------------------------
n(t) | N |N(1-p)^(t-1)
s(t) | 1 |((1-p+dp)/(1-p))^(t-1)
b(t) | L |b(t-1)+p(H-b(t-1))
e(t) |(H-L)/2 |e(t-1)+(p(H-b(t-1)))/2
c(t) |(1-d)pN |(1-d)pN(1-p+dp)^(t-1)
Please help me how should I start this problem to solve.
Since you used a Wolfram-Mathematica tag, perhaps you intend to use Mathematica
RSolve[{b[1]==L, b[t]==b[t-1]+p(H-b[t-1]),
e[1]==(H-L)/2, e[t]==e[t-1]+p(H-b[t-1])/2}, {b[t],e[t]}, t]//FullSimplify
which returns
Solve::svars: Equations may not give solutions for all "solve" variables
{b[t]->H+(-H+L)(1-p)^(-1+t),
e[t]->((H-L)(-2+(1-p)^t+2 p))/(2(-1+p))}
It seems that these formulas give recurrent equations - you find values for t = 1 (from table), then calculate values for t = 2, then for t = 3 and so on
b(t) = b(t-1) + p * (H - b(t-1))
t = 1: L
t = 2: b(2) = b(1) + p * (H - b(1)) or
L + p * (H - L) = L + p * H - p * L
t = 3: b(3) = b(2) + p * (H - b(2))
Example: L= 2; p = 3; H = 7;
b(1) = 2
b(2) = 2 + 3 * (7 - 2) = 17
b(3) = 17 + 3 * (7 - 17) = -13

Resources