首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >将SWI-Prolog代码构造成模块,用于多个算法和数据集的单元测试

将SWI-Prolog代码构造成模块,用于多个算法和数据集的单元测试
EN

Stack Overflow用户
提问于 2019-08-03 11:03:06
回答 3查看 663关注 0票数 5

为了在下面的我的最后一个问题注释中详细讨论:我正在寻找关于构造supporting代码的技术或最佳实践的建议,以便能够使用和测试算法及其支持模块的可替换的、可替换的实现。

当前的情况可以用以下小的、虚构的例子来说明:用户提供一些输入数据(文件data.pl),并用要应用的算法(文件graph.pl)加载一个模块。算法模块本身使用来自另一个模块(文件path.pl)的助手谓词,该模块反过来需要访问用户提供的数据:

文件'data.pl‘(输入数据集):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
:- use_module(graph).

edge(a,b).
edge(b,c).
edge(c,d).

文件'graph.pl‘(算法):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
:- module(graph, [reachable/2]).
:- use_module(path).

reachable(X,Y) :-
    path(X,Y), !.
reachable(X,Y) :-
    path(Y,X), !.

文件'path.pl‘(带有帮助器谓词的模块,请注意它访问user中的数据):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
:- module(path, [path/2]).

path(X,X).
path(X,Y) :-
    user:edge(X,Z),
    path(Z,Y).

对于将算法应用于单个输入数据集的用例和算法的单个实现而言,这是非常好的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
?- [data].
true.

?- reachable(a,a).
true.

?- reachable(a,d).
true.

?- reachable(d,a).
true.

现在假设我有更多的数据集,以及graphpath模块的多个替代实现(具有相同的接口,即导出谓词)。为了(小)的例子,让我们假设我们文件数据文件data1.pldata2.pl,助手谓词模块path1.plpath2.pl,和算法模块graph1graph2.pl.。

我希望使用SWI-Prolog单元测试自动测试这些数据,并且最好能够编写一个测试套件,它既支持不同的数据集,又支持不同的模块实现,而不需要在两者之间重新启动Prolog。也就是说,我希望能够测试笛卡儿积中的所有组合。

{data1.pl, data2.pl} x {path1.pl, path2.pl} x {graph1.pl, graph2.pl}

没有复制粘贴/复制代码。

我的问题是:我将如何在SWI中做到这一点?关于如何为此目的将代码构造成模块,是否有最佳实践、设计模式等?我是否应该使用动态进口在替代算法模块之间切换,并在数据的单元测试中简单地使用setupcleanup

EN

回答 3

Stack Overflow用户

发布于 2019-08-03 23:31:48

首先,您有元谓词。这些应该允许您将数据和算法的构建块作为参数传递。看看这个例子。在绝对确定这种方法不够好之前,我不会尝试任何更复杂的方法。

那么,你仔细看过动态模块进出口接口了吗?

最后,您始终可以回到手动管理数据库的断言、撤回、取消等等。如果这样做,您可以完全避免模块系统。

但是试着先用元谓词来做。这是Prolog中“泛型算法”的明显机制。

一些密码。首先,您可以使用单元测试盒做什么?你可以做以下几件事。以下是三个模块:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ cat foo.pl
:- module(foo, [x/1]).

x(foo).
$ cat bar.pl
:- module(bar, [x/1]).

x(bar).
$ cat baz.pl
:- module(baz, []).

:- begin_tests(foo).
:- use_module(foo).

test(x) :- x(foo).

:- end_tests(foo).

:- begin_tests(bar).
:- use_module(bar).

test(x) :- x(bar).

:- end_tests(bar).

最后一个模块baz还没有导出任何东西,但是它确实有两个独立的单元测试盒。加载模块并运行测试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ swipl
Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.10-59-g09a7d554d-DIRTY)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- use_module(baz).
true.

?- run_tests.
% PL-Unit: foo . done
% PL-Unit: bar . done
% All 2 tests passed
true.

显然单元文本框可以让你有作用域。

