Minizinc piecewise linear function - minizinc

I have a cost minimization problem.In the problem we have 3 suppliers. They are S1,S2 & S3, where cost is calculated as price x Qty purchased.
Price value for 3 suppliers as follows.
price=[10,15,20]
If I have a decision variable as array[1..3] of var int:purchase where I am going to get the answers from optimization problem from which supplier how many units I need to purchase.
Sample code as follows.
enum suppliers={s1,s2,s3};
int: len_sup=length(suppliers);
set of int:range_sup=1..len_sup;
array[range_sup] of int:price=[10,15,20];
int:demand=40;
array[range_sup] of int:moq=[5,0,5];
array[range_sup] of int:maxoq=[8,20,30];
array[range_sup] of var 0..100:purchase;
constraint sum(i in range_sup)(
purchase[i])=demand
;
constraint forall(i in range_sup)(
purchase[i]>=moq[i] \/ purchase[i]=0
);
constraint forall(i in range_sup)(
purchase[i] <= maxoq[i]
);
var int:cost;
constraint sum(i in range_sup)(
purchase[i]*price[i])=cost;
solve minimize cost;
Now I have a new requirement to embed price discounts for this.This price discount will definitely vary from the qty we purchase.
for this example imagine it is known that from any supplier if we purchase Qty of 1 to 5 then we would get 5% discount (price would decrease from 5%) on the price. If we purchase 6 to 10 we get 10% price discount. If we purchase more than 11 we get 15% price discount.
How do you incorporate this thing to model.Is this using by piecewise linear functions (because it seems like problem becoming non linear)? Can someone show how could this using piecewise linear function?

