Error message #227
Replies: 8 comments 38 replies
-
My first guess is that your EoMs or their Jacobian returns invalid values. You can manually check whether those evaluate before you call solve(). |
Beta Was this translation helpful? Give feedback.
-
I am 69 1/2 - by the time I'll be 75 I may be o.k....
and got these resulst;
does this look o.k.? |
Beta Was this translation helpful? Give feedback.
-
Let me clean up the code and send it tomorrow morning. So, I set up two Problems: My hope is, that by iterating this it will converge to optimal strategies phi and phsi. In which form would you like the code? |
Beta Was this translation helpful? Give feedback.
-
Below is the program. # %%
"""
War of Attrition and Attack
===========================
Two players, called :math:`\phi` and :math:`\psi`, have weapons of quantity
$:math`x_1` and :math:`x_2`, respectively. They may use them to either destroy
the other player's weapons or to attack the other player. They employ strategfies
:math:`\phi(t)` and :math:`\psi(t)` with :maht:`0 \leq \phi(t), \psi(t) \leq 1`.
The amount of weapons left is governed by:
:math:`\dot{x}_1 = m_1 - c_1 \psi(t) x_2`
:math:`\dot{x}_2 = m_2 - c_2 \phi(t) x_1`
The pay off is:
:math:` P(x, \psi, \phi) = \int_0^T (1 - \psi(t)) x_2 - (1 - \phi(t)) x_1 dt`
Player :math:`\phi` wants to maximize the payoff and player :math:`\psi` wants to
minimize it.
The idea comes from the book Differential Games by Avner Friedman, page 26.
The idea is this: player :math:`\phi` wants to minimize P(..), so this will be
his objective function and the oppent's strategie :math:`psi` enters as a
known_trajectory_map. Player :math:`\psi` wants to maximize P(..), so his
objective function will be -P(..) and the opponent's strategie :math:`\phi`
enters as a known_trajectory_map.
By iterating a few times maybe the strategies will converge to a solution.
/AS per the book, there is a solution, but it is discontinuous
"""
# %%
# Here I simply integrate the eoms, just to see what they may look like
#
# %%
import sympy as sm
import numpy as np
import sympy.physics.mechanics as me
import matplotlib.pyplot as plt
from scipy.integrate import solve_ivp
print('Sympy version: ', sm.__version__)
from opty import Problem
m1, m2, c1, c2, psi, phi = sm.symbols('m1 m2 c1 c2 psi phi')
par_map = {
m1: 1,
m2: 1,
c1: 1.,
c2: 1.,
psi: 0.25,
phi: 0.255,
}
def gradient(t, x, args):
A = args[0] - args[2] * args[4] * x[1]
B = args[1] - args[3] * args[5] * x[0]
return np.array([A, B])
t0, tf = 0, 10
num_nodes = 100
times = np.linspace(t0, tf, num_nodes)
t_span = (t0, tf)
x0 = np.array([10, 10])
pL_vals = [par_map[i] for i in par_map.keys()]
resultat1 = solve_ivp(gradient, t_span, x0, t_eval = times, args=(pL_vals,)) #, method='Radau')
resultat = resultat1.y.T
print('Shape of result: ', resultat.shape)
event_dict = {-1: 'Integration failed', 0: 'Integration finished successfully', 1: 'some termination event'}
print(event_dict[resultat1.status], ' the message is: ', resultat1.message)
fig, ax = plt.subplots()
plt.plot(times, resultat[:, 0], label='x1')
plt.plot(times, resultat[:, 1], label='x2')
plt.xlabel('Time')
ax.legend();
plt.show()
# %%
# Set up the Optimization Problem.
# --------------------------------
#
x1, x2, ux1, ux2 = me.dynamicsymbols('x1 x2 ux1 ux2')#
psi, phi = sm.symbols('psi phi', cls=sm.Function)
m1, m2, c1, c2 = sm.symbols('m1 m2 c1 c2')
t = me.dynamicsymbols._t
t0, tf = 0, 10
num_nodes = 50
eom = sm.Matrix([ux1 - (m1 - c1 * psi(t) * x2), ux2 - (m2 - c2 * phi(t) * x1)])
instance_constraints = (
x1.subs({t: t0}) - 10,
x2.subs({t: t0}) - 10,
)
constraints = eom.col_join(sm.Matrix(instance_constraints))
jakob = constraints.jacobian([x1, x2 ,ux1, ux2] + [phi(t), psi(t)])
par_map = {
m1: 2,
m2: 2,
c1: 1.,
c2: 1,
}
state_symbols = [x1, x2, ux1, ux2]
constant_symbols = [m1, m2, c1, c2]
interval_value = (tf - t0) / (num_nodes - 1)
"""
objective_phi = sm.Integral(((1 - psi(t))*x2 - (1 - phi(t))*x1), t)
objective_psi = -objective_phi
"""
phi_dict = {phi(t): np.ones(num_nodes)*0.25}
psi_dict = {psi(t): np.ones(num_nodes)*0.25}
initial_guess_phi = np.random.randn(5*num_nodes) * 1
initial_guess_psi = np.random.randn(5*num_nodes) * 1
def obj_phi(free):
h1 = -interval_value * np.sum([(1 - free[4*num_nodes+i])*free[i] for i in range(num_nodes)])
h2 = interval_value * np.sum([(1 - psi_dict[psi(t)][i])*free[num_nodes+i] for i in range(num_nodes)])
return h1 + h2
def obj_psi(free):
h1 = interval_value * np.sum([(1 - phi_dict[phi(t)][i])*free[i] for i in range(num_nodes)])
h2 = -interval_value * np.sum([(1 - free[4*num_nodes+i])*free[num_nodes+i] for i in range(num_nodes)])
return h1 + h2
def obj_grad_phi(free):
grad = np.zeros_like(free)
grad[:num_nodes] = -interval_value * (1 - free[4*num_nodes:])
grad[num_nodes:2*num_nodes] = interval_value * (1 - psi_dict[psi(t)])
return grad
def obj_grad_psi(free):
grad = np.zeros_like(free)
grad[: num_nodes] = interval_value * (1 - phi_dict[phi(t)])
grad[num_nodes:2*num_nodes] = -interval_value * (1 - free[4*num_nodes:])
return grad
instance_constraints = (
x1.subs({t: t0}) - 10,
x2.subs({t: t0}) - 10,
)
constraints = eom.col_join(sm.Matrix(instance_constraints))
jakob = constraints.jacobian(state_symbols + [phi(t), psi(t)])
bound_phi = {phi(t): (0, 1)}
bound_psi = {psi(t): (0, 1)}
problem_psi = Problem(
obj_psi,
obj_grad_psi,
eom,
state_symbols,
num_nodes,
interval_value,
known_parameter_map=par_map,
known_trajectory_map=phi_dict,
instance_constraints=instance_constraints,
bounds=bound_psi,
time_symbol=me.dynamicsymbols._t,
)
print('psi finished')
problem_phi = Problem(
obj_phi,
obj_grad_phi,
eom,
state_symbols,
num_nodes,
interval_value,
known_parameter_map=par_map,
known_trajectory_map=psi_dict,
instance_constraints=instance_constraints,
bounds=bound_phi,
time_symbol=me.dynamicsymbols._t,
)
print('phi finished')
jakob = problem_phi.jacobian(initial_guess_phi)
print('max entry in jakob', np.max(jakob))
print('min entry in jakob', np.min(jakob))
print('len(jakob)', len(jakob))
print('jakob:', '\n')
print(jakob)
# %%
# Solve the Optimization Problem.
# -------------------------------
for i in range(1):
solution_phi, info = problem_phi.solve(initial_guess_phi)
print(info['status_msg'])
problem_phi.plot_objective_value()
initial_guess_phi = solution_phi
phi_dict = {phi(t): solution_phi[4*num_nodes :]}
print(i, 'phi')
solution_psi, info = problem_psi.solve(initial_guess_psi)
print(info['status_msg'])
problem_psi.plot_objective_value
psi_dict = {psi(t): solution_psi[4*num_nodes :]}
initial_guess_psi = solution_psi
print(i, 'psi') |
Beta Was this translation helpful? Give feedback.
-
Enough to keep me going for a while! |
Beta Was this translation helpful? Give feedback.
-
You can open an issue about this to request a better error message if the user does not pass in differential algebraic equations. We could have some kind of input check. |
Beta Was this translation helpful? Give feedback.
-
I may have found a simple way of checking:
almost too simple to be true... |
Beta Was this translation helpful? Give feedback.
-
A check for algebraic equations of motion was added to opty. |
Beta Was this translation helpful? Give feedback.
-
I am trying to model a differential game. (War of Attrition and Pursuit)
I have to set up the objective function and its gradient manually.
Setting up Problem seems fine, but when I run solve, I get this error message:
Would this indicate a mistake in my gradient of the objective function?
My objective function depends on a known_trajectory_map, and of course so does its gradient.
Is this allowed?
Thanks!
Beta Was this translation helpful? Give feedback.
All reactions