要澄清的是,您可以在没有元调用(所以没有附加参数)的情况下使用客户机代码来假设接口(在本例中是对x/1的调用)。然后,您可以通过在同一个文件中的两个独立单元测试框中导入两个相互竞争的模块来测试相同接口的不同实现。

无论如何,所有这些似乎都可以用Logtalk更干净的方式完成。

票数 2
EN

Stack Overflow用户

发布于 2019-08-04 06:36:47

为了将相同的测试集应用于相同谓词的不同实现,或者更笼统地说,应用于相同接口/协议的不同实现,测试必须将实现作为动态参数。理想情况下,我们还应该能够用不同的数据集测试不同的算法实现。

另一个关注的问题是如何组织数据和我们想要在数据上运行的算法。有两种明智的方法。第一个选项是将数据视为导入或继承算法实现。在这种情况下,查询(例如reachable/2)将发送到数据。这种解决方案的一个缺点是,每当我们想要应用不同的算法集(例如,通过导入不同的模块)时,我们都可能需要更新数据集。

第二个选项是将数据视为算法的一个参数。该解决方案的一个简单实现是在谓词(例如路径和可访问谓词)中添加一个额外的参数,用于传递对数据的引用(例如,问题中提到的简单情况下的user )。该解决方案的一个缺点是,所有与算法相关的谓词都需要额外的参数(例如,reachable/2只调用path/2,并且只有这个实际上调用edge/2的谓词)。

以上所有问题和相应的备选解决方案都可以用Logtalk参数对象代替Prolog模块和使用Logtalk单元测试框架lgtunit (支持参数化测试的开箱即用)轻松而清晰地表达出来。下面是一个示例解决方案(它是可移植的,可以用于大多数Prolog系统)。

首先,让我们只制作关于数据的数据。我们首先为所有数据对象定义一个协议/接口:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
:- protocol(graph_protocol).

    :- public(edge/2).
    ...

:- end_protocol.

所有数据对象都将实现此协议。例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
:- object(graph1,
    implements(graph_protocol)).

    edge(a,b).
    edge(b,c).
    edge(c,d).

:- end_object.

接下来,让我们定义包含算法的参数对象,单个参数就是传递dataset对象。这些对象还可能实现已定义的协议,指定我们希望为其提供替代实现的谓词。为了简洁起见,这里省略了这些协议。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
:- object(path(_Data_)).

    :- uses(_Data_, [edge/2]).

    :- public(path/2).
    path(X,X).
    path(X,Y) :-
        edge(X,Z),
        path(Z,Y).

:- end_object.


:- object(reachable(_Data_)).

    :- uses(path(_Data_), [path/2]).

    :- public(reachable/2).
    reachable(X,Y) :-
        path(X,Y), !.
    reachable(X,Y) :-
        path(Y,X), !.

:- end_object.

注意,这些对象使用谓词定义为-is( reachable/1对象中的reachable/1指令需要LogTalk3.28.0或更高版本)。

可以通过定义以下方法简化将数据集加载到user中的默认情况:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
:- object(reachable ,
    extends(reachable(user))).

:- end_object.

一个典型的查询是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
?- reachable(graph1)::reachable(a,d).
...

到目前为止,我们只是在参数化数据集,而不是算法。我们会到达那里的。测试也可以定义为参数对象。例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
:- object(tests(_Data_),
    extends(lgtunit)).

    :- uses(reachable(_Data_), [reachable/2]).

    test(r1) :-
        reachable(a,a).

    test(r2) :-
        reachable(a,d).

    test(r3) :-
        reachable(d,a).

:- end_object.

对多个数据集的测试将使用如下目标:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
lgtunit::run_test_sets([
    tests(graph1),
    tests(graph2),
    tests(graph3)
])

最初的问题集中在算法的测试替代、可互换的实现上。但解决办法是一样的。我们只需修改参数测试对象,就可以接受将算法实现为参数的对象:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
:- object(tests(_Algorithm_),
    extends(lgtunit)).

    :- uses(_Algorithm_, [reachable/2]).

    cover(reachable(_)).
    cover(path(_)).

    test(r1) :-
        reachable(a,a).

    test(r2) :-
        reachable(a,d).

    test(r3) :-
        reachable(d,a).

