Conditional mapping in GAMS - mapping

Consider the following data in GAMS:
set i / 1,2,3 /
j / 1,2,3 /;
parameter stock(i,j);
stock(i,j) = 10;
Consider the following mapping:
set jagg / b1,b2 /
map2(j,jagg) / 1.b1, 2.b1, 3.b2, 4.b2 /;
I can easily mapping using:
parameter stockagg(i,jagg);
stockagg(i,jagg) = sum(map2(j,jagg),stock(i,j));
However, I don't want to map if set i is equal to set j.
That is, I want the following data as my result:
1 1 10
1 b1 10
1 b2 20
2 b1 10
2 2 10
2 b2 20
3 b1 20
3 3 10
3 b2 10
4 b1 20
4 b2 10
4 4 10
Is there an easy way to do that in GAMS?

Not sure, if I got your question completely right, but this give you the result you posted:
set i / 1,2,3,4 /
j / 1,2,3,4,b1,b2 /;
Alias(j,jj);
parameter stock(i,j);
stock(i,j) = 10;
set jagg(j) / b1,b2 /
map2(j,jj) / 1.b1, 2.b1, 3.b2, 4.b2 /;
parameter stockagg(i,j);
stockagg(i,j) = sum(map2(jj,jagg(j))$(not sameas(i,jj)),stock(i,j))$(not sameas(i,j))
+ stock(i,j) $( sameas(i,j));
display stockagg;

Related

Why does SCAN/LAMBDA give unexpected results?

It is very possible that I dont understand the lambda logic or do I? I have dataset A2:A5 like:
1
3
6
10
If I do: =SCAN(0, A2:A5, LAMBDA(aa, bb, aa+bb)) i get:
1
4
10
20
If I do: =SCAN(0, A2:A5, LAMBDA(aa, bb, ROW(bb)-1)) I get
1
2
3
4
if I run: =SCAN(0, A2:A5, LAMBDA(aa, bb, (aa+bb)*(ROW(bb)-1))) the result is
1
8
42
208
Why there is 42 and 208 ? How this results in such values? How can it be 42 and 208 ?
Expected result is
1
8
30
80
And I can get it with:
=ArrayFormula(SCAN(0, A2:A5, LAMBDA(aa, bb, aa+bb))*(ROW(A2:A5)-1))
But not with
=SCAN(0, A2:A5, LAMBDA(aa, bb, (aa+bb)*(ROW(bb)-1)))
SCAN is a great intermediate results function. To understand how SCAN operates, you need to understand how REDUCE operates. The syntax is:
=REDUCE(initial_value, array, LAMBDA(accumulator, current_value, some_function()))
Going through =SCAN(0, A2:A5, LAMBDA(aa, bb, (aa+bb)*(ROW(bb)-1))) step by step,
A2:A5 is 1,3,6,10
Step 1:
aa = 0(initial_value)
bb = 1(current_value:A2)
Result((aa+bb)*(ROW(bb)-1)): (0+1)*(2-1)=1
Step 2:
aa = 1(accumulator(previous return value))
bb = 3(current_value:A3)
Result((aa+bb)*(ROW(bb)-1)): (1+3)*(3-1)=8
Step 3:
aa = 8(accumulator(previous return value))
bb = 6(current_value:A4)
Result((aa+bb)*(ROW(bb)-1)): (8+6)*(4-1)=42
Step 4:
aa = 42(accumulator(previous return value))
bb = 10(current_value:A5)
Result((aa+bb)*(ROW(bb)-1)): (42+10)*(5-1)=52*4=208
aa stores the result of the previous calculation, so you have:
above answers pretty much contain all so I will add only this:
you probably expected that by doing (aa+bb)*(ROW(bb)-1) you will get:
(aa+bb)
*
(ROW(bb)-1)
1
*
1
=
1
4
*
2
=
8
10
*
3
=
30
20
*
4
=
80
but that's not how it works. to get your expected result and by not using your formula where ROW is outside of SCAN:
=ArrayFormula(SCAN(0, A2:A5, LAMBDA(aa, bb, aa+bb))*(ROW(A2:A5)-1))
you would need to do:
=INDEX(MAP(SCAN(0, A2:A5, LAMBDA(aa, bb, (aa+bb))), ROW(A2:A5)-1, LAMBDA(cc, dd, cc*dd)))
where cc is the entire SCAN and dd is ROW(A2:A5)-1 eg. first do the running total and then multiplication, which is not so feasible length-wise.
or shorter but with SEQUENCE:
=MAP(SCAN(0, A2:A5, LAMBDA(aa, bb, (aa+bb))), SEQUENCE(4), LAMBDA(cc, dd, cc*dd))

Round negative values to zero in influx query?

I'm trying to set a lower bounds of zero on my influx query result so that negative values are replaced with zero in the result. e.g. For the query:
SELECT x from measurement
If my raw response is
time x
---- -
1632972969471900180 0
1632972969471988621 -130
1632972969472238055 803
then i want to alter the query so that the result is:
time x'
---- -
1632972969471900180 0
1632972969471988621 0
1632972969472238055 803
My solution was to use the ABS absolute value function, adding the absolute value to the original value and dividing by 2. This maps negative values to zero and leaves posiive (and zero) values unchanged. e.g.
SELECT (x + ABS(x)) / 2 from measurement
time x x'
---- - -
1632972969471900180 0 = 0 + 0 / 2 = 0
1632972969471988621 -130 = -130 + 130 / 2 = 0
1632972969472238055 803 = 803 + 803 / 2 = 803

