我知道我在这里遇到XY问题的可能性很大,所以第一部分是关于更普遍的情况.
问题
我有一组包含抽象地理要素信息的数据点,但没有实际位置(绝对或相对).为了举例,让我们称之为以下描述本地地形的城市列表,但没有坐标或相对定位:
>城市A位于岛屿和山丘上.
> B市位于海岸边,靠近河流.
> C市在山上,靠近河流
> D市在岛上和山上.
> E市位于岛屿和平原上.
由此,我想编写一个可以为这些位置提供相对位置的程序.对于上面的列表,它可能导致A和D彼此靠近,E可能在它们附近但不太可能,并且B和C可能彼此靠近.您可以将其视为一个图形,其中所有边缘都被擦掉,程序会尝试根据节点的属性将它们写回来.鉴于此,它可以为每个城市提供一些任意坐标,从中可以绘制地图.
我不需要一个独特的解决方案 – 我的最终目标是未映射但描述虚构的地方的合理地图.
在我看来,这似乎是一个很适合的问题,例如: Prolog或类似的逻辑引擎,因为它基本上只是约束解析.但是,我不能自己解决这个问题.我目前遇到的问题与例如两个城市可能具有相似的局部特征而不是接近该较大特征的相同实例的方式有关.这是“这座城市靠近一些未指明的山峰”和“这个城市靠近富瓦山”的区别.后者提供了一个强大的约束(两个城市都靠近福波纳山附近),但后者只提供了一个指导原则(两个城市都靠近山区,比一个城市附近的山区和另一个城市更可能相邻不靠近一座山).
问题
如何在Prolog或其他逻辑/规则引擎中定义(并提供基于解决方案的)概率而不是绝对值?
最佳答案 这是使用MiniZinc(一种非常好的约束建模语言)的方法.
该模型的假设是有一个固定地点的地图,例如那里有山,丘陵,河流等. (我不确定这是否在您的假设中.对于不同的型号,请参见下文.)
然后,目标是使用这些约束来放置一些城市(在这个模型中的城市A..H)
– 靠近(P1,P2):P1和P2必须在一定距离内(由“near_distance”定义)
– 开(P1,P2):城市P1必须在固定地点或非常靠近固定地点
– not_near(P1,P2):地点P1和P2不得靠近
我改变了一个原始约束并添加了一些更多的城市和约束.
这个模型也在这里:http://hakank.org/minizinc/place_cities2.mzn.
解决方案是在模型之后
include "globals.mzn";
% The places
enum places = {island,hill,coast,river,mountain,plains,
city_a,city_b,city_c,city_d,city_e,city_f,city_g,city_h
};
int: empty = 0;
set of int: fixed_places = {island,hill,coast,river,mountain,plains};
set of int: to_place = places diff fixed_places; % {city_a,city_b,city_c,city_d,city_e,city_f,city_g,city_h};
int: num_places = length(places);
int: max_x;
int: max_y;
int: near_distance;
array[1..max_x, 1..max_y] of int: data;
array[0..num_places] of string: places_s = array1d(0..num_places,
["-","i","h","c","r","m","p",
"A","B","C","D","E","F","G","H",
]);
% decision variables
% position of a city
array[to_place] of var 1..max_x: x;
array[to_place] of var 1..max_y: y;
% the grid (0 is an empty spot)
array[1..max_x, 1..max_y] of var 0..num_places: grid;
% on: must be really near.
% Assumption: p2 is a fixed_place
predicate on(var 1..num_places: p1, var 1..num_places: p2) =
exists(I in 1..max_x, J in 1..max_y) (
data[I,J] = p2 /\
pow(abs(x[p1]-I),2) + pow(abs(y[p1]-J),2) <= 1
)
;
% define the concept of near: atmost d distance apart
predicate near(var 1..num_places: p1, var 1..num_places: p2) =
exists(I in 1..max_x, J in 1..max_y) (
grid[I,J] = p2 /\
pow(abs(x[p1]-I),2) + pow(abs(y[p1]-J),2) <= near_distance
)
;
% not near: > d distance apart
predicate not_near(var int: p1, var int: p2) =
exists(I in 1..max_x, J in 1..max_y) (
grid[I,J] = p2 /\
pow(abs(x[p1]-I),2) + pow(abs(y[p1]-J),2) > near_distance
)
;
solve satisfy;
% solve :: int_search(x ++ y ++ array1d(grid), input_order, indomain_split, complete) satisfy;
% general constraints
constraint
% Here we ensure that:
% - a fixed place can only be positioned by the fixed place or a city
% - if an empty spot (in data[I,J]) then it can only be positioned by a city
forall(I in 1..max_x, J in 1..max_y) (
if data[I,J] != empty then
(grid[I,J] in {data[I,J]} union to_place)
/\ grid[I,J] != empty
else
grid[I,J] in to_place union {empty}
endif
)
;
% city constraints
constraint
% City A is on an island and on a hill.
on(city_a,island) /\
on(city_a, hill) /\
% City B is on the coast and near a river.
on(city_b,coast) /\
near(city_b,river) /\
% City C is on a mountain and near a river
on(city_c,mountain) /\
near(city_c,river) /\
% City D is on an island and on a hill.
on(city_d,island) /\
on(city_d,hill) /\
%%%City E is on an island and on plains.
% % on(city_e,island) /\
% Changed it to:
% City E is near the mountains and on plains
near(city_e, mountain) /\
on(city_e,plains)
% ADDED:
% City F is on mountains and near a river
/\
on(city_f, mountain) /\
near(city_f,river)
/\
near(city_g, mountain) /\
near(city_g, hill)
/\
on(city_h,plains) /\
% near(city_h,hill) % /\
% not_near(city_h,city_c) /\
not_near(city_h,city_f)
;
constraint
% connect the x[p] and y[p] arrays with grid[I,J]
forall(p in to_place) (
exists(I in 1..max_x, J in 1..max_y) (
x[p] = I /\ y[p] = J /\ grid[I,J] = p
)
)
% unique place in grid
% all cities have unique positions
/\ all_different([(x[p]*num_places-1)+ y[p] | p in to_place])
/\ % each city has just one place in the grid
forall(p in to_place) (
sum([grid[I,J] = p | I in 1..max_x, J in 1..max_y]) <= 1
)
;
output [
"x: \(x)\ny: \(y)\n"
]
++
[
join("", [places_s[fix(grid[I,J])] | J in 1..max_y]) ++ "\n"
| I in 1..max_x % , J in 1..max_y
]
;
%
% data
%
max_x = 15;
max_y = 15;
near_distance = 4;
data = array2d(1..max_x,1..max_y,
[
empty,empty,empty,empty,empty,empty,river,empty,empty,coast,empty,island,hill,hill,empty,
empty,empty,empty,empty,empty,empty,river,empty,empty,coast,empty,empty,island,island,empty,
empty,empty,empty,empty,empty,empty,river,empty,empty,empty,coast,coast,coast,coast,coast,
empty,empty,empty,empty,empty,empty,river,empty,empty,empty,empty,empty,empty,empty,empty,
empty,empty,empty,empty,empty,empty,river,empty,empty,empty,empty,empty,empty,empty,empty,
empty,empty,mountain,mountain,mountain,mountain,empty,empty,empty,empty,empty,empty,empty,empty,empty,
empty,empty,mountain,mountain,mountain,mountain,mountain,empty,empty,empty,hill,hill,hill,empty,empty,
empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,hill,hill,hill,empty,empty,
empty,empty,empty,empty,plains,plains,plains,plains,empty,empty,empty,empty,empty,empty,empty,
empty,empty,empty,empty,plains,plains,plains,empty,empty,empty,empty,empty,empty,empty,empty,
empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,
empty,empty,empty,empty,empty,empty,mountain,mountain,mountain,empty,empty,empty,empty,empty,empty,
empty,empty,empty,empty,empty,empty,mountain,mountain,mountain,empty,empty,empty,empty,empty,empty,
empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,
empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,empty,
]);
数据基于此(虚构)地图和缩写.
i: island
h: hill
c: coast
r: river
m: mountain
p: plains
......r..c.ihh.
......r..c..ii.
......r...ccccc
......r........
......r........
..mmmm.........
..mmmmm...hhh..
..........hhh..
....pppp.......
....ppp........
...............
......mmm......
这是一个解决方案,其中大写字母是要放置的城市:
x: [1, 1, 5, 1, 9, 5, 7, 10]
y: [13, 9, 6, 12, 4, 5, 9, 4]
------r-Bc-DAh-
------r--c--ii-
------r---ccccc
------r--------
----FCr--------
--mmmm---------
--mmmmm-G-hhh--
----------hhh--
---Epppp-------
---Hppp--------
---------------
------mmm------
------mmm------
---------------
---------------
它使用Gecode FlatZinc解算器在一定时间内解决(大部分时间都转换为一般的FlatZinc格式).
约束编程求解器的一个优点是可以很容易地生成许多解决方案,例如:与大多数MIP求解器和大多数/许多SAT求解器相比.
另外两条评论:
– 我首先解释了现在已知位置的问题.模型在这里:http://hakank.org/minizinc/place_cities.mzn
请注意,它假设只有一座山,一条河等.
>此外,我在构建这些模型后意识到问题提醒了Rina Dechter“约束处理”(第5页)中引用的“经典”Nadel的构造问题.然后,目标是将某些事物放置在某些地方附近或附近.我在一些CP系统中实现了这个问题:
> MiniZinc:http://hakank.org/minizinc/nadel.mzn
>皮卡特:http://hakank.org/picat/nadel.pi
> B-Prolog:http://hakank.org/bprolog/nadel.pl
> ECLiPSe CLP:http://hakank.org/eclipse/nadel.ecl
> SICStus Prolog:http://hakank.org/sicstus/nadel.pl
> Gecode:http://hakank.org/gecode/nadel.cpp