Perhaps this don't really answer your question, but for some solvers (e.g. Gecode, JaCoP, and OptiMathSAT) you can use a lookup table for this.
You can add a simple discount table:
array[1..3,1..3] of float: discount = array2d(1..3,1..3,
[
1,5,0.05, % between 1 and 5: 5% discount
6,10,0.10, % between 6 and 10: 10% discount
11,1000,0.15, % 11.. 5: 15% discount
]);
and change the cost constraint to
constraint
cost >= 0 /\
cost =
sum(i in range_sup) (
purchase[i]*price[i]
% lookup the discount
- purchase[i]*price[i]*sum(r in 1..3) (
discount[r,3]*(purchase[i] >= discount[r,1] /\
purchase[i] <= discount[r,2]
)
;
The optimal solution will then be
purchase = array1d(1..3, [8, 20, 12]);
cost = 531;
As mentioned earlier, this works only for solvers that support var float variables and also the non linear float_times.
Update: suresh_chinthy asked about piecewise_linear. Here's an example how to use it. Note that it will work with Gecode, JaCoP, OptiMathSAT, but not with linear solvers such as CBC since piecewise_linear returns a var float which is multiplied with the decision variable purchase[i] (which is var inte) and this is not allowed in CBC.
Change the discount table from the code above, with these two arrays. Here we assume that it's possible to buy between 0 and 40 items.
% the amount of purchase
array[0..40] of float: discount_base = array1d(0..40,[i | i in 0..40]);
% the discounts for each purchase
array[0..40] of float: discount =
array1d(0..40,
[0.0, % 0
0.05, 0.05, 0.05, 0.05, 0.05, % 1-5
0.10,0.10,0.10,0.10,0.10, % 6-10,
0.15,0.15,0.15,0.15,0.15,0.15,0.15,0.15,0.15,0.15, % 11-20
0.15,0.15,0.15,0.15,0.15,0.15,0.15,0.15,0.15,0.15, % 21-30
0.15,0.15,0.15,0.15,0.15,0.15,0.15,0.15,0.15,0.15, % 31-40
]);
And the cost constraint is changed to
constraints
cost > 0 /\
cost =
sum(i in range_sup) (
purchase[i]*price[i] - purchase[i]*price[i]* piecewise_linear(1.0*purchase[i], discount_base, discount)
);
The result is the same as above:
purchase = array1d(1..3, [8, 20, 12]);
cost = 531;

Related

Calculating accuracy for multi-class classification

Consider a three class classification problem with the following confusion matrix.
cm_matrix =
predict_class1 predict_class2 predict_class3
______________ ______________ ______________
Actual_class1 2000 0 0
Actual_class2 34 1966 0
Actual_class3 0 0 2000
Multi-Class Confusion Matrix Output
TruePositive FalsePositive FalseNegative TrueNegative
____________ _____________ _____________ ____________
Actual_class1 2000 34 0 3966
Actual_class2 1966 0 34 4000
Actual_class3 2000 0 0 4000
The formula that I have used are:
Accuracy Of Each class=(TP ./total instances of that class)
( formula based on an answer here: Individual class accuracy calculation confusion)
Sensitivity=TP./TP+FN ;
The implementation of it in Matlab is:
acc_1 = 100*(cm_matrix(1,1))/sum(cm_matrix(1,:)) = 100*(2000)/(2000+0+0) = 100
acc_2 = 100*(cm_matrix(2,2))/sum(cm_matrix(2,:)) = 100*(1966)/(34+1966+0) = 98.3
acc_3 = 100*(cm_matrix(3,3))/sum(cm_matrix(3,:)) = 100*(2000)/(0+0+2000) = 100
sensitivity_1 = 2000/(2000+0)=1 = acc_1
sensitivity_2 = 1966/(1966+34) = 98.3 = acc_2
sensitivity_3 = 2000/2000 = 1 = acc_3
Question1) Is my formula for Accuracy of each class correct? For calculating accuracy of each individual class, say for positive class I should take the TP in the numerator. Similarly, for accuracy of only the negative class, I should consider TN in the numerator in the formula for accuracy. Is the same formula applicable to binary classification? Is my implementation of it correct?
Question2) Is my formula for sensitivity correct? Then how come I am getting same answer as individual class accuracies?
Question1) Is my formula for Accuracy of each class correct?
No, the formula you're using is for the Sensitivity (Recall). See below.
For calculating accuracy of each individual class, say for positive class I should take the TP in the numerator. Similarly, for accuracy of only the negative class, I should consider TN in the numerator in the formula for accuracy. Is the same formula applicable to binary classification? Is my implementation of it correct?
Accuracy is the ratio of the number of correctly classified instances to the total number of instances. TN, or the number of instances correctly identified as not being in a class, are correctly classified instances, too. You cannot simply leave them out.
Accuracy is also normally only used for evaluating the entire classifier for all classes, not individual classes. You can, however, generalize the accuracy formula to handle individual classes, as done here for computing the average classification accuracy for a multiclass classifier. (See also the referenced article.)
The formula they use for each class is:
As you can see, it is identical to the usual formula for accuracy, but we only take into account the individual class's TP and TN scores (the denominator is still the total number of observations). Applying this to your data set, we get:
acc_1 = (2000+3966)/(2000+34+0+3966) = 0.99433
acc_2 = (1966+4000)/(1966+0+34+4000) = 0.99433
acc_3 = (2000+4000)/(2000+0+0+4000) = 1.00000
This at least makes more intuitive sense, since the first two classes had mis-classified instances and the third did not. Whether these measures are at all useful is another question.
Question2) Is my formula for sensitivity correct?
Yes, Sensitivity is given as:
TP / TP+FN
which is the ratio of the instances correctly identified as being in this class to the total number of instances in the class. In a binary classifier, you are by default calculating the sensitivity for the positive class. The sensitivity for the negative class is the error rate (also called the miss rate or false negative rate in the wikipedia article) and is simply:
FN / TP+FN === 1 - Sensitivity
FN is nothing more than the TP for the negative class! (The meaning of TP is likewise reversed.) So it is natural to extend this to all classes as you have done.
Then how come I am getting same answer as individual class accuracies?
Because you're using the same formula for both.
Look at your confusion matrix:
cm_matrix =
predict_class1 predict_class2 predict_class3
______________ ______________ ______________
Actual_class1 2000 0 0
Actual_class2 34 1966 0
Actual_class3 0 0 2000
TP for class 1 is obviously 2000
cm_matrix(1,1)
FN is the sum of the other two columns in that row. Therefore, TP+FN is the sum of row 1
sum(cm_matrix(1,:)
That's exactly the formula you used for the accuracy.
acc_1 = 100*(cm_matrix(1,1))/sum(cm_matrix(1,:)) = 100*(2000)/(2000+0+0) = 100
Answer to question 1. It seems that accuracy is used only in binary classification, check this link.
You refer to an answer on this site, but it concerns also a binary classification (i.e. classification into 2 classes only). You seem to have more than two classes, and in this case you should try something else, or a one-versus-all classification for each class (for each class, parse prediction for class_n and non_class_n).
Answer to question 2. Same issue, this measure is appropriate for binary classification which is not your case.
The formula for sensitivity is:
TP./(TP + FN)
The formula for accuracy is:
(TP)./(TP+FN+FP+TN)
See the documentation here.
UPDATE
And if you wish to use the confusion matrix, you have:
TP on the diagonal, at the level of the class
FN the sum of all the values in the column of the class. In the function getvalues start counting lines from the declaration of the function and check lines 30 and 31:
TP(i)=c_matrix(i,i);
FN(i)=sum(c_matrix(i,:))-c_matrix(i,i);
FP(i)=sum(c_matrix(:,i))-c_matrix(i,i);
TN(i)=sum(c_matrix(:))-TP(i)-FP(i)-FN(i);
If you apply the accuracy formula, you obtain, after calculating and simplifying :
accuracy = c_matrix(i,i) / sum(c_matrix(:))
For the sensitivity you obtain, after simplifying:
sensitivity = c_matrix(i,i) / sum(c_matrix(i,:))
If you want to understand better, just check the links I sent you.

MATLAB: how to loop through my vector and round up or down

I have to write up a code whereby I use Mean-variance optimization to rebalance my portfolio for 12 months (one year). The only thing is that I have to determine how I will round my number of assets after each rebalancing. When I round, I need to see if the difference between my new portfolio value (after subtracting transaction costs) and my old portfolio value is positive, up to a set limit of about $3000.00.
For example, my initial number of assets was:
x_int = [4500, 6000, 0, 0, 0, 500, 1550, 0, 1000, 0];
My new rebalanced number of assets for the first period was:
x_new = [2490.67, 4401.78, 1502.30, 0, 1010.45, 2803.85, 3489.77, 0, 650.98, 1001.87];
My initial portfolio value was $1,897,560.30
My rebalanced portfolio value for the first period came out as $1,658,923.76 (after I rounded all my asset numbers down) and as $2,001,876.95 (after I rounded all my asset numbers up).
Is there a way to loop through my x_new values, round up and/or down each individual number of assets and check to see if my rounded assets will give me a new portfolio value that, when I subtract from the initial portfolio value will satisfy my criteria
Thanks!
Since there would generally be more than one ways of adjusting the portfolio to
meet the criterion, the answer would depend on what kind of adjustments you prefer. The following approach starts with rounding to nearest integer and then, if required to meet the budget, rounds some of the stocks to the opposite direction.
Let,
price be a vector the same size as x_new and represent the unit share price.
budget be the upper limit of the new portfolio value (i.e old portfolio value + 3000 + transaction costs).
Firstly, let's round the new portfolio stocks to nearest integer and compute the cost.
x_rnd = round(x_new);
cost_rnd = x_rnd * price';
Depending on whether cost_rnd is above or below budget we would tweak the number of individual shares. If cost_rnd is under-budget, we would try to round-up some of the stocks that were rounded-down. Similarly, if cost_rnd is over-budget we would change some of the roundings from up to down.
cost_rnd = x_rnd * price';
if (cost_rnd > budget) % exceeds budget, so we need to round a few of them down
x_adjust_dir = floor(x_new)-x_rnd;
cum_adjust_cost = cost_rnd + cumsum(x_adjust_dir .* price);
n_adjust = find(cum_adjust_cost < budget, 1, 'first');
elseif (cost_rnd < budget) % under-budget, so we should round a few of them up
x_adjust_dir = ceil(x_new)-x_rnd;
cum_adjust_cost = cost_rnd + cumsum(x_adjust_dir .* price);
n_adjust = find(cum_adjust_cost < budget, 1, 'last');
else % by some miracle the budget is exactly met
n_adjust = [];
end
Note that some elements of x_adjust_dir would be zeros. They represent the shares that are already rounded in the right direction. The remaining elements would be -1 for over-budget case and 1 for under-budget case. cum_adjust_cost is the cumulative change due to the rounding adjustments. n_adjust is the index of the cumulative adjustment that puts the adjusted cost just below the budget.
Now all that remains is to apply the adjustments:
x_final = x_rnd;
if ~isempty(n_adjust)
x_final(1:n_adjust) = x_final(1:n_adjust) + x_adjust_dir(1:n_adjust);
end
x_final is the adjusted portfolio that meets the criterion.

Implied Volatility in Matlab

I'm trying to calculate the implied volatility using the Black-Scholes formula in Matlab (2012b), but somehow have problems with some strike prices.
For instance blsimpv(1558,1440,0.0024,(1/12),116.4) will return NaN.
I thought it probably would be some problem with the function and therefore searched the internet for some other matlab scripts and customized it to my custom needs, but unfortunately I'm still not able to return a valid implied volatility.
function sigma=impvol(C,S,K,r,T)
%F=S*exp((r).*T);
%G=C.*exp(r.*T);
%alpha=log(F./K)./sqrt(T);
%beta=0.5*sqrt(T);
%a=beta.*(F+K);
%b=sqrt(2*pi)*(0.5*(F-K)-G);
%c=alpha.*(F-K);
%disc=max(0,b.^2-4*a.*c);
%sigma0=(-b+sqrt(disc))./(2*a);
i=-1000;
while i<=5000
sigma0=i/1000;
sigma=NewtonMethod(sigma0);
if sigma<=10 && sigma>=-10
fprintf('This is sigma %f',sigma)
end
i=i+1;
end
end
function s1=NewtonMethod(s0)
s1=s0;
count=0;
f=#(x) call(S,K,r,x,T)-C;
fprime=#(x) call_vega(S,K,r,x,T);
max_count=1e4;
while max(abs(f(s1)))>1e-7 && count<max_count
count=count+1;
s0=s1;
s1=s0-f(s0)./fprime(s0);
end
end
end
function d=d1(S,K,r,sigma,T)
d=(log(S./K)+(r+sigma.^2*0.5).*(T))./(sigma.*sqrt(T));
end
function d=d2(S,K,r,sigma,T)
d=(log(S./K)+(r-sigma.^2*0.5).*(T))./(sigma.*sqrt(T));
end
function p=Phi(x)
p=0.5*(1.+erf(x/sqrt(2)));
end
function p=PhiPrime(x)
p=exp(-0.5*x.^2)/sqrt(2*pi);
end
function c=call(S,K,r,sigma,T)
c=S.*Phi(d1(S,K,r,sigma,T))-K.*exp(-r.*(T)).*Phi(d2(S,K,r,sigma,T));
end
function v=call_vega(S,K,r,sigma,T)
v=S.*PhiPrime(d1(S,K,r,sigma,T)).*sqrt(T);
end
Running impvol(116.4,1558,1440,0.0024,(1/12)) will however unfortunately return the value 'Inf'. There somehow is a problem with the Newton-Rhapson method not converging but I am kind of clueless how to solve this. Does anyone know how to solve this problem or know some other way how to calculate the implied volatility?
Thank u in advance already for your help!
Kind regards,
Henk
I would definitely suggest this code: Fast Matrixwise Black-Scholes Implied Volatility
It is able to compute the entire surface in one shot and - my experience - I found it much more reliable than blsimpv() or impvol() which are other functions implemented in matlab.
Newton-Rhapson method does not work well for implied volatility. You should use the bisection method (not sure how it is used in Matlab). It is described in http://en.wikipedia.org/wiki/Bisection_method. For completeness, it works this way:
1) Pick an arbitrary high (impossible) volatility like high=200%/year.
2) Pick lowest possible volatility (low=0%).
2a) Calculate option premium for 0% volatility, if actual premium is lower than that, it means negative volatility (which is "impossible").
3) While implied volatility is not found:
3.1) If "high" and "low" are very near (e.g. equal up to 5th decimal), either one is your implied volatility. If not...
3.2) Calculate average between "high" and "low". avg=(high+low)/2
3.3) Calculate option premium for avg volatility.
3.4) If actual premium is higher then p(avg), make min=avg, because implied volatility must lie between avg and max.
3.4a) If actual premium is lower than p(avg), make max=avg, because implied vol must lie between min and avg.
The main disvantage of bisect is that you have to pick a maximum value, so your function won't find implied volatilities bigger than that. But something like 200%/year should be high enough for real-world usage.
I use yet another method more like Newton's method, hence not limited to a range, since vega is a derivative, but with a "linearization" fix to avoid hunting and failure due to small vegas:
def implied_volatility(type, premium, S, K, r, s_dummy, t):
if S <= 0.000001 or K <= 0.000001 or t <= 0.000001 or premium <= 0.000001:
return 0.0
s = 0.35
for cycle in range(0, 120):
ext_premium = type(S, K, r, s, t)
if abs(premium - ext_premium) < 0.005:
return s
ext_vega = type.vega(S, K, r, s, t)
# print S, K, r, s, t, premium, ext_premium, ext_vega
if ext_vega < 0.0000001:
# Avoids zero division if stuck
ext_vega = 0.0000001
s_new = s - (ext_premium - premium) / ext_vega
if abs(s_new - s) > 1.00:
# estimated s is too different from previous;
# it is better to go linearly, since
# vega is too small to give a good guess
if s_new > s:
s += 1.0
else:
s -= 1.0
else:
s = s_new
if s < 0.0:
# No volatility < 0%
s = 0.0001
if s > 99.99:
# No point calculating volatilities > 9999%/year
return 100.0
return 0.0
Still, I think that bisect is your best bet.
I created a simple function that conducts a sort of trial and error calculation if the output from blsimpv is NaN. This slows down the computation time significantly for me but it always gives me a desirable result.
The function is shown to be used below
BSIVC(t,i)= blsimpv(S(t,i),K,r,tau(t),HestonCiter(t,i))
if isnan(BSIVC(t,i));
BSIVC(t,i)= secondIVcalc(HestonCiter(t,i),S(t,i),K,r,q,tau(t))
end
The function itself is described below:
function IV= secondIVcalc(HestonC,S,K,r,q,T)
lowCdif = 1;
a=0;
while lowCdif>0.0001
a= a+0.00001
lowCdif = HestonC - BSCprice(S,K,r,q,a,T);
end
IV= a;
end
Please note that BSCprice is not an in-built function in matlab.
Just to make the code clearer-
BSCprice is of the format BSCprice(Underlying Asset Price, Strike Price, interest rate, dividend yield, implied vol, time to maturity).

