逻辑引擎中的不确定性(根据当地地理位置产生合理的相对位置)

时间:2017-04-27 15:51:27

标签: prolog constraint-programming logic-programming

我知道我在这里遇到XY问题的可能性很大,所以第一部分是关于更普遍的情况。

问题

我有一组包含抽象地理要素信息的数据点,但没有实际位置(绝对或相对)。举例来说,让我们称之为以下城市列表来描述当地的地形,但没有坐标或相对位置:

  • A市在岛上和山上。
  • B市位于海岸,靠近河流。
  • C市在山上,靠近河流
  • D市在岛上和山上。
  • E市位于一个岛屿和平原上。

由此,我想编写一个可以为这些位置提供相对位置的程序。对于上面的列表,它可能导致A和D彼此靠近,E可能在它们附近但不太可能,并且B和C可能彼此接近。您可以将其视为一个图形,其中所有边缘都被擦掉,程序会尝试根据节点的属性将它们写回来。鉴于此,它可以为每个城市提供一些任意坐标,从中可以绘制地图。

我不需要一个独特的解决方案 - 我的最终目标是未映射但描述虚构的地方的合理地图。

在我看来,这是一个很适合的问题,例如: Prolog或类似的逻辑引擎,因为它基本上只是约束解析。但是,我不能自己解决这个问题。我目前遇到的问题与例如两个城市可能具有相似的局部特征而不是接近该较大特征的相同实例的方式有关。这是“这座城市靠近一些未指明的山峰”和“这个城市靠近富瓦山”的区别。后者提供了一个强大的约束(两个城市都靠近福波纳山附近),但后者只提供了一个指导原则(两个城市都靠近山区,比一个城市附近的山区和另一个城市更可能相邻不靠近山。)

问题

如何在Prolog或其他逻辑/规则引擎中定义(并提供基于解决方案的)概率而不是绝对值?

2 个答案:

答案 0 :(得分:1)

这听起来像placement问题,所以你应该尝试调查方法来解决它。

我将使用satisfiability框架讨论不确定性和相关内容。您可以定义 2D网格,每个节点可以容纳要素 - 山丘,河流,山脉。功能可以是通用的或特殊的(Mt. Foobar)。某些功能可以预定义 - 您可以在指定节点放置一个山峰,但这取决于您。城市也被定义为特征。

现在,有趣的部分。您可以定义一组约束 over 此类网格。因此,对于网格中的每个节点,您可以定义如下内容:

  

如果城市A发生在节点那么山必须在相邻的节点

     

如果给定节点包含山,则城市A必须位于任何相邻节点

     

如果城市A出现在给定节点那么城市B不能在任何相邻节点

即使计算对象,您也可以通过这种方式引入许多各种约束:

  

如果一个节点有一条河,那么相邻节点不得超过2个城市

为此,您可以依赖pseudo-boolean constraints。您甚至可以通过引入特定配置的计数器来使用它来优化解决方案,并要求此处必须

要解决结果问题,您可以使用任何SAT解算器(例如Glucose

您可以使用AllSAT生成多个不同的解决方案,也有解决方案。

如果纯布尔公式太复杂,您可以尝试SMT

详细说明如何实施此类系统不属于问题的范围,它过于宽泛,需要大量的初步研究。

希望我的回答很有帮助。

修改

SAT求解器返回第一个正确的解决方案,从这个意义上说它将是随机的。

答案 1 :(得分:1)

这是一种使用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   请注意,它假设只有一座山,一条河等。