I am trying to create a simple simulation program of SIR-epidemics model in java.
Basically, SIR is defined by a system of three differential equations:
S'(t) = - l(t) * S(t)
I'(t) = l(t) * S(t) - g(t) * I(t)
R'(t) = g(t) * I(t)
S - susceptible people, I - infected people, R - recovered people.
l(t) = [c * x * I(t)] / N(T)
c - number of contacts, x - infectiveness (probability to get sick after contact with sick person), N(t) - total population (which is constant).
How can I solve such differential equations in Java? I don't think I know any useful way to do that, so my implementation produces rubbish.
public class Main {
public static void main(String[] args) {
int tppl = 100;
double sppl = 1;
double hppl = 99;
double rppl = 0;
int numContacts = 50;
double infectiveness = 0.5;
double lamda = 0;
double duration = 0.5;
double gamma = 1 / duration;
for (int i = 0; i < 40; i++) {
lamda = (numContacts * infectiveness * sppl) / tppl;
hppl = hppl - lamda * hppl;
sppl = sppl + lamda * hppl - gamma * sppl;
rppl = rppl + gamma * sppl;
System.out.println (i + " " + tppl + " " + hppl + " " + sppl + " " + rppl);
}
}
}
I would greatly appreciate any help, many thanks in advance!
Time-series differential equations can be simulated numerically by taking dt = a small number, and using one of several numerical integration techniques e.g. Euler's method, or Runge-Kutta. Euler's method may be primitive but it works OK for some equations and it's simple enough that you might give it a try. e.g.:
S'(t) = - l(t) * S(t)
I'(t) = l(t) * S(t) - g(t) * I(t)
R'(t) = g(t) * I(t)
int N = 100;
double[] S = new double[N+1];
double[] I = new double[N+1];
double[] R = new double[N+1];
S[0] = /* initial value */
I[0] = /* initial value */
R[0] = /* initial value */
double dt = total_time / N;
for (int i = 0; i < 100; ++i)
{
double t = i*dt;
double l = /* compute l here */
double g = /* compute g here */
/* calculate derivatives */
double dSdt = - I[i] * S[i];
double dIdt = I[i] * S[i] - g * I[i];
double dRdt = g * I[i];
/* now integrate using Euler */
S[i+1] = S[i] + dSdt * dt;
I[i+1] = I[i] + dIdt * dt;
R[i+1] = R[i] + dRdt * dt;
}
The tough part is figuring out how many steps to use. You should read one of the articles I have linked to. More sophisticated differential equation solvers use variable step sizes that adapt to accuracy/stability for each step.
I would actually recommend using numerical software like R or Mathematica or MATLAB or Octave, as they include ODE solvers and you wouldn't need to go to all the trouble yourself. But if you need to do this as part of a larger Java application, at least try it out first with math software, then get a sense of what the step sizes are and what solvers work.
Good luck!
Related
I'm attempting to make a simulation of the SEIR epidemic model.
It contains four parts:
Susceptibles (non-infected)
Exposed (infected but not infectious yet)
Infectious (infected and infectious)
Removed (recovered/dead)
where gamma γ is the infection rate and beta β is the reovery/death rate.
I've previously used the SIR model, a more basic model where E and I are combined, which uses these equations:
From another thread I've used a solution to simulate SIR using this code:
double dS = (beta * S.get(day) * I.get(day) / N);
double newS = (S.get(day) - dS);
double newI = (I.get(day) + dS - gamma * I.get(day));
double newR = (R.get(day) + gamma * I.get(day));
This works fine using the Euler's method. However, I've tried to manipulate this to try and fit the SEIR model (which has these equations:)
where u is the death rate, delta is the birth rate and a is the incubation period. I've made an attempt to try and use a similar method to work for SEIR but I'm unsuccessful to simulate it well at all. This isn't really a problem with the variables but as a whole differentiating these complex equations. Wondering if anyone could help, thanks.
Really should've realised this earlier but from messing around with random sign changes, worked out that everything apart from 'newS' requires getting the previous day's number and plussing the new dS, rather than minusing it. My SIR code already did this. Don't really know how I missed this..
New working code:
int totalDays = 160; // How many days/times to loop
int N = 1000; // Population
int I0 = 1; // Starting infected/exposed
double beta = 0.2; // Infection rate
double gamma = 1.0/10.0; // recovery time (days to the -1)
double a = 1.0/2.0; // incubation period (days to the -1)
List<Double> S = new ArrayList<>();
List<Double> E = new ArrayList<>();
List<Double> I = new ArrayList<>();
List<Double> R = new ArrayList<>();
private void createData() {
final int R0 = 0;
final int S0 = N - E0 - R0;
S.add((double) S0);
E.add((double) I0);
I.add(0.0);
R.add(0.0);
for (int day = 1; day < totalDays + 1; day++) {
double[] derivative = deriv(day);
S.add(derivative[0]);
E.add(derivative[1]);
I.add(derivative[2]);
R.add(derivative[3]);
}
}
private double[] deriv(int day) {
day = day - 1;
double dS = (beta * S.get(day) * I.get(day)) / N;
double newS = S.get(day) - (dS);
double newE = E.get(day) + (dS - (a * E.get(day)));
double newI = I.get(day) + ((a * E.get(day)) - (gamma * I.get(day)));
double newR = R.get(day) + (gamma * I.get(day));
return new double[] {newS, newE, newI, newR};
}
I'm looking for some method that takes or does not take parameters for calculate confidence interval.
I don't want the apache methods,
just a simple method or som type of code that does this.
My knowledge is restricted, it basically boils down to completing an online task against an expected set of answers (https://www.hackerrank.com/challenges/stat-warmup).
However, as far as I read up, there are mistakes in the given answer, and I'd like to correct these.
My source is pretty much wikipedia https://en.wikipedia.org/wiki/Confidence_interval#Basic_Steps
/**
*
* #return int[]{lower, upper}, i.e. int array with Lower and Upper Boundary of the 95% Confidence Interval for the given numbers
*/
private static double[] calculateLowerUpperConfidenceBoundary95Percent(int[] givenNumbers) {
// calculate the mean value (= average)
double sum = 0.0;
for (int num : givenNumbers) {
sum += num;
}
double mean = sum / givenNumbers.length;
// calculate standard deviation
double squaredDifferenceSum = 0.0;
for (int num : givenNumbers) {
squaredDifferenceSum += (num - mean) * (num - mean);
}
double variance = squaredDifferenceSum / givenNumbers.length;
double standardDeviation = Math.sqrt(variance);
// value for 95% confidence interval, source: https://en.wikipedia.org/wiki/Confidence_interval#Basic_Steps
double confidenceLevel = 1.96;
double temp = confidenceLevel * standardDeviation / Math.sqrt(givenNumbers.length);
return new double[]{mean - temp, mean + temp};
}
here is you go this is the code calculate Confidence Interval
/**
*
* #author alaaabuzaghleh
*/
public class TestCI {
public static void main(String[] args) {
int maximumNumber = 100000;
int num = 0;
double[] data = new double[maximumNumber];
// first pass: read in data, compute sample mean
double dataSum = 0.0;
while (num<maximumNumber) {
data[num] = num*10;
dataSum += data[num];
num++;
}
double ave = dataSum / num;
double variance1 = 0.0;
for (int i = 0; i < num; i++) {
variance1 += (data[i] - ave) * (data[i] - ave);
}
double variance = variance1 / (num - 1);
double standardDaviation= Math.sqrt(variance);
double lower = ave - 1.96 * standardDaviation;
double higher = ave + 1.96 * standardDaviation;
// print results
System.out.println("average = " + ave);
System.out.println("sample variance = " + variance);
System.out.println("sample standard daviation = " + standardDaviation);
System.out.println("approximate confidence interval");
System.out.println("[ " + lower + ", " + higher + " ]");
}
}
I am using the pointwise mutual information (PMI) association measure to calculate how frequently words co-occure by using word-frequencies obtained from a large corpus.
I am calculating PMI via the classical formulae of
log(P(X,Y) / (P(X)*P(Y))
and using the contingency table notation with joint- and marginal frequencies I found on http://collocations.de/AM/index.html
The results I get are very similar, but not the same. As far as I understood things both methods should result in the exact same result value.
I made a little Java-programm (minimal working example) that uses word-frequencies from a corpus using both formulae. I get different results for the two methods. Does someone know why ?
public class MutualInformation
{
public static void main(String[] args)
{
long N = 1024908267229L;
// mutual information = log(P(X,Y) / P(X) * P(Y))
double XandY = (double) 1210738 / N;
double X = (double) 67360790 / N;
double Y = (double) 1871676 / N;
System.out.println(Math.log(XandY / (X * Y)) / Math.log(10));
System.out.println("------");
// contingency table notation as on www.collocations.de
long o11 = 1210738;
long o12 = 67360790;
long o21 = 1871676;
long c1 = o11 + o21;
long r1 = o11 + o12;
double e11 = ((double) r1 * c1 / N);
double frac = (double) o11 / e11;
System.out.println(Math.log(frac) / Math.log(10));
}
}
Let write it in the same terms
long o11 = 1210738;
long o12 = 67360790;
long o21 = 1871676;
long N = 1024908267229L
The first equation is
XandY = o11 / N;
X = o12 / N;
Y = o21 / N;
so
XandY / (X * Y)
is
(o11 / N) / (o12 / N * o21 / N)
or
o11 * N / (o12 * o21)
Note there is no adding going on.
The second equation is rather different.
c1 = o11 + o21;
r1 = o11 + o12;
e11 = ((double) r1 * c1 / N);
frac = (double) o11 / e11;
so
e11 = (o11 + o21) * (o11 + o12) /N;
frac = (o11 * N) / (o11^2 + o11 * o12 + o21 * o11 + o21 * o12);
I would expect these to be different as mathematically they are not the same.
I suggest you write what you want as maths first, and then find the most efficient way of coding it.
I need to get the amplitude of a signal at a certain frequency.
I use FFTAnalysis function. But I get all spectrum. How can I modify this for get the amplitude of a signal at a certain frequency?
For example I have:
data = array of 1024 points;
If I use FFTAnalysis I get FFTdata array of 1024 points.
But I need only FFTdata[454] for instance ();
public static float[] FFTAnalysis(short[] AVal, int Nvl, int Nft) {
double TwoPi = 6.283185307179586;
int i, j, n, m, Mmax, Istp;
double Tmpr, Tmpi, Wtmp, Theta;
double Wpr, Wpi, Wr, Wi;
double[] Tmvl;
float[] FTvl;
n = Nvl * 2;
Tmvl = new double[n];
FTvl = new float[Nvl];
for (i = 0; i < Nvl; i++) {
j = i * 2; Tmvl[j] = 0; Tmvl[j+1] = AVal[i];
}
i = 1; j = 1;
while (i < n) {
if (j > i) {
Tmpr = Tmvl[i]; Tmvl[i] = Tmvl[j]; Tmvl[j] = Tmpr;
Tmpr = Tmvl[i+1]; Tmvl[i+1] = Tmvl[j+1]; Tmvl[j+1] = Tmpr;
}
i = i + 2; m = Nvl;
while ((m >= 2) && (j > m)) {
j = j - m; m = m >> 1;
}
j = j + m;
}
Mmax = 2;
while (n > Mmax) {
Theta = -TwoPi / Mmax; Wpi = Math.sin(Theta);
Wtmp = Math.sin(Theta / 2); Wpr = Wtmp * Wtmp * 2;
Istp = Mmax * 2; Wr = 1; Wi = 0; m = 1;
while (m < Mmax) {
i = m; m = m + 2; Tmpr = Wr; Tmpi = Wi;
Wr = Wr - Tmpr * Wpr - Tmpi * Wpi;
Wi = Wi + Tmpr * Wpi - Tmpi * Wpr;
while (i < n) {
j = i + Mmax;
Tmpr = Wr * Tmvl[j] - Wi * Tmvl[j-1];
Tmpi = Wi * Tmvl[j] + Wr * Tmvl[j-1];
Tmvl[j] = Tmvl[i] - Tmpr; Tmvl[j-1] = Tmvl[i-1] - Tmpi;
Tmvl[i] = Tmvl[i] + Tmpr; Tmvl[i-1] = Tmvl[i-1] + Tmpi;
i = i + Istp;
}
}
Mmax = Istp;
}
for (i = 0; i < Nft; i++) {
j = i * 2; FTvl[Nft - i - 1] = (float) Math.sqrt((Tmvl[j]*Tmvl[j]) + (Tmvl[j+1]*Tmvl[j+1]));
}
return FTvl;
}
The Goertzel algorithm (or filter) is similar to computing the magnitude for just 1 bin of an FFT.
The Goertzel algorithm is identical to 1 bin of an FFT, except for numerical artifacts, if the period of the frequency is an exact submultiple of your Goertzel filter's length. Otherwise there are some added scalloping effects from a rectangular window of non-periodic-in-aperture size, and how that window relates to the phase of the input.
Multiplying by a complex sinusoid and taking the magnitude of the complex sum is also computationally similar to a Goertzel, except the Goertzel does not require separately calling (or looking up) a trig library function every point, as it usually includes a trig recursion at part of its algorithm.
You'd multiply a (complex) sine wave on the input data, and integrate the result.
Multiplying with a complex sine is equal to a frequency shift, you want to shift the target frequency down to 0 Hz. The integration is a low pass filtering step, with the bandwidth being the inverse of the sampling length.
You then end up with a complex number, which is the same number you would have found in the FFT bin for this frequency (because in essence this is what the FFT does).
The fast fourier transform (FFT) is a clever way of doing many discrete fourier transforms very quickly. As such, the FFT is designed for when one needs a lot of frequencies from the input. If you want just one frequency, the DFT is the way to go (as otherwise you're wasting resources).
The DFT is defined as:
So, in pseudocode:
samples = [#,#,#,#...]
FREQ = 440; // frequency to detect
PI = 3.14159;
E = 2.718;
DFT = 0i; // this is a complex number
for(int sampleNum=0; sampleNum<N; sampleNum++){
DFT += samples[sampleNum] * E^( (-2*PI*1i*N) / N ); //Note that "i" here means imaginary
}
The resulting variable DFT will be a complex number representing the real and imaginary values of the chosen frequency.
I would like to take an array of bytes of roughly size 70-80k and transform them from the time domain to the frequency domain (probably using a DFT). I have been following wiki and gotten this code so far.
for (int k = 0; k < windows.length; k++) {
double imag = 0.0;
double real = 0.0;
for (int n = 0; n < data.length; n++) {
double val = (data[n])
* Math.exp(-2.0 * Math.PI * n * k / data.length)
/ 128;
imag += Math.cos(val);
real += Math.sin(val);
}
windows[k] = Math.sqrt(imag * imag + real
* real);
}
and as far as I know, that finds the magnitude of each frequency window/bin. I then go through the windows and find the one with the highest magnitude. I add a flag to that frequency to be used when reconstructing the signal. I check to see if the reconstructed signal matches my original data set. If it doesn't find the next highest frequency window and flag that to be used when reconstructing the signal.
Here is the code I have for reconstructing the signal which I'm mostly certain is very wrong (it is supposed to perform an IDFT):
for (int n = 0; n < data.length; n++) {
double imag = 0.0;
double real = 0.0;
sinValue[n] = 0;
for (int k = 0; k < freqUsed.length; k++) {
if (freqUsed[k]) {
double val = (windows[k] * Math.exp(2.0 * Math.PI * n
* k / data.length));
imag += Math.cos(val);
real += Math.sin(val);
}
}
sinValue[n] = imag* imag + real * real;
sinValue[n] /= data.length;
newData[n] = (byte) (127 * sinValue[n]);
}
freqUsed is a boolean array used to mark whether or not a frequency window should be used when reconstructing the signal.
Anyway, here are the problems that arise:
Even if all of the frequency windows are used, the signal is not reconstructed. This may be due to the fact that ...
Sometimes the value of Math.exp() is too high and thus returns infinity. This makes it difficult to get accurate calculations.
While I have been following wiki as a guide, it is hard to tell whether or not my data is meaningful. This makes it hard to test and identify problems.
Off hand from the problem:
I am fairly new to this and do not fully understand everything. Thus, any help or insight is appreciated. Thanks for even taking the time to read all of that and thanks ahead of time for any help you can provide. Any help really would be good, even if you think I'm doing this the most worst awful way possible, I'd like to know. Thanks again.
-
EDIT:
So I updated my code to look like:
for (int k = 0; k < windows.length; k++) {
double imag = 0.0;
double real = 0.0;
for (int n = 0; n < data.length; n++) {
double val = (-2.0 * Math.PI * n * k / data.length);
imag += data[n]*-Math.sin(val);
real += data[n]*Math.cos(val);
}
windows[k] = Math.sqrt(imag * imag + real
* real);
}
for the original transform and :
for (int n = 0; n < data.length; n++) {
double imag = 0.0;
double real = 0.0;
sinValue[n] = 0;
for (int k = 0; k < freqUsed.length; k++) {
if (freqUsed[k]) {
double val = (2.0 * Math.PI * n
* k / data.length);
imag += windows[k]*-Math.sin(val);
real += windows[k]*Math.cos(val);
}
}
sinValue[n] = Math.sqrt(imag* imag + real * real);
sinValue[n] /= data.length;
newData[n] = (byte) (Math.floor(sinValue[n]));
}
for the inverse transform. Though I am still concerned that it isn't quite working correctly. I generated an array holding a single sine wave and it can't even decompose/reconstruct that. Any insight as to what I'm missing?
Yes, your code (for both DFT and IDFT) is broken. You are confusing the issue of how to use the exponential. The DFT can be written as:
N-1
X[k] = SUM { x[n] . exp(-j * 2 * pi * n * k / N) }
n=0
where j is sqrt(-1). That can be expressed as:
N-1
X[k] = SUM { (x_real[n] * cos(2*pi*n*k/N) + x_imag[n] * sin(2*pi*n*k/N))
n=0 +j.(x_imag[n] * cos(2*pi*n*k/N) - x_real[n] * sin(2*pi*n*k/N)) }
which in turn can be split into:
N-1
X_real[k] = SUM { x_real[n] * cos(2*pi*n*k/N) + x_imag[n] * sin(2*pi*n*k/N) }
n=0
N-1
X_imag[k] = SUM { x_imag[n] * cos(2*pi*n*k/N) - x_real[n] * sin(2*pi*n*k/N) }
n=0
If your input data is real-only, this simplifies to:
N-1
X_real[k] = SUM { x[n] * cos(2*pi*n*k/N) }
n=0
N-1
X_imag[k] = SUM { x[n] * -sin(2*pi*n*k/N) }
n=0
So in summary, you don't need both the exp and the cos/sin.
As well as the points that #Oli correctly makes, you also have a fundamental misunderstanding about conversion between time and frequency domains. Your real input signal becomes a complex signal in the frequency domain. You should not be taking the magnitude of this and converting back to the time domain (this will actually give you the time domain autocorrelation if done correctly, but this is not what you want). If you want to be able to reconstruct the time domain signal then you must keep the complex frequency domain signal as it is (i.e. separate real/imaginary components) and do a complex-to-real IDFT to get back to the time domain.
E.g. your forward transform should look something like this:
for (int k = 0; k < windows.length; k++) {
double imag = 0.0;
double real = 0.0;
for (int n = 0; n < data.length; n++) {
double val = (-2.0 * Math.PI * n * k / data.length);
imag += data[n]*-Math.sin(val);
real += data[n]*Math.cos(val);
}
windows[k].real = real;
windows[k].imag = image;
}
where windows is defined as an array of complex values.