Lisp 二元约束满足问题的随机实例生成
我正在实现一个随机CSP生成器,用于对两种不同的arc一致性算法(AC3和AC2001)进行比较测试。生成实例时,参数包括变量数量、域大小(所有变量相同)、约束数量和每个约束拒绝的值对数量(所有约束相同) 我的实现构建了变量(包含两个字段的结构,名称和域(列表)),约束(包含两个字段的结构,涉及的变量和约束函数))。它创建一个哈希表,该哈希表将每个限制中涉及的变量作为键和值,并列出被所述约束拒绝的对。使用时,每个约束检查变量的给定值是否包含在拒绝值列表中 此实现“可行”,但生成的实例中很少有需要减少弧,因此它们对于测试目的基本上是无用的。 代码如下:Lisp 二元约束满足问题的随机实例生成,lisp,artificial-intelligence,common-lisp,constraint-programming,Lisp,Artificial Intelligence,Common Lisp,Constraint Programming,我正在实现一个随机CSP生成器,用于对两种不同的arc一致性算法(AC3和AC2001)进行比较测试。生成实例时,参数包括变量数量、域大小(所有变量相同)、约束数量和每个约束拒绝的值对数量(所有约束相同) 我的实现构建了变量(包含两个字段的结构,名称和域(列表)),约束(包含两个字段的结构,涉及的变量和约束函数))。它创建一个哈希表,该哈希表将每个限制中涉及的变量作为键和值,并列出被所述约束拒绝的对。使用时,每个约束检查变量的给定值是否包含在拒绝值列表中 此实现“可行”,但生成的实例中很少有需要
; This function generates the complete list of variables for the problem
(defun crea-lista-variables (nvars tdom p-v)
(loop for i from 0 to (1- nvars) collect
(crea-variable :nombre i
:dominio (crea-dominio-nuevo tdom p-v nil))))
; This function creates a variable's domain, without repetitions. It takes it's
; values from a list of possible values for the problem
(defun crea-dominio-nuevo (tdom p-v dominio)
(let ((candidato (nth (random (1- (length p-v))) p-v)))
(cond ((= tdom 0) dominio)
((not (pertenece candidato dominio))
(crea-dominio-nuevo (- tdom 1) p-v
(append dominio (list candidato))))
(t (crea-dominio-nuevo tdom p-v dominio)))))
此函数用于创建限制及其被拒绝的值
(defun crea-lista-restricciones (nrest npares tdom p-p p-v
restricciones rechazados)
(let* ((variables (nth (random (1- (length p-p))) p-p))
(rest (crea-restriccion :variables variables
:funcion #'(lambda (x y &optional (z nil))
(not (pertenece (list x y)
z))))))
(cond ((= nrest 0) restricciones)
((null (gethash variables rechazados))
(crea-rechazados npares tdom variables p-v rechazados)
(crea-lista-restricciones (1- nrest) npares tdom p-p
p-v (append restricciones (list rest))
rechazados))
(t (crea-lista-restricciones nrest npares tdom p-p
p-v restricciones rechazados)))))
此函数用于创建拒绝值哈希表
(defun crea-rechazados (numpares tamdom variables posibles-valores rechazados)
(let* ((valor1 (nth (random (1- (length posibles-valores)))
posibles-valores))
(valor2 (nth (random (1- (length posibles-valores)))
posibles-valores))
(candidato (list valor1 valor2))
(lista (gethash variables rechazados)))
(cond ((= numpares 0) rechazados)
((not (pertenece candidato lista))
(setf (gethash variables rechazados)
(append lista (list candidato)))
(crea-rechazados (1- numpares) tamdom variables
posibles-valores rechazados))
(t (crea-rechazados numpares tamdom variables
posibles-valores rechazados)))))
以及为解算器创建全局参数以供使用的主函数
(defun genera-problema (numvars tamdom numrest numpares)
(cond ((< numvars 2)
(format t "~&Error: Debe haber al menos 2 variables"))
((< tamdom 2)
(format t "~&Error: Los dominios deben tener al menos dos elementos"))
((or (< numrest 0) (> numrest (/ (* numvars (- numvars 1)) 2)))
(format t "~&Error: numero de restricciones incorrecto"))
((or (< numpares 1) (> numpares (- (* tamdom tamdom) 1)))
(format t "~&Error: numero de pares incorrecto"))
(t (let ((posibles-valores (loop for i from 0
to (1- (+ tamdom tamdom))
collect i))
(posibles-pares (loop for i from 0 to (- numvars 2) append
(loop for j from (+ i 1)
to (1- numvars)
collect (list i j)))))
(defparameter *RECHAZADOS*
(make-hash-table :test #'equalp))
(defparameter *VARIABLES-AC3*
(crea-lista-variables numvars tamdom posibles-valores))
(defparameter *VARIABLES-AC2001*
(loop for variable in *VARIABLES-AC3*
collect (crea-variable :nombre (psr-var-nombre var)
:dominio (copia-lista
(psr-var-dominio var)))))
(defparameter *RESTRICCIONES*
(crea-lista-restricciones numrest numpares tamdom
posibles-pares posibles-valores
nil *RECHAZADOS*))
(defparameter *ARCOS-AC3* 0)
(defparameter *ARCOS-AC2001* 0)))))
(定义一般问题(numvars tamdom numrest numpares)
(条件(numrest(/(*numvars(-numvars 1))2)))
(格式t“~&错误:限制数字不正确”)
((或(numpares(-tamdom-tamdom)1)))
(格式t“~&错误:数字比较不正确”))
(t)let((posibles)valores(从0开始的i的循环
至(1-(+tamdom-tamdom))
收款(一)
(posibles pares(i从0到(-numvars 2)的循环)append
(来自(+i 1)的j回路
至(1-numvar)
收集(列表i j()()))
(defparameter*RECHAZADOS*
(生成哈希表:test#'equalp))
(defparameter*变量-AC3*
(crea lista变量numvars tamdom posibles valores))
(defparameter*变量-AC2001*
(用于*变量-AC3中的变量的循环*
收集(crea变量:nombre(psr var nombre var)
:多米尼奥(科皮亚·利斯塔)
(psr var dominio var(()()))
(定义参数*限制)*
(crea lista RESCRICCIONES numrest numpares tamdom)
可能的事,可能的事,可能的事
无*雷查扎多斯*))
(defparameter*ARCOS-AC3*0)
(defparameter*ARCOS-AC2001*0(()()))
函数“pertence”检查元素是否在列表中
我希望这是可以理解的,即使是西班牙语的名字。如果不是,我可以完整地翻译
那么,撇开我糟糕的lisp编码技能不谈,我是否可以纠正或改进任何错误,以使生成的实例具有更高的质量?关于基本编码风格,有一些评论:
(loop for i from 0 upto (1- n) ...)
只是
(loop for i below n ...)
crea dominio nuevo
是一个递归函数。在每次迭代中,您都会在列表的末尾添加一个项目。这是在Lisp中使用单链表最糟糕的方法。应避免在列表末尾追加项目。有一个简单的操作可以添加一个项目,那就是把它放到前面。如果你真的需要在某件事情的结尾添加内容,有两种方法:
- 使用矢量并将其推到底
- 进行迭代,这样您就可以将列表倒转到前面,并在最后将列表倒转一次
crea lista restricciones
也有同样的问题
在列表中多次调用
length
是另一个问题。通常,在生成基准测试时,应该修复所有参数,并尝试只使用一个参数。后者通常与随机化有关。在你的情况下,似乎你没有使用任何随机化。例如,我强烈建议您添加一个参数,表示在约束范围内两个变量同时存在的概率,或者它们在一起的频率,等等
另一方面,您可以使用现有的基准测试,如。有一系列问题,其中一些是二进制CSP(例如“RAND”cathegory中的“mark”问题) 基本事实:关于随机实例的每个决策都将反映在基准测试中。如果你想比较你的算法A和B,有人可能会生成A(或B)占主导地位的随机实例
大多数时候,有人对硬实例感兴趣(因为约束编程主要用于硬问题)。在这种情况下,我认为您有两种可能:
谢谢你的建议,正如我所说,我的lisp编码知识非常有限。我将尝试优化m