Cbprice syntax (migrating from Excel to matlab)

I want to value convertible bonds in Matlab using cbprice, but I'm having trouble lining it up with what result from the spreadsheet provided by this answer. This is primarily a cbprice syntax question, I think.
For example, let's value the Intel 2.95 2035 bond using the inputs at the bottom of this question.
The bond is currently trading around 112.
Plugging into the excel spreadsheet, I get around 106. Pretty good.
Now, I'd like to do the same calculation using Matlab:
% CbMatrix = cbprice(RiskFreeRate, StaticSpread, Sigma, Price, ConvRatio, ...
% NumSteps, IssueDate, Settle, Maturity, CouponRate)
>> CbMatrix = cbprice(0.03, 0.00575, 0.236, 24.49, 34.24, ...
100, '30-Mar-2006', '20-Jun-2013', '15-Dec-2035', 0.0295);
>> disp(CbMatrix(1, 1) * 0.1)
88.3347
I wasn't sure how I should give the dividend yield to cbprice, but the spreadsheet gives a price near 132 for a zero dividend yield for comparison.
I expect a number closer to 110, at least above 100.
How can I reproduce the calculation using cbprice?
Spreadsheet inputs:
Bond info: Stock info: Pricing Info
Pricing Date: 6/20/2013 Current Price: 24.49 Risk Free Rate: 0.03
Maturity Date: 12/15/2035 Dividend Yield: 0.0453 Credit Spread: 0.00575
Face Value: 1000 Volatility: 0.236 Number of steps: 100
Conversion Ratio: 34.24
Coupon (%): 2.95
Frequency: 2
Communicating with the Matlab folks, they clarified that it implicitly uses a $100 face value for the bond. The conversion ratio needs to be adjusted accordingly.
The dividend yield has been specified as well in the last two lines of the invocation.
% CbMatrix = cbprice(RiskFreeRate, StaticSpread, Sigma, Price, ...
% ConvRatio, ...
% NumSteps, IssueDate, Settle, Maturity, CouponRate, ...)
>> CbMatrix = cbprice(0.03, 0.00575, 0.236, 24.49, ...
34.24 * 100 / 1000, ... % changed here
100, '30-Mar-2006', '20-Jun-2013', '15-Dec-2035', 0.0295, ...
'DividendType', 2, ...
'DividendInfo', [datenum('20-Jun-2013') 0.0453]);
>> CbMatrix(1,1)
ans =
107.3614