:- end_object.

然后,在运行测试的查询上,使用我们想要的数据集和算法的任何组合。例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
lgtunit::run_test_sets([
    tests(reachable1(graph1)), tests(reachable2(graph1)), 
    tests(reachable1(graph2)), tests(reachable2(graph2)),
    ...
])

还可以动态创建lgtunit::run_test_sets/1谓词的list参数。例如,假设reachable/2谓词的所有替代实现都实现了reachable_protocol协议,则测试目标可以是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
datasets(Datasets),
findall(
    tests(Algorithm),
    (   implements_protocol(Algorithm, reachable_protocol),
        member(Dataset, Datasets),
        arg(1, Algorithm, Dataset)
    ),
    TestObjects
),
lgtunit::run_test_sets(TestObjects)

使用lgtunit运行这些测试的一个值得注意的方面是,除了报告通过的和失败的测试之外,在谓词子句级别报告完整的谓词代码覆盖率也很简单。这意味着我们不仅测试算法,而且检查用于实现算法的所有子句是否被使用。对于本例,仅使用graph1数据集,顶层解释器上的测试输出是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
?- {tester}.
% 
% tests started at 2019/8/5, 7:17:46
% 
% running tests from object tests(graph1)
% file: /Users/pmoura/Desktop/plu/tests.lgt
% 
% g1: success
% g2: success
% g3: success
% 
% 3 tests: 0 skipped, 3 passed, 0 failed
% completed tests from object tests(graph1)
% 
% 
% clause coverage ratio and covered clauses per entity predicate
% 
% path(A): path/2 - 2/2 - (all)
% path(A): 2 out of 2 clauses covered, 100.000000% coverage
% 
% reachable(A): reachable/2 - 2/2 - (all)
% reachable(A): 2 out of 2 clauses covered, 100.000000% coverage
% 
% 2 entities declared as covered containing 4 clauses
% 2 out of 2 entities covered, 100.000000% entity coverage
% 4 out of 4 clauses covered, 100.000000% clause coverage
% 
% tests ended at 2019/8/5, 7:17:46
% 
true.

如果您正在自动化测试(例如使用CI服务器),则可以使用logtalk_tester脚本。

如果我们想继续为数据集和/或算法使用模块怎么办?对于test对象来说,它只是一个编写的问题:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
:- object(tests(_Algorithm_),
    extends(lgtunit)).

    :- use_module(_Algorithm_, [reachable/2]).
    ...

:- end_object.

Logtalk的lgtunit支持测试普通Prolog代码和Prolog模块代码,以及Logtalk代码(实际上,Logtalk发行版包括一个Prolog标准一致性测试套件)。有关工具概述,请参见。

https://logtalk.org/tools.html#testing

在上面的URL中,我们还将找到一个代码覆盖率报告示例。有关使用上述解决方案的完整代码示例,请参见。

https://github.com/LogtalkDotOrg/logtalk3/tree/master/library/dictionaries

这个库提供了三个字典API的替代实现和一组测试(使用参数对象)来测试所有这些测试。

最后,但并非最不重要的是,您可以使用这个测试解决方案,不仅与SWI,而且还+10其他Prolog系统。

票数 2
EN

Stack Overflow用户

发布于 2019-08-03 12:27:40

对于单元测试,绝对使用setup/1cleanup/1,您希望测试用例。

为了您自己的探索和灵活性,重新定义依赖树,您不希望用用户命名空间调用谓词,因为当您的导入变得更加复杂或移动时,它将无法工作。该算法依赖于实用程序谓词,然后该谓词需要它所操作的数据。

文件'data.pl‘(输入数据集):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
:- module(data, [edge/2]).

edge(a,b).
edge(b,c).
edge(c,d).

文件'graph.pl‘(算法):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
:- module(graph, [reachable/2]).
:- use_module(path).

reachable(X,Y) :-
    path(X,Y), !.
reachable(X,Y) :-
    path(Y,X), !.

文件'path.pl‘(带有助手谓词的模块,注意它访问使用模块中的数据):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
:- module(path, [path/2]).
:- use_module(data).