How to take all values from a single cell

I have the following data
X f1 f2 f3
1 20 20/5/2 3
2 0 10/5/0 7
3 15 20/2/1 3
4 30 80/0/9 3
I want to make SUM() of all values in f2 column but it gives me an error because of the /.
How can I take each value, separately?
Plus, how to get each relative percentage of each cell in f2? For example, the first cell of f2 would be 74,07 / 18,52 / 7,41 taken from doing (20/27 - 5/27- 2/27)
use:
=INDEX(SUM(IFERROR(SPLIT(F1:F; "/"); 0)*1))
update:
=ARRAYFORMULA(IF(C1:C="";;SUBSTITUTE(FLATTEN(QUERY(TRANSPOSE(ROUND(
IFERROR(SPLIT(C1:C; "/")/MMULT(1*IFERROR(SPLIT(C1:C; "/"));
SEQUENCE(COLUMNS(SPLIT(C1:C; "/")); 1;;)^0))*100; 2));;9^9)); " "; " / ")))

How to apply function across each row and one of the parameters passed in is a table

I want to create a column that checks to see that each row of a table can be found in another table using 3 column ids. x, y and z are the columns of the table and transferrable is the second table
I tried this:
elligibleCrossMarginTransfers:{[x;y;z;transferrable]
potentialTransfers: select from transferrable where marginPctPost>collateralUpperLimitPct,not crossMargin;
if[1<count select from potentialTransfers where client=x, primeBroker=y,parentPortfolioId=z;
:1b]; //determine if parentPortfolio of crossMargin exists as possible transfer from other non-cross Margin counts
:0b
};
crossMarginNegExcess:update elligibleToTransfer:elligibleCrossMarginTransfers'[client;primeBroker;parentPortfolioId;transferrable] from crossMarginNegExcess
Are you looking for something like this?
q)0N!t:flip `a`b`c!(`a`b`c;1 2 3;10 20 30)
+`a`b`c!(`a`b`c;1 2 3;10 20 30)
a b c
------
a 1 10
b 2 20
c 3 30
q)0N!t2:flip `a`b`c!(`a`B`c;1 -2 3;10 -20 30)
+`a`b`c!(`a`B`c;1 -2 3;10 -20 30)
a b c
--------
a 1 10
B -2 -20
c 3 30
q)t[`elligibleToTransfer]:(`a`b#t) in `a`b#t2
q)t
a b c elligibleToTransfer
--------------------------
a 1 10 1
b 2 20 0
c 3 30 1
q)
updating with two examples you can attempt on your data (provide some samples for more complete answer)
crossMarginNegExcess[`elligibleToTransfer]:(`client`primeBroker`parentPortfolioId#crossMarginNegExcess) in select client,primeBroker,parentPortfolioId from transferrable where marginPctPost>collateralUpperLimitPct,not crossMargin
//all qsql
update elligibleToTransfer:1b from `crossMarginNegExcess where ([]client;primeBroker;parentPortfolioId) in select client,primeBroker,parentPortfolioId from transferrable where marginPctPost>collateralUpperLimitPct,not crossMargin

Extracting sampled Time Points

I have a matlab Curve from which i would like to plot and find Concentration values at 17 different time samples
Following is the curve from which i would like to extract Concentration values at 17 different time points
following are the time points in minutes
t = 0,0.25,0.50,1,1.5,2,3,4,9,14,19,24,29,34,39,44,49. minutes samples
Following is the Function which i have written to plot the above graph
function c_t = output_function_constrainedK2(t, a1, a2, a3,b1,b2,b3,td, tmax,k1,k2,k3)
K_1 = (k1*k2)/(k2+k3);
K_2 = (k1*k3)/(k2+k3);
DV_free= k1/(k2+k3);
c_t = zeros(size(t));
ind = (t > td) & (t < tmax);
c_t(ind)= conv(((t(ind) - td) ./ (tmax - td) * (a1 + a2 + a3)),(K_1*exp(-(k2+k3)*t(ind)+K_2)),'same');
ind = (t >= tmax);
c_t(ind)= conv((a1 * exp(-b1 * (t(ind) - tmax))+ a2 * exp(-b2 * (t(ind) - tmax))) + a3 * exp(-b3 * (t(ind) - tmax)),(K_1*exp(-(k2+k3)*t(ind)+K_2)),'same');
plot(t,c_t);
axis([0 50 0 1400]);
xlabel('Time[mins]');
ylabel('concentration [Mbq]');
title('Model :Constrained K2');
end
If possible, Kindly please suggest me some idea how i could possibly alter the above function so that i can come up with concentration values at 17 different time points stated above
Following are the input values that i have used to come up with the curve
output_function_constrainedK2(0:0.1:50,2501,18500,65000,0.5,0.7,0.3,3,8,0.014,0.051,0.07)
This will give you concentration values at the time points you wanted. You will have to put this inside the output_function_constrainedK2 function so that you can access the variables t and c_t.
T=[0 0.25 0.50 1 1.5 2 3 4 9 14 19 24 29 34 39 44 49];
concentration=interp1(t,c_t,T)

Resources