Understanding T-SQL stdev, stdevp, var, and varp

I'm having a difficult time understand what these statistics functions do and how they work. I'm having an even more difficult time understanding how stdev works vs stdevp and the var equivelant. Can someone please break these down into dumb for me?
In statistics Standard Deviation and Variance are measures of how much a metric in a population deviate from the mean (usually the average.)
The Standard Deviation is defined as the square root of the Variance and the Variance is defined as the average of the squared difference from the mean, i.e.:
For a population of size n: x1, x2, ..., xn
with mean: xmean
Stdevp = sqrt( ((x1-xmean)^2 + (x2-xmean)^2 + ... + (xn-xmean)^2)/n )
When values for the whole population are not available (most of the time) it is customary to apply Bessel's correction to get a better estimate of the actual standard deviation for the whole population. Bessel's correction is merely dividing by n-1 instead of by n when computing the variance, i.e:
Stdev = sqrt( ((x1-xmean)^2 + (x2-xmean)^2 + ... + (xn-xmean)^2)/(n-1) )
Note that for large enough data-sets it won't really matter which function is used.
You can verify my answer by running the following T-SQL script:
-- temporary data set with values 2, 3, 4
declare #t table([val] int);
insert into #t values
(2),(3),(4);
select avg(val) as [avg], -- equals to 3.0
-- Estimation of the population standard devisation using a sample and Bessel's Correction:
-- ((x1 - xmean)^2 + (x2 - xmean)^2 + ... + (xn-xmean)^2)/(n-1)
stdev(val) as [stdev],
sqrt( (square(2-3.0) + square(3-3) + square(4-3))/2) as [stdev calculated], -- calculated with value 2, 3, 4
-- Population standard deviation:
-- ((x1 - xmean)^2 + (x2 - xmean)^2 + ... + (xn-xmean)^2)/n
stdevp(val) as [stdevp],
sqrt( (square(2-3.0) + square(3-3) + square(4-3))/3) as [stdevp calculated] -- calculated with value 2, 3, 4
from #t;
Further reading wikipedia articles for: standard deviation and Bessel's Correction.
STDDEV is used for computing the standard deviation of a data set. STDDEVP is used to compute the standard deviation of a population from which your data is a sample.
If your input is the entire population, then the population standard deviation is computed with STDDEV. More typically, your data set is a sample of a much larger population. In this case the standard deviation of the data set would not represent the true standard deviation of the population since it will usually be biased too low. A better estimate for the standard deviation of the population based on a sample is obtained with STDDEVP.
The situation with VAR and VARP is the same.
For a more thorough discussion of the topic, please see this Wikipedia article.