path(X,X).
path(X,Y) :-
    edge(X,Z),
    path(Z,Y).

现在你可以swipl -g "reachable(a, d)" -s graph.pl了。这将使您可以轻松地更改path.pl中使用的数据模块。如果您愿意,可以在这里使用谓词动态加载模块,但最好在单元测试中使用安装/清理:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
:- dynamic path:edge/2.

/* Testing Graph
a→b→c→d 
*/
setup :-
    asserta(path:edge(a,b)),
    asserta(path:edge(b,c)),
    asserta(path:edge(c,d)).
cleanup :-
    retractall(path:edge(_, _)).

test(reach_same,
    [ true(A, a)
    , setup(setup)
    , cleanup(cleanup)
    , nondet
    ]
 ) :-
     reachable(a, A).
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57341339

复制
相关文章
用JQUERY做大表单(多表单域)AJAX提交
function postData() { var post = ""; $(":text").each(function() { post += "&" + this.name + "=" + this.value; }); $(":password").each(function() { post += "&" + this.name + "=" + this.value; }
liulun
2022/05/09
1.3K0
【jquery Ajax 】form表单教学+评论案例
表单在网页中主要负责数据采集功能,HTML中的<form>标签,就是用于采集用户输入的信息,并通过<form>标签的提交操作,把采集到的信息提交到服务器端进行处理。
坚毅的小解同志的前端社区
2022/11/28
2.2K1
【jquery Ajax 】form表单教学+评论案例
在ASP.MVC中使用Ajax
      Asp.net MVC 抛弃了Asp.net WebForm那种高度封装的控件,让我们跟底层的HTML有了更多的亲近。可以更自由、更灵活的去控制HTML的结构、样式和行为。Asp.net
用户1055830
2018/01/18
1.6K0
在ASP.MVC中使用Ajax
JQuery Ajax解读(3)
3.使用post方式进行异步请求:$.post (url,[data],[callback],[type])
py3study
2020/01/10
2930
Asp.Net Mvc表单提交(批量提交)
Asp.Net Mvc中Action的参数可以自动接收和反序列化form表单的值,
yaphetsfang
2020/07/30
3K0
JQuery ajax调用asp.net的webMethod
在vs2010中,用JQuery ajax调用asp.net 2.0的  webMethod 方法时,怎么都调不出来,原来和3.5 有点出入。
跟着阿笨一起玩NET
2018/09/19
2.2K0
JQuery ajax调用asp.net的webMethod
jQuery ajax - ajax() 方法jQuery ajax - ajax() 方法
http://www.w3school.com.cn/jquery/ajax_ajax.asp
一个会写诗的程序员
2018/08/17
14.5K0
JQuery ajax调用asp.net的webMethod
本文章转载:http://www.cnblogs.com/zengxiangzhan/archive/2011/01/16/1936938.html
跟着阿笨一起玩NET
2018/09/19
2.1K0
jquery实现ajax提交form表单的方法总结
方法一: function AddHandlingFeeToRefund() { var AjaxURL= "../OrderManagement/AjaxModifyOrderService.aspx"; alert($('#formAddHandlingFee').serialize()); $.ajax({ type: "POST",
PM吃瓜
2019/08/12
2K0
jquery validation engine ajax验证,jQuery Validation Engine 表单验证「建议收藏」
可以依赖多项,如:validate[condRequired[id1,id2]][Demo]
全栈程序员站长
2022/11/09
1.5K0
jQuery学习笔记之jQuery的Ajax(3)
———————————————————————————— 6.0 jQuery ajax 浏览器给我们提供的XMLHttpRequest的作用是来发送http请求。 js代码发送一个http的请求 XMLHttpRequest的四步:创建对象、注册监听、建立连接、发送数据
王小雷
2019/05/26
9040
ASP.NET MVC (三、表单与文件上传)
本章节主要针对文件上传进行强化练习,关键字【HttpPostedFileBase files,enctype="multipart/form-data"】  
红目香薰
2022/11/29
2.7K0
ASP.NET MVC (三、表单与文件上传)
ASP.Net MVC开发基础学习笔记:四、校验、AJAX与过滤器
  位于 System.ComponentModel.DataAnnotations 命名空间中的特性指定对数据模型中的各个字段的验证。这些特性用于定义常见的验证模式,例如范围检查和必填字段。而 DataAnnotations 特性使 MVC 能够提供客户端和服务器验证检查,使你无需进行额外的编码来控制数据的有效。
Edison Zhou
2018/08/20
2.1K0
ASP.Net MVC开发基础学习笔记:四、校验、AJAX与过滤器
如何解决jQuery Validation针对动态添加的表单无法工作的问题?
为了充分利用ASP.NET MVC在服务端呈现HTML的能力,在《利用动态注入HTML的方式来设计复杂页面》一文中介绍了,通过Ajax调用获取HTML来呈现复杂页面中某一部分界面的解决方案。我们知道ASP.NET MVC默认集成了jQuery Validation,但是对于通过JavaScript动态添加的表单,客户端验证默认情况下是失效的。 还是以前文涉及的“联系人管理”为例,在一个ASP.NET MVC应用中定义了如下两个类型,Contact封装联系人信息,HomeController包含三个Actio
蒋金楠
2018/01/15
2K0
如何解决jQuery Validation针对动态添加的表单无法工作的问题?
ASP.NET Core通过jQuery Ajax发送AntiForgeryToken
在ASP.NET Core中,如我我们希望用jQuery Ajax向服务器提交数据,并希望使用ValidateAntiForgeryToken标记,我们需要一些技巧。官方文档并没有说如何使用jQuery完成这个操作,我来演示给大家看看。
Edi Wang
2019/07/08
1.6K0
ASP.NET AJAX(3)__UpdatePanel
今天也不知道写不写的完了,最近闲下来了,却感冒了,早上起来都不会说话了,不过幸亏咱不是靠嘴皮子过活了,哎~~~~窃喜吧 上一篇简单写到UpdatePanel的一些好处和坏处,这一篇呢,就细致的认识一下UpdatePanel这个控件,并合理的使用它 UpdatePanel的一些属性 : RenderMode     __Block(默认值):设定UpdatePanel使用DIV来圈出要跟新的区域     __Inline:设定UpdatePanel使用span来。。。。。。 UpdateMode  
小白哥哥
2018/03/07
4.9K0
ASP.NET AJAX(3)__UpdatePanel
Asp.net mvc 知多少(六)
本系列主要翻译自《ASP.NET MVC Interview Questions and Answers 》- By Shailendra Chauhan,想看英文原版的可访问http://www.dotnettricks.com/free-ebooks自行下载。该书主要分为两部分,ASP.NET MVC 5、ASP.NET WEB API2。本书最大的特点是以面试问答的形式进行展开。通读此书,会帮助你对ASP.NET MVC有更深层次的理解。 由于个人技术水平和英文水平也是有限的,因此错误在所难免,希
圣杰
2018/01/11
2.4K0
Asp.net mvc 知多少(六)
Asp.net MVC Jquery提交后乱码问题
最近在处理MVC时,遇到要将特殊字符,或者XML格式的数据传递到后台,但是后台解析发现无法识别,处理有误。
aehyok
2018/09/11
1.6K0
jQuery和asp.net mvc相关资源链接
jQuery: Simplify calling ASP.NET AJAX services from jQuery jQuery Splitter jHtmlArea – The all NEW HTML WYSIWYG Editor for jQuery Expand table rows with jQuery - jExpand plugin Quick Tip – Reading & Editing HTML Attributes in jQuery Use jQuery and ASP.NET
张善友
2018/01/22
1.3K0
jquery ajax步骤,jquery ajax(ajax请求的五个步骤jQuery)
AJAX是与服务器交流数据的艺术,它在不重载全部页面的情况下,完成了对部分网页的更新。
全栈程序员站长
2022/08/29
1.7K0
jquery ajax步骤,jquery ajax(ajax请求的五个步骤jQuery)

相似问题

JavaScript硬币翻转“你赢/输”信息无效

50

连续赢/输R

125

轮盘赌赢输

33

将javascript数组导出到形状文件

10

Javascript::导出到文本文件

20
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文