I am trying to implement an rk4 function to solve 2 differential equations. I have this code that implements the Runge Kutta 4 method:
//RK4 method
func rk4_func(y_array: [Double], f_array: [(([Double], Double) -> Double)], t_val: Double, h_val: Double) -> [Double] {
let length = y_array.count
let t_half_step = t_val + h_val / 2.0
let t_step = t_val + h_val
var k1 = [Double](repeating: 0.0, count: length)
var k2 = [Double](repeating: 0.0, count: length)
var k3 = [Double](repeating: 0.0, count: length)
var k4 = [Double](repeating: 0.0, count: length)
var w = [Double](repeating: 0.0, count: length)
var result = [Double](repeating: 0.0, count: length)
for i in 0...length {
k1[i] = h_val * f_array[i](y_array, t_val)
w[i] = y_array[i] + k1[i]/2.0
}
for i in 0...length {
k2[i] = h_val * f_array[i](w, t_half_step)
w[i] = y_array[i] + k2[i]/2.0
}
for i in 0...length {
k3[i] = h_val * f_array[i](w, t_half_step)
w[i] = y_array[i] + k3[i]
}
for i in 0...length {
k4[i] = h_val * f_array[i](w, t_step)
}
for i in 0...length {
result[i] = y_array[i] + (k1[i] + 2.0*k2[i] + 2.0*k3[i] + k4[i])/6.0
}
print(result)
return result;
}
But now I need to actually use it, which is the part I'm confused about. If anyone has experience with numerically computing solutions to differential equations, that would help.
What arrays do I need to feed this function?
What does the t_val argument represent? Is it a maximum time?
How does the output "solve" the equation?
What does the output give me?
In the line k1[i] = h_val * f_array[i](y_array, t_val), what does f_array[i](y_array, t_val) mean? Is it saying that for the i-th value of f_array, find the corresponding i-th value for y_array? Then what does the t_val mean there?
For reference, here are the 2 differential equations needed to be solved. The context is that I'm trying to numerically solve these Lotka-Volterra Models to plot a time series and a phase space plot in Xcode (Swift 3.x).
y is the vector of the current state (implemented as double array). f_array is a function pointer to a function doty = f_array(y,t).
t_val is the time for the current state, h_val is the time step.
One call of rk4_func performs the time step from t_val to t_val+h_val and
returns the new state, y_next = rk4_func(y, f_array, t, h).
One would have to study the language internals. Hopefully, that is, for the code to work correctly, the first call of f_array[0](y_array, t_val) computes the full vector/array-valued result and further calls just extract the components of the cached result.
The original code as found at https://github.com/pdemarest/swift-rk4 is severely deficient in its RK4 realization and out-of-date in language standards. A working version as tested at https://swift.sandbox.bluemix.net/ is
import Foundation
func RK4step(y: [Double], f: ([Double], Double) -> [Double], t: Double, h: Double) -> [Double] {
let length = y.count
var w = [Double](repeating: 0.0, count: length )
var result = [Double](repeating: 0.0, count: length)
let k1 = f(y,t)
assert(k1.count == y.count, "States and Derivatives must be the same length")
for i in 0..<length { w[i] = y[i] + 0.5*h*k1[i] }
let k2 = f(w, t+0.5*h)
for i in 0..<length { w[i] = y[i] + 0.5*h*k2[i] }
let k3 = f(w,t+0.5*h)
for i in 0..<length { w[i] = y[i] + h*k3[i]
}
let k4 = f(w,t+h)
for i in 0..<length {
result[i] = y[i] + (k1[i] + 2.0*k2[i] + 2.0*k3[i] + k4[i])*h/6.0
}
return result;
}
func test_exp(){
// Integrate: y' = y
// y_0 = 1.0
// from 0 to 2.0
var y = [1.0]
func deriv (y: [Double], t: Double) -> [Double] {
return [ y[0] ]
}
var t = 0.0
let h = 0.1
while t < 2.0 {
y = RK4step(y:y, f:deriv, t:t, h:h)
t += h
print("t: \(t), y: \(y[0]) exact: \(exp(t))\n")
}
let exact = exp(2.0)
let error = abs(y[0] - exact)
assert(error < pow(h, 4.0))
print("y: \(y[0]) exact: \(exact) error: \(error)\n")
}
print("testing...\n")
test_exp()
For the Volterra-Lotka dynamics one would have to change
var y = [150.0, 5.0]
let a = 5.0
let b = 1.0
let eps = 0.1
let m = 5.0
func deriv (y: [Double], t: Double) -> [Double] {
let p = y[0]
let q = y[1]
return [ a*p-b*p*q, eps*b*p*q - m*q ]
}
with properly fixed global constants a,b,eps,m and a two-dimensional initial value. Add print statements where required.
Related
I'm trying to implemenet an assignment problem. I have the following problem when trying to multiply two variables in linear programming (using glpk gusek) in my goal function:
minimize PATH_COST: sum{k in Rodzaj_Transportu}(sum{z in numery_Zlecen}Koszty_Suma[k,z])*y[k,z]; #y is a binary variable; Koszty_Suma is total cost for ordez z and car type k
The following error is arising: "model.mod:47: multiplication of linear forms not allowed".
Code (.dat file):
data;
set numery_Zlecen := 1, 2, 3; #order numbers
set Miasta := '*some data: *' #cities.
#order numer (from city to city)
set Zlecenie[1] := Warszawa Paris;
set Zlecenie[2] := Berlin Praha;
set Zlecenie[3] := Praha Amsterdam;
#number of packages for transport for a particular order
param Ilosc_Wyrobow :=
1 10
2 50
3 110;
param Godziny_Pracy := 9; #number of working hours during the day
param Pojemnosc_Samochodu := 35; #capacity of the car (how many packages it can take)
param Srednia_Predkosc := 80; #average car speed
param Spalenie_Paliwa := 0.25; #fuel combustion
param Wynagrodzenie_za_Godzine := 20; #salary for one working hour
param Cena_Noclegu := 100; #price of accommodation
param Dystans: '*some data: *' #km between cities.
param Koszt_Paliwa : '*some data: *' #fuel consumption depends on country.
end;
Code (.mod file):
#INDEXY
#=====================================================================
set Miasta; #i,j
set numery_Zlecen; #z
set Zlecenie{numery_Zlecen} dimen 2; #p,q
set Rodzaj_Transportu; #k
#PARAMETRY
#=====================================================================
param Dystans {Miasta,Miasta};
param Ilosc_Wyrobow{numery_Zlecen};
param Godziny_Pracy >= 0;
param Pojemnosc_Samochodu {Rodzaj_Transportu}>= 0;
param Srednia_Predkosc >=0;
param Spalenie_Paliwa >=0;
param Koszt_Paliwa {Miasta,Miasta};
param Wynagrodzenie_za_Godzine >= 0;
param Cena_Noclegu >= 0;
#ZMIENE
#=====================================================================
var x{Miasta,Miasta,numery_Zlecen} <= 1, >= 0; #variable x equal 1 when we're going the path from city A to city B; otherwise it equals 0
var y{Rodzaj_Transportu,numery_Zlecen} binary <=1, >=0; #variable that shows what types of car/s we are using for order (can be 0 or 1)
var Koszty_Suma{Rodzaj_Transportu,numery_Zlecen}; #total costs
var Koszty_Transportu{numery_Zlecen}; #transport costs
var Koszty_Odpoczynku{numery_Zlecen}; #rest costs
var Koszty_Wynagrodzenia{numery_Zlecen}; #salary costs
#FUNKCjA CELU
#=====================================================================
minimize PATH_COST: sum{k in Rodzaj_Transportu}(sum{z in numery_Zlecen}Koszty_Suma[k,z])*y[k,z];
#OGRANICZENIA (constraints)
#=====================================================================
s.t. SOURCE{z in numery_Zlecen, (p,q) in Zlecenie[z], i in Miasta: i = p && p != q}:
sum {j in Miasta} (x[i ,j ,z ]) - sum {j in Miasta}( x[j ,i ,z ]) = 1;
s.t. INTERNAL {z in numery_Zlecen, (p,q) in Zlecenie[z],i in Miasta: i != p && i != q && p != q }:
sum {j in Miasta} (x[i ,j ,z ]) - sum {j in Miasta}( x[j ,i ,z ]) = 0;
s.t. OGR_KM_DZIEN{z in numery_Zlecen,(p,q) in Zlecenie[z], j in Miasta, i in Miasta: i != q}:
if (Dystans[i,j] > (Godziny_Pracy*Srednia_Predkosc)) and i != q then x[i,j,z] = 0;
s.t. OGR_KOSZTY_SUMA{z in numery_Zlecen, k in Rodzaj_Transportu}:
Koszty_Suma[k,z] = (Koszty_Transportu[z] + Koszty_Odpoczynku[z] + Koszty_Wynagrodzenia[z])*ceil(Ilosc_Wyrobow[z]/Pojemnosc_Samochodu[k]);
s.t. OGR_KOSZTY_TRANSPORTU{z in numery_Zlecen}:
Koszty_Transportu[z] = (sum{i in Miasta} (sum{j in Miasta} ( Dystans[i,j]*x[i,j, z]*Koszt_Paliwa[i,j] ) ))*Spalenie_Paliwa;
s.t. OGR_KOSZTY_ODPOCZYNKU{z in numery_Zlecen}:
Koszty_Odpoczynku[z] =
(sum{i in Miasta} (sum{j in Miasta} ( Dystans[i,j]*x[i,j, z] ) ))/(Godziny_Pracy*Srednia_Predkosc) * Cena_Noclegu;
s.t. OGR_KOSZTY_WYNAGRODZENIA{z in numery_Zlecen}:
Koszty_Wynagrodzenia[z] =
((sum{i in Miasta} (sum{j in Miasta} ( Dystans[i,j]*x[i,j, z] ) ))/(Srednia_Predkosc)) * Wynagrodzenie_za_Godzine;
s.t. OGR_Y_JEDEN{z in numery_Zlecen}:
sum{k in Rodzaj_Transportu}(y[k,z]) = 1;
solve;
How is it possible to get rid of this error? Any hints how to solve this kind of problem are welcome.
First I think the parentheses are incorrect (note that y[k,z] depends on z). The expression
sum{k in Rodzaj_Transportu}(sum{z in numery_Zlecen}Koszty_Suma[k,z])*y[k,z];
is not mathematically correct. So, I assume what you meant is:
sum{k in Rodzaj_Transportu}(sum{z in numery_Zlecen}Koszty_Suma[k,z]*y[k,z]);
Let me restate the problem a little bit. I assume we can write this as:
sum((i,j), x[i,j]*y[i,j])
with y a binary variable and x a continuous variable. I also assume 0 <= x[i,j] <= U[i,j]. (U is an upper bound).
Here is a way to linearize this quadratic term. We can introduce a variable z[i,j]=x[i,j]*y[i,j] using the following inequalities:
z[i,j] <= U[i,j]*y[i,j]
z[i,j] <= x[i,j]
z[i,j] >= x[i,j]-U[i,j]*(1-y[i,j])
0 <= z[i,j] <= U[i,j]
Now you just can minimize sum((i,j),z[i,j]). For a similar linearization see link.
Recently I want to reproduce the Fig.1(a) of Edge States and Topological Invariants of Non-Hermitian Systems.I used cgeev to solve eigenvalue of non-Hermitian Hamiltonian matrices,I found the solution become wired.
Here is my Fortran code,the result to Fig1.(a) correspond the abs.dat.
module pub
implicit none
complex,parameter::im = (0.0,1.0)
real,parameter::pi = 3.1415926535
integer xn,N,en,kn
parameter(xn = 100,N = xn*2,en = 100)
complex Ham(N,N)
real t1,t2,t3,gam
!-----------------
integer::lda = N
integer,parameter::lwmax=2*N + N**2
complex,allocatable::w(:) ! store eigenvalues
complex,allocatable::work(:)
real,allocatable::rwork(:)
integer lwork
integer info
integer LDVL, LDVR
parameter(LDVL = N, LDVR = N )
complex VL( LDVL, N ), VR( LDVR, N )
end module pub
!=====================================================
program sol
use pub
! Physics memory allocate
allocate(w(N))
allocate(work(lwmax))
allocate(rwork(2*N))
!-----------------
t2 = 1.0
t3 = 0.0
gam = 3.0/4.0
call band()
end program sol
!======================================================
subroutine band()
use pub
integer m1,i
open(11,file="real.dat")
open(12,file="imag.dat")
open(13,file="abs.dat")
do m1 = -en,en
t1 = 3.0*m1/en
call matset()
call eigsol()
write(11,999)t1,(real(w(i)),i = 1,N)
write(12,999)t1,(aimag(w(i)),i = 1,N)
write(13,999)t1,(abs(w(i)),i = 1,N)
end do
close(11)
close(12)
close(13)
999 format(201f11.6)
end subroutine band
!======================================================
subroutine matset()
use pub
real kx
complex sx(2,2),sy(2,2),sz(2,2)
integer k,m1,m2
sx(1,2) = 1.0
sx(2,1) = 1.0
sy(1,2) = -im
sy(2,1) = im
sz(1,1) = 1.0
sz(2,2) = -1.0
!--------
Ham = 0.0
do k = 0,xn-1
if(k == 0)then
do m1 = 1,2
do m2 = 1,2
ham(m1,m2) = t1*sx(m1,m2) + im*gam/2.0*sy(m1,m2)
ham(m1,m2 + 2) = (t2 + t3)/2.0*sx(m1,m2) - im*(t2 - t3)/2.0*sy(m1,m2)
end do
end do
elseif(k == xn-1)then
do m1 = 1,2
do m2 = 1,2
ham(k*2 + m1,k*2 + m2) = t1*sx(m1,m2) + im*gam/2.0*sy(m1,m2)
ham(k*2 + m1,k*2 + m2 - 2) = (t2 + t3)/2.0*sx(m1,m2) + im*(t2 - t3)/2.0*sy(m1,m2)
end do
end do
else
do m1 = 1,2
do m2 = 1,2
ham(k*2 + m1,k*2 + m2) = t1*sx(m1,m2) + im*gam/2.0*sy(m1,m2)
! right hopping
ham(k*2 + m1,k*2 + m2 + 2) = (t2 + t3)/2.0*sx(m1,m2) - im*(t2 - t3)/2.0*sy(m1,m2)
! left hopping
ham(k*2 + m1,k*2 + m2 - 2) = (t2 + t3)/2.0*sx(m1,m2) + im*(t2 - t3)/2.0*sy(m1,m2)
end do
end do
end if
end do
return
end subroutine matset
!==============================================================================
subroutine eigsol()
use pub
! Query the optimal workspace.
LWORK = -1
CALL cgeev( 'Vectors', 'Vectors', N, Ham, LDA, W, VL, LDVL, VR, LDVR, WORK, LWORK, RWORK, INFO)
LWORK = MIN( LWMAX, INT( WORK( 1 ) ) )
! Solve eigenproblem.
CALL cgeev( 'Vectors', 'Vectors', N, Ham, LDA, W, VL, LDVL,VR, LDVR, WORK, LWORK, RWORK, INFO)
! Check for convergence.
IF( INFO.GT.0 ) THEN
WRITE(*,*)'The algorithm failed to compute eigenvalues.'
STOP
END IF
! open(120,file="eigval.dat")
! do m = 1,N
! write(120,*)m,w(m)
! end do
! close(120)
return
end subroutine eigsol
If I used wrong function from Lapack or my code isn't correct.
I use intel fortran,complie command is
*ifort -mkl file.f90 -o a.out
Run program ./a.out&*
I am getting a particular double number from the webservice like 0.097 or 0.034 from the webservice. So if i am getting a particular number like 0.56 or 0.5 i need to add a zero in 0.56 and two zeros in 0.5. How to do this in swift3?
Currently i am doing :
class func appendString(data: Int) -> String {
let value = data
let formatter = NumberFormatter()
formatter.minimumFractionDigits = 3 // for float
formatter.maximumFractionDigits = 3 // for float
formatter.minimumIntegerDigits = 1
formatter.paddingPosition = .afterPrefix
formatter.paddingCharacter = "0"
return formatter.string(from: NSNumber(floatLiteral: Double(value)))!
}
Any idea how to achieve th above told logic?
The issue that you are passing data input in Int type, so it will always ignore fractions
see next example [Swift 3.1]
func formatNumber(_ number: Double) -> String? {
let formatter = NumberFormatter()
formatter.minimumFractionDigits = 3 // minimum number of fraction digits on right
formatter.maximumFractionDigits = 3 // maximum number of fraction digits on right, or comment for all available
formatter.minimumIntegerDigits = 1 // minimum number of integer digits on left (necessary so that 0.5 don't return .500)
let formattedNumber = formatter.string(from: NSNumber.init(value: number))
return formattedNumber
}
let formattedNumber = formatNumber(0.5)
print(formattedNumber) // Optional("0.500")
Just few small changes to your code :
func appendString(data: Double) -> String { // changed input type of data
let value = data
let formatter = NumberFormatter()
formatter.minimumFractionDigits = 3 // for float
formatter.maximumFractionDigits = 3 // for float
formatter.minimumIntegerDigits = 1
formatter.paddingPosition = .afterPrefix
formatter.paddingCharacter = "0"
return formatter.string(from: NSNumber(floatLiteral: value))! // here double() is not required as data is already double
}
print(appendString(data: 0.5)) // 0.500
The following is a program for self avoiding random walk. The program works fine but I need to make a minor modification but I do not know how.
Currently the program receives n and ns as inputs and then calculates a distance (dis). I want the program to receive more than one n and calculate the distance for each n.
Example of current output
n = 100 ns = 100 dis = 10.8
I want the program to output
n = 100 ns = 100 dis = 10.8
n = 200 ns = 100 dis = 11.6
and go on for all input vales of n.
This can be done by running the program every time with different n but I need to do it with one run.
PROGRAM Two_dimensional_Self_Avoiding__Random_Walks
implicit none
integer, dimension(:,:), allocatable :: lattice
integer :: i,x,y,xt,yt,id,step,xx, ns,n
real :: r,dis,dis2,square,d,d2
Logical :: terminate,newsite
print*, ' Enter ns and n '
read(*,*) ns,n
allocate(lattice(-n:n,-n:n))
CALL RANDOM_SEED()
dis = 0.0; dis2 = 0.0 ! intial values for end to end distance
CALL walks() ! self avoiding walks
dis = dis/float(ns); dis2 = dis2/float(ns)
print*,ns,n,dis,dis2
CONTAINS
SUBROUTINE walks
DO i = 1,ns
lattice = 0; x = 0; y = 0
step = 0; terminate = .FALSE.
!do ii = 1, n
DO WHILE ((.NOT. terminate) .AND. (step <= n))
xt = x; yt = y
xx = lattice(x+1,y)+lattice(x-1,y) &
+lattice(x,y+1)+lattice(x,y-1)
IF (xx == 4) THEN
terminate = .TRUE.
ELSE
newsite = .FALSE.
DO WHILE (.NOT. newsite)
CALL RANDOM_NUMBER(r)
id = INT(r*4.0)
IF (id == 0) THEN
x = xt + 1; y = yt
ELSEIF (id == 1) THEN
x = xt - 1; y = yt
ELSEIF (id == 2) THEN
x = xt; y = yt + 1
ELSEIF (id == 3) THEN
x = xt; y = yt - 1
ENDIF
IF (lattice(x,y) == 0) newsite = .TRUE.
ENDDO
step = step + 1; lattice(x,y) = 1
ENDIF
write(10,*),step
!print*, x,y
write(7,*) x,y
ENDDO
square = float(x**2+y**2)
dis = dis + sqrt(square); dis2 = dis2 + square
d = dis/ns; d2=dis2/ns
write(8,*) step, d, d2
!enddo
ENDDO
END SUBROUTINE walks
END PROGRAM Two_dimensional_Self_Avoiding__Random_Walks
I am attempting to convert the first code snippet at:
Calculate distance between 2 GPS coordinates
// var R = 6371; // km
// var dLat = (lat2-lat1).toRad();
// var dLon = (lon2-lon1).toRad();
// var lat1 = lat1.toRad();
// var lat2 = lat2.toRad();
// var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
// Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
// var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
// var d = R * c;
(also shown below) for use in qt c++. It is used in a program that simulates gps flight inside of a radio control simulator. The GpsCalcLoop grabs gps latitude and longitude (in decimal format) once per second. These are fed into my converted code in hopes of getting a distance traveled during that one second of time. Speed would then be calculated.
I used the information at this page:
http://doc.qt.io/qt-4.8/qtcore-qmath-h.html
to convert the math functions. The output, however, is not what I expected. No matter what is input into lat2, lat1, lon2, and lon1 the results are always the same, '16777200.00'.
I am hoping that someone more familiar with qt c++ will be able to show me where I have gone wrong with the conversion. or point me to where I can find qt c++ code that is working.
I will add that I have attempted to use "#include "<"QGeoPositionInfo">" but get a 'No such file or directory' error when running the program.
void TelemetrySimulator::onGpsCalcLoop()
{
if(rungps)
{
ui -> valuetest1 -> setValue(flat);
ui -> valuetest2 -> setValue(flat2);
ui -> valuetest3 -> setValue(flon);
ui -> valuetest4 -> setValue(flon2);
ui -> valuetest5 -> setValue(flat-flat2);
ui -> valuetest6 -> setValue(flon-flon2);
flat2 = flat;
flon2 = flon;
//--https://stackoverflow.com/questions/365826 //calculate-distance-between-2-gps-coordinates--
// var R = 6371; // km
// var dLat = (lat2-lat1).toRad();
// var dLon = (lon2-lon1).toRad();
// var lat1 = lat1.toRad();
// var lat2 = lat2.toRad();
// var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
// Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
// var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
// var d = R * c;
//--------------my conversio to qt c++---------
//---converted to qt using this web page -> http://doc.qt.io/qt-4.8/qtcore-qmath-h.html----
double R, dLat, dLon, lat1, lat2, lon2, lon1, a, c, d;
lat2 = flat2;
lat1 = flat;
lon2 = flon2;
lon1 = flon;
R = 6371; // km
dLat = qAcos(lat2-lat1); //dLat = (lat2-lat1).toRad(); instead of qAcos could be qAsin, qAtan, qCos, qSin,
// qTan. All refer to Radials.
dLon = qAcos(lon2-lon1); //dLon = (lon2-lon1).toRad();
lat1 = qAcos(lat1); //lat1 = lat1.toRad();
lat2 = qAcos(lat2); //lat2 = lat2.toRad();
a = qSin(dLat/2) * qSin(dLat/2) + //Math.sin(dLat/2) * Math.sin(dLat/2) +
qSin(dLon/2) * qSin(dLon/2) * qCos(lat1) * qCos(lat2);//Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
c = 2 * qAtan2(qSqrt(a), qSqrt(1-a)); //Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
d = R * c;
ui -> valuetest7 -> setValue(d);
}
}
Thanks to everyone for your great help! Here is the final code:
void MainWindow::onGpsCalcLoop()
{
//Get initial values from gps run loop-------
double lat2 = flat2;
double lat1 = flat;
double lon2 = flon2;
double lon1 = flon;
//GPS distance and speed calculation -------
double dLat = .01745329 * (lat2 - lat1);
double dLon = .01745329 * (lon2 - lon1);
lat1 = .01745329 * lat1;
lat2 = .01745329 * lat2;
double a = qSin(dLat/2) * qSin(dLat/2) +
qSin(dLon/2) * qSin(dLon/2) * qCos(lat1) * qCos(lat2);
double c = 2 * qAtan2(qSqrt(a), qSqrt(1-a));
double d = 3975 * c;
//Distance calculation done. Next is total distance and speed------
td = td + d;
if (d > .1)
{
d = 0;
td = 0;
}
if (ui -> metric -> isChecked())
{
ui -> valuetest1 -> setValue(td * 1.6);
ui -> valuetest2 -> setValue((d * 3600) * 1.6);
}
else
{
ui -> valuetest1 -> setValue(td);
ui -> valuetest2 -> setValue(d * 3600);
}
flat2 = flat;
flon2 = flon;
}
I used .01745329*(whatever) instead of qDegreesToRadians(whatever) just to keep things as simple as possible.
Again, thanks to all for your help!