1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.

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"
];