85 lines
3.0 KiB
MiniZinc
85 lines
3.0 KiB
MiniZinc
include "globals.mzn";
|
|
enum TOWER;
|
|
|
|
enum HANDSET;
|
|
|
|
int: min_signal_strength;
|
|
|
|
int: maxpower = 10;
|
|
set of int: POWER = 1..maxpower;
|
|
array [POWER] of int: effective_power = [ 2 * (p-1) * (p-1) | p in POWER ];
|
|
|
|
array [TOWER] of int: capacity;
|
|
array [HANDSET] of int: demand;
|
|
|
|
% main decisions
|
|
array[TOWER] of var 0..maxpower: power;
|
|
|
|
float: POWER_SCALE = 10000;
|
|
array[HANDSET, TOWER] of float: distance;
|
|
|
|
% Effective power loss for handset/tower pairs. Scaled up to make everything integer.
|
|
array[HANDSET, TOWER] of float: attenuation = array2d(HANDSET,TOWER,
|
|
[ POWER_SCALE / (distance[h, t] * distance[h, t]) | h in HANDSET, t in TOWER ]);
|
|
array[HANDSET, TOWER] of int: attenuation_i = array2d(HANDSET, TOWER, [round(attenuation[h, t]) | h in HANDSET, t in TOWER ]);
|
|
%constraint trace("attenuation = \(attenuation);\n");
|
|
|
|
array[HANDSET] of var TOWER: tower = [ to_enum(TOWER, arg_max(t in TOWER)(signal_strength(t, h))) | h in HANDSET ];
|
|
|
|
% Manual implementation of Boolean par argmax.
|
|
function int: arg_max_(array [int] of int: idx, array [int] of int: tl, int: best, int: acc) =
|
|
if length(tl) = 0 then
|
|
best
|
|
elseif tl[1] > acc then
|
|
arg_max_(array1d(idx[2..]), array1d(tl[2..]), idx[1], tl[1])
|
|
else
|
|
arg_max_(array1d(idx[2..]), array1d(tl[2..]), best, acc)
|
|
endif;
|
|
|
|
function int: arg_max(array [int] of bool: elts) =
|
|
let {
|
|
array [int] of int: idx = [i | i in index_set(elts)] ;
|
|
array [int] of int: vals = [ bool2int(b) | b in elts ] ;
|
|
} in
|
|
arg_max_(array1d(idx[2..]), array1d(vals[2..]), idx[1], vals[1]);
|
|
|
|
var int: signal_strength(var TOWER: t, HANDSET: h) =
|
|
attenuation_i[h, t] * effective_power[power[t]];
|
|
|
|
% What is the minimum strength for t to transmit to h?
|
|
% Computed as the real minimum value.
|
|
function int: min_transmit_power(TOWER: t, HANDSET: h) ::promise_total =
|
|
let {
|
|
array [int] of bool: sel =
|
|
[effective_power[p] * attenuation[h, t] >= min_signal_strength | p in POWER]
|
|
++ [true] ;
|
|
} in
|
|
arg_max(sel);
|
|
|
|
% minium signal strength
|
|
constraint forall (h in HANDSET) ([ power[t] >= min_transmit_power(t, h) | t in TOWER ][tower[h]]);
|
|
% constraint forall(h in HANDSET)(signal_strength(tower[h], h) >= min_signal_strength);
|
|
|
|
% max handsets
|
|
include "global_cardinality_low_up.mzn";
|
|
array [TOWER] of var bool: overloaded = [ sum (h in HANDSET) (demand[h] * (tower[h] == t)) > capacity[t] | t in TOWER ];
|
|
|
|
% non interference
|
|
% array[HANDSET] of var int: connection_quality =
|
|
% [ 1000*signal_strength(tower[h],h) div sum(t in TOWER)(signal_strength(t,h)) | h in HANDSET ];
|
|
|
|
array[HANDSET] of var int: connection_quality = [not overloaded[tower[h]] | h in HANDSET];
|
|
var int: objective = sum(connection_quality);
|
|
|
|
|
|
solve ::seq_search([
|
|
int_search(tower, first_fail, indomain_min),
|
|
int_search(power, first_fail, indomain_min)
|
|
]) maximize objective;
|
|
|
|
output [
|
|
"tower = array1d(HANDSET, \([t+0 | t in tower]));\n",
|
|
"power = array1d(TOWER, \(power));\n",
|
|
"objective = \(objective);\n"
|
|
];
|