AMPL: Syntax for sets? - set

I'm spinning up on high level language for mixed integer linear programs (MILPs). The language is A Modeling Language for A Mathematical Programming Language (AMPL).
Chapter 4, page 65, Figure 4-7 shows the following syntax:
set PROD := bands coils plate ;
However, Chapter 5, page 74, shows the following syntax:
set PROD = {"bands", "coils", "plate"};
Can anyone please explain this difference in syntax?
I put the latter into a *.dat file, and AMPL complains expected ; ( : or symbol where the { is. Wondering if it is just a mistake in the manual.
Thanks.

The syntax in Chapter 4 --
set PROD := bands coils plate;
-- is used in data files, while the syntax in Chapter 5 --
set PROD = {"bands", "coils", "plate"};
-- is used in model files. It's a little weird (IMO) that the syntax for sets is different in model and data files, but it is. For another example of this difference, see this question and answer.
Complete working example code modified from AMPL manual
Added by the original poster of the question.
dietu.mod:
# dietu.mod
#----------
# set MINREQ; # nutrients with minimum requirements
# set MAXREQ; # nutrients with maximum requirements
set MINREQ = {"A", "B1", "B2", "C", "CAL"};
set MAXREQ = {"A", "NA", "CAL"};
set NUTR = MINREQ union MAXREQ; # nutrients
set FOOD; # foods
param cost {FOOD} > 0;
param f_min {FOOD} >= 0;
param f_max {j in FOOD} >= f_min[j];
param n_min {MINREQ} >= 0;
param n_max {MAXREQ} >= 0;
param amt {NUTR,FOOD} >= 0;
var Buy {j in FOOD} >= f_min[j], <= f_max[j];
minimize Total_Cost: sum {j in FOOD} cost[j] * Buy[j];
subject to Diet_Min {i in MINREQ}:
sum {j in FOOD} amt[i,j] * Buy[j] >= n_min[i];
subject to Diet_Max {i in MAXREQ}:
sum {j in FOOD} amt[i,j] * Buy[j] <= n_max[i];
The explicit definitions of setes MINREQ and MAXREQ and their members is taken from the *.dat file below (where their definitions have been commented out). Matlab users, observe above & beware that you need commas between members in a set.
dietu.dat:
# dietu.dat
#----------
data;
# set MINREQ := A B1 B2 C CAL ;
# set MAXREQ := A NA CAL ;
set FOOD := BEEF CHK FISH HAM MCH MTL SPG TUR ;
param: cost f_min f_max :=
BEEF 3.19 2 10
CHK 2.59 2 10
FISH 2.29 2 10
HAM 2.89 2 10
MCH 1.89 2 10
MTL 1.99 2 10
SPG 1.99 2 10
TUR 2.49 2 10 ;
param: n_min n_max :=
A 700 20000
C 700 .
B1 0 .
B2 0 .
NA . 50000
CAL 16000 24000 ;
param amt (tr): A C B1 B2 NA CAL :=
BEEF 60 20 10 15 938 295
CHK 8 0 20 20 2180 770
FISH 8 10 15 10 945 440
HAM 40 40 35 10 278 430
MCH 15 35 15 15 1182 315
MTL 70 30 15 15 896 400
SPG 25 50 25 15 1329 370
TUR 60 20 15 10 1397 450 ;
Solve the model using the following at the AMPL prompt:
reset data;
reset;
model dietu.mod;
data dietu.dat;
solve;

Related

How to write a program in gwbasic for adding the natural numbers for 1 to 100?

I am trying to write a program for adding the natural numbers from 1 to n (1 + 2 + 3 + ... + n). However, the sum appears 1 when I use if statement. And when I use for-next statement there is a syntax error that I don't understand.
if:
30 let s = 0
40 let i = 1
50 s = s + i
60 i = i + 1
70 if i<=n, then goto 50
80 print s
for-next:
30 let i, s
40 s = 0
50 for i = 1 to n
60 s = s + i
70 next i
80 print n
When I take n = 10, the if statement code gives a result of 1, but it should be 55.
When I try to use the for-next statement, it gives no result saying that there is a syntax error in 30.
Why is this happening?
The following code works in this online Basic interpreter.
10 let n = 100
30 let s = 0
40 let i = 1
50 s = s + i
60 i = i + 1
70 if i <= n then goto 50 endif
80 print s
I initialised n on the line labelled 10, removed the comma on the line labelled 70 and added an endif on the same line.
This is the for-next version:
30 let n = 100
40 let s = 0
50 for i = 1 to n
60 s = s + i
70 next i
80 print s
(btw, the sum of the first n natural numbers is n(n+1)/2:
10 let n = 100
20 let s = n * (n + 1) / 2
30 print s
)
Why is this happening? Where am I mistaking?
30 let s = 0
40 let i = 1
50 s = s + i
60 i = i + 1
70 if i<=n, then goto 50
80 print s
Fix #1: Initialize variable 'n':
20 let n = 10
Fix #2: Remove comma from line 70:
70 if i<=n then goto 50
30 let i, s
40 s = 0
50 for i = 1 to n
60 s = s + i
70 next i
80 print n
Fix #1: Initialize variable 'n':
30 let n = 10
Fix #2: Print 's' instead of 'n':
80 print s
10 cls
20 let x=1
30 for x=1 to 100
40 print x
50 next x
60 end

AMPL syntax error

I'm learnig to use AMPL and I wrote the next script
# Problema 2
set P #plantas
set PI #puntos intermedios
set CD # centros de distribucion
set O # origenes
set D # destinos
param coste {i in O , j in D}
param produc {k in P}
param capac {l in PI}
param requiere {m in CD}
var cantidad{O,D}>==0;
check: sum{k in P} produc[k] <= sum{m in CD} requiere[m];
minimize costo_transporte: sum{i in O, j in D} coste[i,j]*cantidad[i,j];
subject to restriccion_produccion{k in P}:
sum{j in D}cantidad[k,j]<=produc[k];
subject to restriccion_intermedio_entrada{l in PI}:
sum{i in O}cantidad[i,l]<=capac[l];
subject to resctriccion_intermedio_salida{l in PI}:
sum{i in O}cantidad[i,j] - sum{j in D}cantidad[l,j]>=0;
subject to restriccion_demanda{m in CD}:
sum{i in O}cantidad[i,m]=requiere[m];
with the next data file
set P:= Rancagua SanPablo Bogota;
set PI:= Lima Mendoza;
set CD:= Santiago RiodeJaneiro Quito Caracas;
set O:= Rancagua SanPablo Bogota Santiago Lima Mendoza;
set D:= Santiago RiodeJaneiro Quito Caracas Lima Mendoza;
param coste:
Santiago RiodeJaneiro Quito Caracas Lima Mendoza:=
Rancagua 3 20 30 30 10 6
SanPablo 15 5 35 40 20 12
Bogota 45 25 10 12 25 30
Santiago 0 15 30 48 12 10
Lima 12 22 8 30 0 15
Mendoza 10 15 12 35 15 0;
param produc:=
Rancagua 300
SanPablo 250
Bogota 200;
param capac:=
Lima 150
Mendoza 180;
param requiere:=
Santiago 120
RiodeJaneiro 300
Quito 80
Caracas 200;
But when I charge the mod file, AMPL print
ampl: model 'C:\Users\Laura\Desktop\Monserrat\P2\problema2.mod';
C:\Users\Laura\Desktop\Monserrat\P2\problema2.mod, line 3 (offset 30):
syntax error
I reviewed the code, but I don't understand what is the error.
Please! Help me.
You have to end the line with a semicolon ; also for the definition of the sets and the parameters, and not just for the variables and equations.

Obtaining opposite diagonal of a matrix in Matlab

Let A be an matrix of size [n,n]. If I want to extract its diagonal, I do diag(A).
Actually, I want the opposite diagonal, which would be [A(n,1),A(n-1,2),A(n-2,3),...].
One way to do this is via diag(flipud(A)). However, flipud(A) is quite wasteful and multiplies the time it takes by a factor of 10 compared to finding the usual diagonal.
I'm looking for a fast way of obtaining the opposite diagonal. Naturally, for loops seem abysmally slow. Suggestions would be greatly appreciated.
Here is my matrix, produced by A = magic(5)
A =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
s = size(A,1)
A(s:s-1:end-1)
ans =
11 12 13 14 15
Below is a comparison of all the methods mentioned so far, plus a few other variations I could think of. This was tested on 64-bit R2013a using TIMEIT function.
function [t,v] = testAntiDiag()
% data and functions
A = magic(5000);
f = {
#() func0(A) ;
#() func1(A) ;
#() func2(A) ;
#() func3(A) ;
#() func4(A) ;
#() func5(A) ;
#() func6(A) ;
#() func7(A) ;
};
% timeit and check results
t = cellfun(#timeit, f, 'UniformOutput',true);
v = cellfun(#feval, f, 'UniformOutput',false);
assert( isequal(v{:}) )
end
function d = func0(A)
d = diag(A(end:-1:1,:));
end
function d = func1(A)
d = diag(flipud(A));
end
function d = func2(A)
d = flipud(diag(fliplr(A)));
end
function d = func3(A)
d = diag(rot90(A,3));
end
function d = func4(A)
n = size(A,1);
d = A(n:n-1:end-1).';
end
function d = func5(A)
n = size(A,1);
d = A(cumsum(n + [0,repmat(-1,1,n-1)])).';
end
function d = func6(A)
n = size(A,1);
d = A(sub2ind([n n], n:-1:1, 1:n)).';
end
function d = func7(A)
n = size(A,1);
d = zeros(n,1);
for i=1:n
d(i) = A(n-i+1,i);
end
end
The timings (in the same order they are defined above):
>> testAntiDiag
ans =
0.078635867152801
0.077895631970976 % #AlexR.
0.080368641824528
0.195832501156751
0.000074983294297 % #thefourtheye
0.000143019460665 % #woodchips
0.000174679680437
0.000152488508547 % for-loop
The most suprising result to me is the last one. Apparently JIT compilation is very effective on such simple for-loops.
The elements you want are easily obtained by indexing. For example, this should do the trick.
n = 4;
A = magic(n)
A =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
A(cumsum(n + [0,repmat(-1,1,n-1)]))
ans =
4 7 10 13
I could also have used sub2ind to get those element indexes, but this does it a bit more cleanly, though less obvious in how it works.
A = magic(6)
A =
35 1 6 26 19 24
3 32 7 21 23 25
31 9 2 22 27 20
8 28 33 17 10 15
30 5 34 12 14 16
4 36 29 13 18 11
b = diag(A(1:length(A),length(A):-1:1))
b =
24
23
22
33
5
4

Generating random points to build a procedural line

I want to randomly generate points. Well at least there should be a limitation on the y-axis. Later I connect the points to a line which should proceed in a simple animation. You can imagine this as a random walk of a drunken person, going uphill and downhill.
This sounds very simple. I searched around the web and found that this could be accomplished using the markov chain. I think this idea is really interesting.
You can create the first state of your scene by yourself and pass this state as input to the markov chain algorithm. The algorithm randomly changes this state and creates a walk.
However I cannot find any example of that algorithm and no source code. I just found an applet that demonstrates the markov chain algorithm: http://www.probability.ca/jeff/java/unif.html
Please suggest some code. Any other ideas how to accomplish this are appreciated too.
I painted an example
So I want the line to proceed in a similar way. There are valleys, slopes ... they are random but the randomness still apply to the initial state of the line. This is why I found makrov chain so interesting here: http://www.suite101.com/content/implementing-markov-chains-a24146
Here's some code in Lua:
absstepmax = 25
ymin = -100
ymax = 100
x = 0
y = 5
for i = 1, 20 do
y = y + (math.random(2*absstepmax) - absstepmax - 1)
y = math.max(ymin, math.min(ymax, y))
x = x + 5
print (x,y)
end
absstepmax limits the size of a y step per iteration
ymin and ymax limit the extent of y
There is no bias in the example, i.e., y can change symmetrically up or down. If you want your "drunk" tending more "downhill" you can change the offset after the call to random from absstepmax - 1 to absstepmax - 5 or whatever bias you like.
In this example, the x step is fixed. You may make this random as well using the same mechanisms.
Here are some sample runs:
> absstepmax = 25
> ymin = -100
> ymax = 100
> x = 0
> y = 5
> for i = 1, 20 do
>> y = y + (math.random(2*absstepmax) - absstepmax - 1)
>> y = math.max(ymin, math.min(ymax, y))
>> x = x + 5
>> print (x,y)
>> end
5 4
10 22
15 37
20 39
25 50
30 40
35 21
40 22
45 12
50 16
55 16
60 12
65 -1
70 -8
75 -14
80 -17
85 -19
90 -25
95 -37
100 -59
> absstepmax = 25
> ymin = -100
> ymax = 100
> x = 0
> y = 5
> for i = 1, 20 do
>> y = y + (math.random(2*absstepmax) - absstepmax - 1)
>> y = math.max(ymin, math.min(ymax, y))
>> x = x + 5
>> print (x,y)
>> end
5 -2
10 -15
15 -7
20 1
25 1
30 12
35 23
40 45
45 43
50 65
55 56
60 54
65 54
70 62
75 57
80 62
85 86
90 68
95 76
100 68
>
Painted result added from OP:

Generate random points distributed like cities?

How can one generate say 1000 random points with a distribution like that of
towns and cities in e.g. Ohio ?
I'm afraid I can't define "distributed like cities" precisely;
uniformly distributed centres + small Gaussian clouds
are easy but ad hoc.
Added: There must be a family of 2d distributions
with a clustering parameter that can be varied to match a given set of points ?
Maybe you can take a look at Walter Christaller's Theory of Central Places. I guess there must be some generator somewhere, or you can cook up your own.
Start with a model of the water features in your target area (or make one up, if it's for an imaginary place), then cluster the cities near river junctions, along lakeshores, lake-river junctions. Then make imaginary highways connecting those major cities. Now sprinkle some intermediate cities along those highways at reasonable spacing, preferring to be near junctions in the highways. Now sprinkle some small towns through the empty spaces.
Gaussian clusters with Poisson cluster sizes work fairly well.
Problem: generate random points that cluster roughly like given cities, say in the USA.
Subproblems:
a) describe clusters with rows of numbers, so that "cluster A is like cluster B"
simplifies to "clusternumbers(A) is like "clusternumbers(B)".
Running N=100 then 1000 points through fcluster below, with ncluster=25, gives
N 100 ncluster 25: 22 + 3 r 117
sizes: av 4 10 9 8 7 6 6 5 5 4 4 4 ...
radii: av 117 202 198 140 134 64 62 28 197 144 148 132 ...
N 1000 cluster 25: 22 + 3 r 197
sizes: av 45 144 139 130 85 84 69 63 43 38 33 30 ...
radii: av 197 213 279 118 146 282 154 245 212 243 226 235 ...
b) find a combiation of random generators with 2 or 3 parameters
which can be varied to generate different clusterings.
Gaussian clusters with Poisson cluster sizes can match clustering of cities fairly well:
def randomclusters( N, ncluster=25, radius=1, box=box ):
""" -> N 2d points: Gaussian clusters, Poisson cluster sizes """
pts = []
lam = eval( str( N // ncluster ))
clustersize = lambda: np.random.poisson(lam - 1) + 1
# poisson 2: 14 27 27 18 9 4 %
# poisson 3: 5 15 22 22 17 10 %
while len(pts) < N:
u = uniformrandom2(box)
csize = clustersize()
if csize == 1:
pts.append( u )
else:
pts.extend( inbox( gauss2( u, radius, csize )))
return pts[:N]
# Utility functions --
import scipy.cluster.hierarchy as hier
def fcluster( pts, ncluster, method="average", criterion="maxclust" ):
""" -> (pts, Y pdist, Z linkage, T fcluster, clusterlists)
ncluster = n1 + n2 + ... (including n1 singletons)
av cluster size = len(pts) / ncluster
"""
# Clustering is pretty fast:
# sort pdist, then like Kruskal's MST, O( N^2 ln N )
# Many metrics and parameters are possible; these satisfice.
pts = np.asarray(pts)
Y = scipy.spatial.distance.pdist( pts ) # N*(N-1)/2
Z = hier.linkage( Y, method ) # N-1, like mst
T = hier.fcluster( Z, ncluster, criterion=criterion )
clusters = clusterlists(T)
return (pts, Y, Z, T, clusters)
def clusterlists(T):
""" T = hier.fcluster( Z, t ) e.g. [a b a b c a]
-> [ [0 2 5] [1 3] ] sorted by len, no singletons [4]
"""
clists = [ [] for j in range( max(T) + 1 )]
for j, c in enumerate(T):
clists[c].append( j )
clists.sort( key=len, reverse=True )
n1 = np.searchsorted( map( len, clists )[::-1], 2 )
return clists[:-n1]
def radius( x ):
""" rms |x - xmid| """
return np.sqrt( np.mean( np.var( x, axis=0 )))
# * 100 # 1 degree lat/long ~ 70 .. 111 km
In java this is provided through new Random().nextGaussian(). Since the java source is available, you can look at it:
synchronized public double nextGaussian() {
// See Knuth, ACP, Section 3.4.1 Algorithm C.
if (haveNextNextGaussian) {
haveNextNextGaussian = false;
return nextNextGaussian;
} else {
double v1, v2, s;
do {
v1 = 2 * nextDouble() - 1; // between -1 and 1
v2 = 2 * nextDouble() - 1; // between -1 and 1
s = v1 * v1 + v2 * v2;
} while (s >= 1 || s == 0);
double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
nextNextGaussian = v2 * multiplier;
haveNextNextGaussian = true;
return v1 * multiplier;
}
}
Plotting 30000 houses using
x = r.nextGaussian() * rad/4 + rad;
y = r.nextGaussian() * rad/4 + rad;
yields this beautiful city:

Resources