Table functions/interpolation in Netlogo - netlogo

I am combining and rewriting some system dynamics models (i.e. stock-and-flow models) with agent based models in Netlogo.
System dynamics models often include table functions for describing non-linear relationships. If we have two continuous variables x and y, and we know that an approximate relationship is (x = 0, y = 100; x = 1, y = 50; x = 2, y = 45, x = 3, y = 40; x = 4, y = 35), we can use interpolation to find the value of y for any value of x. In R, for instance, you can use the appoxfun() function.
Is there a way of addressing these relationships in Netlogo, in absence of actually knowing the causal mechanisms and coding them in the model? I have searched around on internet resources, but haven't been able to find much.
Thanks for your help!

There is not an existing function. However, it is straightforward to construct an interpolation function that you can call. This version does linear interpolation and handles values outside the specified range of x values by reporting the appropriate end y value. Someone who is better than me at list functions (eg reduce) might find a more elegant method.
to-report calc-piecewise [#xval #xList #yList]
if not (length #xList = length #ylist)
[ report "ERROR: mismatched points"
]
if #xval <= first #xList [ report first #yList ]
if #xval >= last #xList [ report last #yList ]
; iterate through x values to find first that is larger than input x
let ii 0
while [item ii #xlist <= #xval] [ set ii ii + 1 ]
; get the xy values bracketing the input x
let xlow item (ii - 1) #xlist
let xhigh item ii #xlist
let ylow item (ii - 1) #ylist
let yhigh item ii #ylist
; interpolate
report ylow + ( (#xval - xlow) / (xhigh - xlow) ) * ( yhigh - ylow )
end
to testme
let xs [0 1 2 3 4]
let ys [100 50 30 20 15]
print calc-piecewise 1.5 xs ys
end
This version requires you to specify the x-value list and y-value list (as well as the x value for interpolation) each time you use it. If you are always going to use the same points, they can be specified inside the function.

Related

MatLab :: Assume and find different possible unknown variables of inequalities ,

I have inequalities with two unknown variables. So how could I assume one variable with different values and get the others?
For instance: -15<10*x+2*y<20.
How could I assume x=2, 3, and so on, and then find answer of (y) depending on the value of (x)?
I have been trying to apply the assume and find commands, but unfortunately, I could not. So I hope anyone could help me, please.
Looking forward to hearing from you.
I am new to Matlab, so I have been trying to apply solve, assume, and find commands
clear all;
clc;
syms x y real;
z=solve(-15<10*x+2*y,[x y])
b=solve(10*x+2*y<20,[x y])
yinterval = [ z,b]
I expect the output: to assume x=different numbers and then y= be a list of possible results depending on the value of x
Thanks,
For each value of x, technically there are infinite values of y that satisfy those equations, so for my solution, I assumed x and y were integer values. As well, it appears that you want to give the program a set of x values and have it calculate y values for each x value. Instead of using the solve command, we can simply use a couple of loops to find all satisfactory integer values of y for each value of x.
To start, we need to make a results matrix to store each x,y pair that satisfies the equations you've given. This is called pre-allocation, as we're pre-allocating the space needed to store our answers. Using the equations, we can deduce that there will be 17 satisfactory y values per x. So, our first two lines of code will be initializing the desired x-values and the results matrix:
xVec = 1:5; %x-vector, change this to whatever x-values you want to test
results = zeros(length(xVec)*14, 2); %results matrix
Note: If you decide to iterate x or y by a value different than +1 (more on that later), you'll need to come up with a different method of creating this results matrix. You could also just not pre-allocate the results matrix, but your code will run slower as the size of the results matrix will be changing on each loop.
Next are the loops. Admittedly, this is not the most elegant solution, but it'll get the job done. First, we need an index to keep up with where we are in our results matrix. This is pretty easy, we'll just call it index and start at 1 (since MATLAB indexes from 1 in matrices. Remember that!):
index = 1; %index for results matrix
Next, we need to loop through each value in our x-vector. Simply use a for loop:
for x = xVec
...
For each value of x, there is a minimum value of y. This value can be solved for in
-15 < 10*x + 2*y --> -14 = 10*x + 2*y_min
So, simply solving for y gives us our next line of code:
y = -7 - 5*x; %solving for y
Note: each time we iterate x in our for loop, a new starting value of y will be calculated.
Finally, we need to loop through values of y that still satisfy the inequalities given. This is performed through use of a while loop:
while 10*x + 2*y > -15 && 10*x + 2*y < 20
...
Note: && is the 'and' statement while using loops. You can't use a single equation for this (i.e. you can't say something like -15 < x < 20, you have to split them up using &&).
Since we solved for the first value of y, we can go ahead and record the current x and y values in our results matrix:
results(index, :) = [x, y]; %storing current x- and y-values
Then, we need to iterate y, as otherwise we'd be stuck in this while-loop forever.
y = y + 1;
Note: You can iterate this y-value with whatever amount you want. I chose to iterate by 1 each time, as I assumed you wanted to find integer values. Just change the +1 to whatever value you want.
Finally, we iterate our index, so that the next pair of x,y values that satisfy our equations don't overwrite our previous solutions.
index = index + 1;
All that's left is to close our loops and run! As I said, this isn't the most efficient solution, so I wouldn't use this for large amounts of x- and y-values. As well, like with iterating the y-values, the x-values can have any 'step-size' you want. As it's coded currently, it jumps +1 between each x, but changing the xVec input to any vector will still work (ex. xVec = 1:0.1:5; iterates the x-value by +0.1 each step instead of +1).
Here's the code all together, sans comments (since I wrote the comments while making the above code snippets):
xVec = 1:5;
results = zeros(length(xVec)*14, 2);
index = 1;
for x = xVec
y = -7 - 5*x;
while 10*x + 2*y > -15 && 10*x + 2*y < 20
results(index, :) = [x, y];
y = y + 1;
index = index + 1;
end
end
Let me know if you have any questions!

How can I generate a distribution whose values are distributed according to an input array?

I have written the following script which should create an array which contains the probability mass of every number from 1 to N, defined following the robust soliton distribution. The values of delta, N and M are completely arbitrary.
N = 300; % length of the the array
in = [1:1:N]; % index array
delta = 0.5;
M = 70;
R = N/M;
t(1:M-1) = 1./(in(1:M-1)*M);
t(M) = log(R/delta)/M;
t(M+1:N) = 0;
What I'm trying to do now is using the arrays in and t in order to "generate" in some way a pdf which returns the numbers in the array in with the probability contained in the array t. I have already looked in the manual and I found the makedist function, but I didn't find an option which allowed me to use as arguments two input arrays. I don't really know where to look.
The numbers generated should be used to encode packets using LT codes (for didactic purposes, I'm just trying to understand how to build them).
It sounds like you would like to be able to randomly pick numbers i element of 1:N with probabilities proportional to the value t(i).
First, let's restructure the unnormalized probabilities into an array that lists the ranges of each value; I.e.
t-> p {0,0.01,0.05,0.09, etc} I just used random values here.
Then what we can do is randomly pick a number from 0 to 1, and find the value of i associated with that random number. I.e. if we get 0.07, then the value of i would be 3 in my example because 0.07 is between 0.05 and 0.09 and the value i=3 has a 4% probability of being picked;
s = sum(t);
p = double.empty(N,1);
for i = 1:N
if(i == 0)
p(i) = 0
else
p(i) = p(i-1) + t(i-1)/s;
end
end
Now whenever we need a number from the distribution, we can use matlab's inherent find function
r = rand()
i = max(find(r-p>0)) % this could probably be optimized
What this does by example: If we use the same r and p as above:
r-p = {0.07, 0.06, 0.02, -0.02, etc}
find(r-p>0) = {1,2,3}

Matlab : How to represent a real number as binary

Problem : How do I use a continuous map - The Link1: Bernoulli Shift Map to model binary sequence?
Concept :
The Dyadic map also called as the Bernoulli Shift map is expressed as x(k+1) = 2x(k) mod 1. In Link2: Symbolic Dynamics, explains that the Bernoulli Map is a continuous map and is used as the Shift Map. This is explained further below.
A numeric trajectory can be symbolized by partitioning into appropriate regions and assigning it with a symbol. A symbolic orbit is obtained by writing down the sequence of symbols corresponding to the successive partition elements visited by the point in its orbit. One can learn much about the dynamics of the system by studying its symbolic orbits. This link also says that the Bernoulli Shift Map is used to represent symbolic dynamics.
Question :
How is the Bernoulli Shift Map used to generate the binary sequence? I tried like this, but this is not what the document in Link2 explains. So, I took the numeric output of the Map and converted to symbols by thresholding in the following way:
x = rand();
y = mod(2* x,1) % generate the next value after one iteration
y =
0.3295
if y >= 0.5 then s = 1
else s = 0
where 0.5 is the threshold value, called the critical value of the Bernoulli Map.
I need to represent the real number as fractions as explained here on Page 2 of Link2.
Can somebody please show how I can apply the Bernoulli Shift Map to generate symbolized trajectory (also called time series) ?
Please correct me if my understanding is wrong.
How do I convert a real valued numeric time series into symbolized i.e., how do I use the Bernoulli Map to model binary orbit /time series?
You can certainly compute this in real number space, but you risk hitting precision problems (depending on starting point). If you're interested in studying orbits, you may prefer to work in a rational fraction representation. There are more efficient ways to do this, but the following code illustrates one way to compute a series derived from that map. You'll see the period-n definition on page 2 of your Link 2. You should be able to see from this code how you could easily work in real number space as an alternative (in that case, the matlab function rat will recover a rational approximation from your real number).
[EDIT] Now with binary sequence made explicit!
% start at some point on period-n orbit
period = 6;
num = 3;
den = 2^period-1;
% compute for this many steps of the sequence
num_steps = 20;
% for each step
for n = 1:num_steps
% * 2
num = num * 2;
% mod 1
if num >= den
num = num - den;
end
% simplify rational fraction
g = gcd(num, den);
if g > 1
num = num / g;
den = den / g;
end
% recover 8-bit binary representation
bits = 8;
q = 2^bits;
x = num / den * q;
b = dec2bin(x, bits);
% display
fprintf('%4i / %4i == 0.%s\n', num, den, b);
end
Ach... for completeness, here's the real-valued version. Pure mathematicians should look away now.
% start at some point on period-n orbit
period = 6;
num = 3;
den = 2^period-1;
% use floating point approximation
x = num / den;
% compute for this many steps of the sequence
num_steps = 20;
% for each step
for n = 1:num_steps
% apply map
x = mod(x*2, 1);
% display
[num, den] = rat(x);
fprintf('%i / %i\n', num, den);
end
And, for extra credit, why is this implementation fast but daft? (HINT: try setting num_steps to 50)...
% matlab vectorised version
period = 6;
num = 3;
den = 2^period-1;
x = zeros(1, num_steps);
x(1) = num / den;
y = filter(1, [1 -2], x);
[a, b] = rat(mod(y, 1));
disp([a' b']);
OK, this is supposed to be an answer, not a question, so let's answer my own questions...
It's fast because it uses Matlab's built-in (and highly optimised) filter function to handle the iteration (that is, in practice, the iteration is done in C rather than in M-script). It's always worth remembering filter in Matlab, I'm constantly surprised by how it can be turned to good use for applications that don't look like filtering problems. filter cannot do conditional processing, however, and does not support modulo arithmetic, so how do we get away with it? Simply because this map has the property that whole periods at the input map to whole periods at the output (because the map operation is multiply by an integer).
It's daft because it very quickly hits the aforementioned precision problems. Set num_steps to 50 and watch it start to get wrong answers. What's happening is the number inside the filter operation is getting to be so large (order 10^14) that the bit we actually care about (the fractional part) is no longer representable in the same double-precision variable.
This last bit is something of a diversion, which has more to do with computation than maths - stick to the first implementation if your interest lies in symbol sequences.
If you only want to deal with rational type of output, you'll first have to convert the starting term of your series into a rational number if it is not. You can do that with:
[N,D] = rat(x0) ;
Once you have a numerator N and a denominator D, it is very easy to calculate the series x(k+1)=mod(2*x(k), 1) , and you don't even need a loop.
for the part 2*x(k), it means all the Numerator(k) will be multiplied by successive power of 2, which can be done by matrix multiplication (or bsxfun for the lover of the function):
so 2*x(k) => in Matlab N.*(2.^(0:n-1)) (N is a scalar, the numerator of x0, n is the number of terms you want to calculate).
The Mod1 operation is also easy to translate to rational number: mod(x,1)=mod(Nx,Dx)/Dx (Nx and Dx being the numerator and denominator of x.
If you do not need to simplify the denominator, you could get all the numerators of the series in one single line:
xn = mod( N.*(2.^(0:n-1).'),D) ;
but for visual comfort, it is sometimes better to simplify, so consider the following function:
function y = dyadic_rat(x0,n)
[N,D] = rat(x0) ; %// get Numerator and Denominator of first element
xn = mod( N.*(2.^(0:n-1).'),D) ; %'// calculate all Numerators
G = gcd( xn , D ) ; %// list all "Greatest common divisor"
y = [xn./G D./G].' ; %'// output simplified Numerators and Denominators
If I start with the example given in your wiki link (x0=11/24), I get:
>> y = dyadic_rat(11/24,8)
y =
11 11 5 2 1 2 1 2
24 12 6 3 3 3 3 3
If I start with the example given by Rattus Ex Machina (x0=3/(2^6-1)), I also get the same result:
>> y = dyadic_rat(3/63,8)
y =
1 2 4 8 16 11 1 2
21 21 21 21 21 21 21 21

Position matrix and distance from each position

I have created a position matrix which I am happy with, and for each position (or element) of this matrix, I want to calculate the positional distance between all other positions in the matrix. This way i can obtain the direction each other element is from another. I have tried to do this in the following way:
pos = [X(:),Y(:),Z(:)];
for j = 1:length(pos)
for i = 1:length(pos)
vecdir(i,:,:) = pos(i,:,:) - pos(j,:,:);
end
v(i) = {vecdir};
i = i+1;
end
where each cell holds the positional distance per position in the position matrix. v(i) only seems to store the last calculation (i.e. all cells are empty apart from the last cell which holds the correct information for the last position on the position matrix.). Where am I going wrong here? Also, if there is a more efficient way of doing this then I'd like to know, as I know storing and accessing cell arrays slows programs down a lot.
They're is always pdist2:
dist = pdist2(pos,pos);
which gives the norm of the distance vectors.
In case you also need the distance vectors I'd use something like this:
N = size(pos,1);
v = arrayfun(#(ii) bsxfun(#minus,pos,pos(ii,:)),1:N,'uni',false)
which returns a Nx1 cell array, each cell containing the distance vector of pos(ii,:) to the other positions.
Your code seems to do the same, altough there are some errors; I think you intended to do the following:
N = size(pos,1);
v = cell(N,1);
for j = 1:N
for i = 1:N
vecdir(i,:) = pos(i,:) - pos(j,:);
end
v{j} = vecdir;
end
What are these statements doing at the end of your loop over j ?
v(i) = {vecdir};
i = i+1;
As I read your code, these always set v(length(pos)) to {vecdir} and then add 1 to i. This updated value of i is never used before it is reset (to 1) at the next go round the inner loop.
I can't say that the rest of your code is OK, I'm not sure I follow your question entirely, but these bits smell a bit fishy.
x = repmat(X(:), 1, numel(X));
y = repmat(Y(:), 1, numel(Y));
z = repmat(Z(:), 1, numel(Z));
dst = sqrt((x - x') .^ 2 + (y - y') .^ 2 + (z - z') .^ 2);

How to filter data within certain threshold in Matlab?

To remove data above 1.2 and below -1.2.
I use the following function:
threshold = [-1.2, 1.2];
y = rmoutliers(y,'percentiles',threshold);
But error occurred:
Error using isoutlier>parseinput (line 236)
'Percentiles' value must be a sorted 2-element numeric vector with entries between 0 and 100.
Any other functions which can be used to solve the problem?
Removing them is straight forward. Assuming you need to remove the points from both the x and y axis data then,
idx_to_remove = ((y<-1.2)|(y>1.2));
x(idx_to_remove) = [];
y(idx_to_remove) = [];
But do you need to remove them or saturate them to the appropriate limit instead? For saturation x wouldn't change, but you'd do the following to y,
y(y < -1.2) = -1.2;
y(y > 1.2) = 1.2;
If you want to leave the x axis variable unchanged (i.e. the number of elements should stay the same), it would be a good idea to convert the outliers to NaN.
y( abs(y)>1.2 ) = NaN;
If you want to remove the elements, you can use [] instead of NaN.
y( abs(y)>1.2 ) = [];
This condition abs(y)>1.2 tests for an absolute (positive) value greater than 1.2, if your thresholds were different then you could test them separately
y( y > 1.2 | y < -1.2 ) = NaN;