I'm trying to perform MCT on AES CBC. The pseudocode is documented here: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/aes/AESAVS.pdf section 6.4.2
Note that there is a mistake in the pseudocode, which is revealed here: What is missing from the AES Validation Standard Pseudocode for the Monte Carlo Tests?
By working in combination with these two references, I am able to come up with a working encryption test for the MCT. The following code shows the working encrypt module (given an initial key, iv, and plaintext as hex strings):
def monte_carlo_encrypt(key_len, initial_key, initial_iv, initial_pt):
key_array = []
iv_array = []
pt_array = []
ct_array = []
key_array.append(bytes.fromhex(initial_key))
iv_array.append(bytes.fromhex(initial_iv))
pt_array.append(bytes.fromhex(initial_pt))
for j in range(0, 1000):
if j == 0:
ct = encrypt(key_array[0], iv_array[0], pt_array[j])
ct_array.append(ct)
pt_array.append(iv_array[0])
else:
ct = encrypt(key_array[0], ct_array[j - 1], pt_array[j])
ct_array.append(ct)
pt_array.append(ct_array[j - 1])
if key_len == 128:
key_array.append(bytes(a ^ b for a, b in zip(key_array[0], ct_array[j])))
elif key_len == 256:
key_array.append(bytes(a ^ b for a, b in zip(key_array[0], ct_array[j - 1] + ct_array[j])))
iv_array.append(ct_array[-1])
pt_array.clear()
pt_array.append(ct_array[-2])
return key_array[-1], iv_array[-1], pt_array[-1], ct_array[-1]
for k in range(0, 100):
(next_key, next_iv, next_pt, next_ct) = monte_carlo_encrypt(key_len * 8,
key.hex().upper(),
iv.hex().upper(),
given_pt.hex().upper())
key = next_key
iv = next_iv
given_pt = next_pt
The above test produces the correct results, which can be tested with the standards outlined in the stackoverflow question linked above.
Now the issue comes up when I try to adapt this for decryption. According to the NIST reference, "The pseudocode for
decryption can be obtained by replacing all PT’s with CT’s and all CT’s with PT’s. "
So, I tried that, and came up with this:
def monte_carlo_decrypt(key_len, initial_key, initial_iv, initial_ct):
key_array = []
iv_array = []
pt_array = []
ct_array = []
key_array.append(bytes.fromhex(initial_key))
iv_array.append(bytes.fromhex(initial_iv))
ct_array.append(bytes.fromhex(initial_ct))
for j in range(0, 1000):
if j == 0:
pt = decrypt(key_array[0], iv_array[0], ct_array[j])
pt_array.append(pt)
ct_array.append(iv_array[0])
else:
pt = decrypt(key_array[0], pt_array[j - 1], ct_array[j])
pt_array.append(pt)
ct_array.append(pt_array[j - 1])
if key_len == 128:
key_array.append(bytes(a ^ b for a, b in zip(key_array[0], pt_array[j])))
elif key_len == 256:
key_array.append(bytes(a ^ b for a, b in zip(key_array[0], pt_array[j - 1] + pt_array[j])))
iv_array.append(pt_array[-1])
ct_array.clear()
ct_array.append(pt_array[-2])
return key_array[-1], iv_array[-1], pt_array[-1], ct_array[-1]
for k in range(0, 100):
(next_key, next_iv, next_pt, next_ct) = monte_carlo_decrypt(key_len * 8,
key.hex().upper(),
iv.hex().upper(),
given_ct.hex().upper())
key = next_key
iv = next_iv
given_ct = next_ct
But this decryption module gets the decryption wrong on the very first iteration. Given:
"iv": "9982F2D532BC341791ECC30A1FEA9A3F",
"key": "A58C28340553879F488E161CF815D104",
"ct": "349F129B75B99E845D99090B26801D12"
It should produce:
"key": "A58C28340553879F488E161CF815D104",
"iv": "9982F2D532BC341791ECC30A1FEA9A3F",
"pt": "9B2F1D63DE3809F47E40EFB885F01277",
"ct": "349F129B75B99E845D99090B26801D12"
But mine produces:
"key": "A58C28340553879F488E161CF815D104",
"iv": "9982F2D532BC341791ECC30A1FEA9A3F",
"pt": "23119C0130042FDA973D171E9E9E4921",
"ct": "349F129B75B99E845D99090B26801D12"
Does anyone see where I went wrong with my decryption implementation?
I figured out the answer. I found this reference, which was much more helpful in terms of pseudocode than the NIST reference: https://www.ipa.go.jp/security/jcmvp/jcmvp_e/documents/atr/atr01b_en.pdf section 3.4.3.2.2
Here is the working decrypt code:
def monte_carlo_decrypt(key_len, initial_key, initial_iv, initial_ct):
key_array = []
iv_array = []
pt_array = []
ct_array = []
key_array.append(bytes.fromhex(initial_key))
iv_array.append(bytes.fromhex(initial_iv))
ct_array.append(bytes.fromhex(initial_ct))
for j in range(0, 1000):
pt = decrypt(key_array[0], iv_array[j], ct_array[j])
pt_array.append(pt)
if j == 0:
tmp = ct_array[j]
ct_array.append(iv_array[j])
iv_array.append(tmp)
else:
iv_array.append(ct_array[j])
ct_array.append(pt_array[j - 1])
if key_len == 128:
key_array.append(bytes(a ^ b for a, b in zip(key_array[0], pt_array[j])))
elif key_len == 256:
key_array.append(bytes(a ^ b for a, b in zip(key_array[0], pt_array[j - 1] + pt_array[j])))
iv_array.append(pt_array[-1])
ct_array.clear()
ct_array.append(pt_array[-2])
return key_array[-1], iv_array[-1], pt_array[-1], ct_array[-1]
for k in range(0, 100):
(next_key, next_iv, next_pt, next_ct) = monte_carlo_encrypt(key_len * 8,
key.hex().upper(),
iv.hex().upper(),
given_pt.hex().upper())
key = next_key
iv = next_iv
given_pt = next_pt
Related
This is the code I tried
fun printsl([], k) = true
| printsl(h::t) = if k > h then print(h) andalso printsl(t);
But when I run the code, i get the following error
= stdIn:4.68-7.8 Error: syntax error: deleting SEMICOLON ID
stdIn:8.1 Error: syntax error found at EOF
The goal of the function is to print any number in the list that is less than the value k
A few things wrong here. Let's start with your function signature.
On the first line, your function takes 2 parameters, an empty list and whatever the type of k is (it is not important yet). Then on the second line, the function takes just one parameter, a non-empty list.
The two lines should match to look like:
fun printsl([], k) = ...
| printsl(h::t, k) = ...
Now let's think about the use of andalso. andalso is an operator which takes two booleans and returns a bool. It can be considered to have the signature bool * bool -> bool.
Your usage print(h) andalso printsl(t) does not match this signature.
The type of print is string -> unit, so the type of print(h) is unit (assuming h to be a string). As such, the usage of andalso is incorrect as the types on each side are not bools.
Instead of using andalso, we can simply execute both statements (print(h); printsl(t, k)). Sequences like this are expressions which return the last value. That is to say (x; y; z) returns z.
fun printsl([], k) = true
| printsl(h::t, k) = if h < k then (print(h); printsl(t, k));
However, this is still broken as the if-else construct in SML is an expression and must have a matching else, so you could use either of the following:
fun printsl([], k) = true
| printsl(h::t, k) =
if h < k then (print(h); printsl(t))
else printsl(t, k);
fun printsl([], k) = true
| printsl(h::t, k) = (
if h < k then print(h) else ();
printsl(t, k)
);
I personally prefer the latter as it prevents repetition of printsl.
This code will compile, but the signature is wrong. As we use h directly as a parameter of print, its type is inferred to be a string. This means that the compiler determines printsl to have type string list * string -> bool, whereas we are aiming for int list * int -> bool.
This can be corrected by changing the call print(h) to print(Int.toString h), giving us:
fun printsl([], k) = true
| printsl(h::t, k) = (
if h < k then print(Int.toString h) else ();
printsl(t, k)
);
This is now a function which will print all values in the given list which are less than k, but it always returns true. This provides no extra information so I would be inclined to change the signature to int list * int -> unit, giving us (finally):
fun printsl([], k) = ()
| printsl(h::t, k) = (
if h < k then print(Int.toString h) else ();
printsl(t, k)
);
This entire program could also be written in a more functional manner using List.app and List.filter.
fun printsl (xs, k) =
List.app
(fn y => print (Int.toString y))
(List.filter
(fn x => x < k)
xs);
I am trying to implement ST-HOSVD algorithm in Julia because I could not found library which contains ST-HOSVD.
See this paper in Algorithm 1 in page7.
https://people.cs.kuleuven.be/~nick.vannieuwenhoven/papers/01-STHOSVD.pdf
I cannot reproduce input (4,4,4,4) tensor by approximated tensor whose tucker rank is (2,2,2,2).
I think I have some mistake in indexes of matrix or tensor elements, but I could not locate it.
How to fix it?
If you know library of ST-HOSVD, let me know.
ST-HOSVD is really common way to reduce information. I hope the question helps many Julia user.
using TensorToolbox
function STHOSVD(A, reqrank)
N = ndims(A)
S = copy(A)
Sk = undef
Uk = []
for k = 1:N
if k == 1
Sk = tenmat(S, k)
end
Sk_svd = svd(Sk)
U1 = Sk_svd.U[ :, 1:reqrank[k] ]
V1t = Sk_svd.V[1:reqrank[k], : ]
Sigma1 = diagm( Sk_svd.S[1:reqrank[k]] )
Sk = Sigma1 * V1t
push!(Uk, U1)
end
X = ttm(Sk, Uk[1], 1)
for k=2:N
X = ttm(X, Uk[k], k)
end
return X
end
A = rand(4,4,4,4)
X = X_STHOSVD(A, [2,2,2,2])
EDIT
Here, Sk = tenmat(S, k) is mode n matricization of tensor S.
S∈R^{I_1×I_2×…×I_N}, S_k∈R^{I_k×(Π_{m≠k}^{N} I_m)}
The function is contained in TensorToolbox.jl. See "Basis" in Readme.
The definition of mode-k Matricization can be seen the paper in page 460.
It works.
I have seen 26 page in this slide
using TensorToolbox
using LinearAlgebra
using Arpack
function STHOSVD(T, reqrank)
N = ndims(T)
tensor_shape = size(T)
for i = 1 : N
T_i = tenmat(T, i)
if reqrank[i] == tensor_shape[i]
USV = svd(T_i)
else
USV = svds(T_i; nsv=reqrank[i] )[1]
end
T = ttm( T, USV.U * USV.U', i)
end
return T
end
Is there any module in Erlang to find the BFS and parent-BFS sequence of a graph?
For example,
for the Graph [[0,7,0,0,1],[7,0,6,0,5],[0,6,0,2,3],[0,0,2,0,4],[1,5,3,4,0]]:
So the result should be :
the BFS sequence is [1,5,2,3,4] for root 1 and parent-BFS sequence should be [0,1,5,5,1]
The data structure I am using is a list of lists to store the graph. And the result is also expected to be in a list(However, this is flexible)
I already have written the code for parent-BFS sequence as follows:
-module(prog).
-export([main/0,createlist/2,createlistbool/2,dense/5,populate/5,bfs/4]).
createlist(L,0) ->
L;
createlist(L,Sz) ->
List = lists:append(L,[0]),
createlist(List,Sz-1).
createlistbool(L,0) ->
L;
createlistbool(L,Sz) ->
List = lists:append(L,[false]),
createlistbool(List,Sz-1).
dense(_,_,0,Q,_) ->
Q;
dense(X,L,N,Q,Viz) ->
Child = lists:nth(N,L),
case ( Child =/= 0 ) of
true ->
case ( lists:nth(N, Viz) == false ) of
true -> Qu = queue:in({N,X},Q);
false -> Qu = Q
end;
false -> Qu = Q
end,
dense(X,L,N-1,Qu,Viz).
populate(_,_,Ans,_,0) ->
Ans;
populate(Graph,Q,Ans,Viz,F) ->
case ( queue:is_empty(Q) == false ) of
true -> {X,Y} = queue:get(Q),
Que = queue:drop(Q),
case ( lists:nth(X,Viz) == false) of
true ->
Answer = lists:sublist(Ans,X-1) ++ [Y] ++ lists:nthtail(X,Ans),
Vizible = lists:sublist(Viz,X-1) ++ [true] ++ lists:nthtail(X,Viz);
false ->
Answer = Ans, Vizible = Viz
end,
Flag = F,
C = lists:nth(X,Graph),
Qu = dense(X,C,length(Graph),Que,Vizible);
false ->
Answer = Ans, Vizible = Viz, Flag = 0, Qu = Q
end,
populate(Graph,Qu,Answer,Vizible,Flag).
bfs(Graph,Node,Ans,Viz) ->
Q = queue:new(),
Qu = queue:in({Node,0},Q),
Answer = populate(Graph,Qu,Ans,Viz,1),
Answer.
main() ->
% your code goes here
N = 5,
Graph = [[0,7,0,0,1],[7,0,6,0,5],[0,6,0,2,3],[0,0,2,0,4],[1,5,3,4,0]],
Viz = createlistbool([],N),
Ans = createlist([],N),
Root = 1,
Answer = bfs(Graph,Root,Ans,Viz),
Answer.
However, I am looking for if there exists any module that performs the same?
I was trying to write a least time control code, using drake toolbox. But in the middle, I cannot understand the error info: (please ignore things happened in this parentheis, i just don't know how much detail is needed to submit the post, god!)
'''python
from pydrake.all import MathematicalProgram, Solve
import numpy as np
def g(x):
if abs(x)<1e-7:
return 0.
else:
return 1.
mp = MathematicalProgram()
state_initial = np.asarray([1., 0])
position_goal = np.asarray([0, 0])
N=100
dt=0.01
u_over_time=mp.NewContinuousVariables(1,"u_0")
states_over_time = np.asarray([state_initial])
for k in range(1,N):
u = mp.NewContinuousVariables(1, "u_%d" % k)
state =mp.NewContinuousVariables(2,"state_%d" % k)
u_over_time = np.vstack((u_over_time, u))
states_over_time = np.vstack((states_over_time,state))
print "Number of decision vars", mp.num_vars()
for i in range(N-1):
state_next0 = states_over_time[i,0]+ dt*states_over_time[i,1]
state_next1 = states_over_time[i,1]+ dt*u_over_time[i]
mp.AddLinearConstraint(states_over_time[i+1,0]>=state_next0)
mp.AddLinearConstraint(states_over_time[i+1,1]>=state_next1)
mp.AddLinearConstraint(states_over_time[i+1,0]<=state_next0)
mp.AddLinearConstraint(states_over_time[i+1,1]<=state_next1)
mp.AddLinearConstraint(u_over_time[i]<=1.)
mp.AddLinearConstraint(u_over_time[i]>=-1.)
And the error info is :
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-2-be1aa565be42> in <module>()
29 state_next1 = states_over_time[i,1]+ dt*u_over_time[i]
30 mp.AddLinearConstraint(states_over_time[i+1,0]>=state_next0)
---> 31 mp.AddLinearConstraint(states_over_time[i+1,1]>=state_next1)
32 mp.AddLinearConstraint(states_over_time[i+1,0]<=state_next0)
33 mp.AddLinearConstraint(states_over_time[i+1,1]<=state_next1)
RuntimeError: You should not call `__bool__` / `__nonzero__` on `Formula`. If you are trying to make a map with `Variable`, `Expression`, or `Polynomial` as keys (and then access the map in Python), please use pydrake.common.containers.EqualToDict`.
May I know what's happening here? Thanks
----------------update line-----------------
I modified the code as you told me. Now the code now becomes:
'''python
from pydrake.all import MathematicalProgram, Solve
import numpy as np
def g(x):
if abs(x)<1e-7:
return 0.
else:
return 1.
mp = MathematicalProgram()
state_initial = np.asarray([1., 0])
position_goal = np.asarray([0, 0])
N=100
dt=0.01
u_over_time=mp.NewContinuousVariables(1,"u_0")
states_over_time = np.asarray([state_initial])
for k in range(1,N):
u = mp.NewContinuousVariables(1, "u_%d" % k)
state =mp.NewContinuousVariables(2,"state_%d" % k)
u_over_time = np.vstack((u_over_time, u))
states_over_time = np.vstack((states_over_time,state))
print "Number of decision vars", mp.num_vars()
for i in range(N-1):
state_next0 = states_over_time[i,0]+ dt*states_over_time[i,1]
state_next1 = states_over_time[i,1]+ dt*u_over_time[i,0]
mp.AddLinearConstraint(states_over_time[i+1,0]>=state_next0[0])
mp.AddLinearConstraint(states_over_time[i+1,1]>=state_next1[0])
mp.AddLinearConstraint(states_over_time[i+1,0]<=state_next0[0])
mp.AddLinearConstraint(states_over_time[i+1,1]<=state_next1[0])
mp.AddLinearConstraint(u_over_time[i,0]<=1.)
mp.AddLinearConstraint(u_over_time[i,0]>=-1.)
'''
And the error info is:
TypeError Traceback (most recent call last)
<ipython-input-7-82e68c2ebfaa> in <module>()
27 state_next0 = states_over_time[i,0]+ dt*states_over_time[i,1]
28 state_next1 = states_over_time[i,1]+ dt*u_over_time[i,0]
---> 29 mp.AddLinearConstraint(states_over_time[i+1,0]>=state_next0[0])
30 mp.AddLinearConstraint(states_over_time[i+1,1]>=state_next1[0])
31 mp.AddLinearConstraint(states_over_time[i+1,0]<=state_next0[0])
TypeError: 'float' object has no attribute '__getitem__'
What's the problem this time? Thanks.
(Btw, one of my complain is that, the error info always not that effective to give the hint of where the problem is...)
-----------------update 2nd time line--------------------
Now a similar problem happened to the g(x), the code:
'''
from pydrake.all import MathematicalProgram, Solve
import numpy as np
def g(x):
print 'x=',x
print 'x[0]=',x[0]
if x[0]*x[0]+x[1]*x[1]<1e-7: # x.dot(x)
return 0.
else:
return 1.
mp = MathematicalProgram()
state_initial = np.asarray([1., 0])
#position_goal = np.asarray([0, 0]) # already in g(x)
N=100
dt=0.01
u_over_time=mp.NewContinuousVariables(1,"u_0")
states_over_time = np.asarray([state_initial])
for k in range(1,N):
u = mp.NewContinuousVariables(1, "u_%d" % k)
state =mp.NewContinuousVariables(2,"state_%d" % k)
u_over_time = np.vstack((u_over_time, u))
states_over_time = np.vstack((states_over_time,state))
print "Number of decision vars", mp.num_vars()
for i in range(N-1):
state_next0 = states_over_time[i,0]+ dt*states_over_time[i,1]
state_next1 = states_over_time[i,1]+ dt*u_over_time[i,0]
mp.AddLinearConstraint(states_over_time[i+1,0]>=state_next0)
mp.AddLinearConstraint(states_over_time[i+1,1]>=state_next1)
mp.AddLinearConstraint(states_over_time[i+1,0]<=state_next0)
mp.AddLinearConstraint(states_over_time[i+1,1]<=state_next1)
mp.AddLinearConstraint(u_over_time[i,0]<=1.)
mp.AddLinearConstraint(u_over_time[i,0]>=-1.)
reward=np.zeros((N,1))
for i in range(N):
reward[i]=g(states_over_time[i,:])
mp.AddQuadraticCost(reward.dot(reward))
result=Solve(mp)
'''
This time neither x or x[0] could solve the problem. the output info is :
Number of decision vars 298
x= [1.0 0.0]
x[0]= 1.0
x= [Variable('state_1(0)', Continuous) Variable('state_1(1)', Continuous)]
x[0]= state_1(0)
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-8-08d1cd75397e> in <module>()
37 reward=np.zeros((N,1))
38 for i in range(N):
---> 39 reward[i]=g(states_over_time[i,:])
40
41 mp.AddQuadraticCost(reward.dot(reward))
<ipython-input-8-08d1cd75397e> in g(x)
5 print 'x=',x
6 print 'x[0]=',x[0]
----> 7 if x[0]*x[0]+x[1]*x[1]<1e-7: # x.dot(x)
8 return 0.
9 else:
RuntimeError: You should not call `__bool__` / `__nonzero__` on `Formula`. If you are trying to make a map with `Variable`, `Expression`, or `Polynomial` as keys (and then access the map in Python), please use pydrake.common.containers.EqualToDict`.
What can I do this time? Thanks
Btw, you see in the code i print x or x[0] only once, but i got two different answer? funny, isn't it? why is this?
state_next1 is not a symbolic expression, it is a numpy array of symbolic expression, so you need to do state_next1[0]. Similarly you will need to change u_over_time[i] <= 1 to u_over_time[i, 0] <= 1.
The other way to solve the problem is to compute state_next1 using u_overt_time[i, 0] instead of u_over_time[i]. After modification, the for loop in your code should be
for i in range(N-1):
state_next0 = states_over_time[i,0]+ dt*states_over_time[i,1]
state_next1 = states_over_time[i,1]+ dt*u_over_time[i, 0]
mp.AddLinearConstraint(states_over_time[i+1,0]>=state_next0)
mp.AddLinearConstraint(states_over_time[i+1,1]>=state_next1)
mp.AddLinearConstraint(states_over_time[i+1,0]<=state_next0)
mp.AddLinearConstraint(states_over_time[i+1,1]<=state_next1)
mp.AddLinearConstraint(u_over_time[i, 0]<=1.)
mp.AddLinearConstraint(u_over_time[i, 0]>=-1.)
I changed u_over_time[i] to u_over_time[i, 0] where you define state_next1.
The error thrown in the line
if x[0]*x[0]+x[1]*x[1]<1e-7: # x.dot(x)
return 0.
is because you called with AddQuadraticCost, but your cost is not quadratic. Drake tries to parse the symbolic expression as a quadratic expression, and failed. Specifically Drake fails when you check if the expression x[0] * x[0] + x[1] * x[1] < 1e-7. No quadratic cost can have this type of "if" statement.
What is the mathematical formulation of your cost? Do you really want to impose the cost as defined in your g(x) function, that if x'*x < 1e-7, then g(x) = 0, otherwise g(x) = 1? This is a pretty bad cost (it is almost constant everywhere, but have discrete jumps from 1 to 0 near the origin).
Since you want to solve a least time optimal control problem, I would suggest to change your formulation, and make dt a decision variable in your problem. Namely you will have the dynamic constraint
x[n+1] = x[n] + f(x[n], u[n]) * dt[n]
The final state constraint
x[N] = x_desired
The initial state constraint
x[0] = x_initial
And your cost function is to minimize the time
min sum_i dt[i]
Then you will have smooth cost and constraint.
Here is a piece of code that doesn't throw syntax error
from pydrake.all import MathematicalProgram, Solve
import numpy as np
def g(x):
x_squared_norm = np.power(x.reshape((2, -1)), 2)
return np.sum(x_squared_norm > 1e-7)
mp = MathematicalProgram()
state_initial = np.asarray([1., 0])
#position_goal = np.asarray([0, 0]) # already in g(x)
N=100
dt=0.01
u_over_time=mp.NewContinuousVariables(1,"u_0")
states_over_time = np.asarray([state_initial])
for k in range(1,N):
u = mp.NewContinuousVariables(1, "u_%d" % k)
state =mp.NewContinuousVariables(2,"state_%d" % k)
u_over_time = np.vstack((u_over_time, u))
states_over_time = np.vstack((states_over_time,state))
print "Number of decision vars", mp.num_vars()
for i in range(N-1):
state_next0 = states_over_time[i,0]+ dt*states_over_time[i,1]
state_next1 = states_over_time[i,1]+ dt*u_over_time[i,0]
mp.AddLinearConstraint(states_over_time[i+1,0]>=state_next0)
mp.AddLinearConstraint(states_over_time[i+1,1]>=state_next1)
mp.AddLinearConstraint(states_over_time[i+1,0]<=state_next0)
mp.AddLinearConstraint(states_over_time[i+1,1]<=state_next1)
mp.AddLinearConstraint(u_over_time[i,0]<=1.)
mp.AddLinearConstraint(u_over_time[i,0]>=-1.)
mp.AddCost(g, vars=states_over_time[1:,:].reshape((1, -1)).squeeze())
result=Solve(mp)
Notice that I changed the definition of g, and called mp.AddCost instead of mp.AddQuadraticCost. mp.AddQuadraticCost expects a quadratic symbolic expression. The expression in your code is not quadratic (it has an if statement in the cost, and quadratic cost doesn't allow if statement.).
This code should run without error, but I don't know if it can find the solution. Again this cost is not differentiable, so any gradient based nonlinear solver will have trouble.
If you really don't want to solve the problem as a nonlinear optimization problem, you can consider to re-formulate the problem as a mixed-integer program. Namely your cost is the summation of a bunch of binary variables b[i], that b[i] = 1 if |x[i, 0]| > epsilon or |x[i, 1]| > epsilon; otherwise b[i] = 0, and your can formulate this as a mixed-integer linear constraints.
I wrote an answer by bisection method, which also recommended by tedrake on class. but I don't like this method. Too many iterations. I just put it here, when i have a mixed integer code, i will back.
god, i just cannot pass the code check...i really hate the code check machanism of stackoverflow...
'''
from pydrake.all import MathematicalProgram, Solve
import numpy as np
import matplotlib.pyplot as plt
'''
def g(x):
print 'x=',x
print 'x[0]=',x[0]
if x[0]*x[0]+x[1]*x[1]<1e-7: # x.dot(x)
return 0.
else:
return 1.
'''
#mp = MathematicalProgram()
state_initial = np.asarray([1., 0])
#position_goal = np.asarray([0, 0]) # already in g(x)
#N=201
dt=0.01
upper=1000; lower=1;
N=upper
while upper-lower>1:
print '---------------------'
print 'N=',N
mp = MathematicalProgram()
u_over_time=mp.NewContinuousVariables(1,"u_0")
states_over_time = mp.NewContinuousVariables(2,"state intial")
mp.AddLinearConstraint(states_over_time[0]==np.asarray([state_initial[0]]))
mp.AddLinearConstraint(states_over_time[1]==np.asarray([state_initial[1]]))
#states_over_time = np.asarray([state_initial])
for k in range(1,N):
u = mp.NewContinuousVariables(1, "u_%d" % k)
state =mp.NewContinuousVariables(2,"state_%d" % k)
u_over_time = np.vstack((u_over_time, u))
states_over_time = np.vstack((states_over_time,state))
print "Number of decision vars", mp.num_vars()
for i in range(N-1):
state_next0 = states_over_time[i,0]+ dt*states_over_time[i,1]
state_next1 = states_over_time[i,1]+ dt*u_over_time[i,0]
mp.AddLinearConstraint(states_over_time[i+1,0]>=state_next0)
mp.AddLinearConstraint(states_over_time[i+1,1]>=state_next1)
mp.AddLinearConstraint(states_over_time[i+1,0]<=state_next0)
mp.AddLinearConstraint(states_over_time[i+1,1]<=state_next1)
mp.AddLinearConstraint(u_over_time[i,0]<=1.)
mp.AddLinearConstraint(u_over_time[i,0]>=-1.)
'''
reward=np.zeros((N,1))
for i in range(N):
reward[i]=g(states_over_time[i,:])
'''
mp.AddLinearConstraint(states_over_time[-1,0]<=1e-7)
mp.AddLinearConstraint(states_over_time[-1,1]<=1e-7)
mp.AddLinearConstraint(states_over_time[-1,0]>=1e-7)
mp.AddLinearConstraint(states_over_time[-1,1]>=1e-7)
#mp.AddQuadraticCost(reward.dot(reward))
result=Solve(mp)
print result.is_success()
if result.is_success():
upper=N
else:
lower=N
N=lower+int((upper-lower)/2.0)
N=upper
#print result.is_success()
print 'least time=',dt*N
u_over_time=result.GetSolution(u_over_time)
states_over_time=result.GetSolution(states_over_time)
#print 'u=',u_over_time
#print 'last state=',states_over_time[-1,:]
fig, ax = plt.subplots(2, 1)
plt.subplot(2, 1, 1);plt.plot(np.arange(dt, dt*N, dt),u_over_time);
plt.legend(["u against t"])
plt.subplot(2, 1, 2);plt.plot(states_over_time[:,0],states_over_time[:,1]);
plt.legend(["phase portrait"])
'''
I ran into an issue trying to using a dictionary whose keys are a tuple including a composite type.
Here is a minimal example to replicate my issue:
import Base: hash, isequal
type T
a :: Int
b :: Int
end
function isequal(A::(T,Int), B::(T,Int))
A[1].a == B[1].a && A[1].b == B[1].b && A[2] == B[2]
end
function hash(A::(T,Int))
hash(A[1].a + A[1].b + A[2])
end
d = Dict{(T,Int),Int}()
d[(T(1,1),1)] = 1
d[(T(2,2),2)] = 2
r = (T(2,2),2)
for k in keys(d)
println(isequal(r, k) && hash(r) == hash(k))
end
println(d[r])
Running this results in:
false
true
ERROR: key not found: (T(2,2),2)
So isequal and hash work, but for some reason the dict is not.
Does anyone know what is going on? Thank you.
There is something I don't quite understand in this case about the types of tuples and dispatching, but basically you need to implement the two argument form of hash for this case. The following very similar code works as expected, as a point of comparison, without the two argument form:
type T
a::Int
b::Int
end
function Base.isequal(A::T, B::T)
println("isequal", A, " ", B)
A.a == B.a && A.b == B.b
end
function Base.hash(A::T)
println("hash", A)
hash(A.a + A.b)
end
d = Dict{T,Int}()
d[T(1,1)] = 1
d[T(2,2)] = 2
println("test")
r = T(2,2)
println(d[r])
with output
isequalT(1,1) T(1,1)
hashT(1,1)
isequalT(2,2) T(2,2)
hashT(2,2)
test
hashT(2,2)
isequalT(2,2) T(2,2)
2
The problem can be solved by creating hash & isequal functions for each composite type rather than for the overall tuple.
If you key is (T,Int):
Instead of this:
function isequal(A::(T,Int), B::(T,Int))
A[1].a == B[1].a && A[1].b == B[1].b && A[2] == B[2]
end
function hash(A::(T,Int))
hash(A[1].a + A[1].b + A[2])
end
Do this:
function isequal(A::T, B::T)
A.a == B.a && A.b == B.b
end
function hash(A::T)
hash(A.a + A.b)
end
If you want the original formulation to work, you have to specify Base.hash with the optional second argument: h::Uint64:
function isequal(A::(T,Int), B::(T,Int))
A[1].a == B[1].a && A[1].b == B[1].b && A[2] == B[2]
end
function hash(A::(T,Int))
hash(A[1].a + A[1].b + A[2])
end
function hash(A::(T,Int), h::Uint64)
hash(A[1].a + A[1].b + A[2] + h)
end