首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >将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
运行
AI代码解释
复制
:- use_module(graph).

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

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

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

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

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

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

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

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

代码语言:javascript
运行
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
运行
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
运行
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
运行
AI代码解释
复制
:- protocol(graph_protocol).

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

:- end_protocol.

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

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

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

:- end_object.

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

代码语言:javascript
运行
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
运行
AI代码解释
复制
:- object(reachable ,
    extends(reachable(user))).

:- end_object.

一个典型的查询是:

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

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

代码语言:javascript
运行
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
运行
AI代码解释
复制
lgtunit::run_test_sets([
    tests(graph1),
    tests(graph2),
    tests(graph3)
])

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

代码语言:javascript
运行
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
运行
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
运行
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
运行
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
运行
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
运行
AI代码解释
复制
:- module(data, [edge/2]).

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

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

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

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

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

代码语言:javascript
运行
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
运行
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

复制
相关文章
Livy:基于Apache Spark的REST服务
Apache Spark提供的两种基于命令行的处理交互方式虽然足够灵活,但在企业应用中面临诸如部署、安全等问题。为此本文引入Livy这样一个基于Apache Spark的REST服务,它不仅以REST的方式代替了Spark传统的处理交互方式,同时也提供企业应用中不可忽视的多用户,安全,以及容错的支持。 背景 Apache Spark作为当前最为流行的开源大数据计算框架,广泛应用于数据处理和分析应用,它提供了两种方式来处理数据:一是交互式处理,比如用户使用spark-shell或是pyspark脚本启动Sp
CSDN技术头条
2018/02/13
4K0
Livy:基于Apache Spark的REST服务
基于spring-boot的rest微服务框架
周末在家研究spring-boot,参考github上的一些开源项目,整了一个rest微服务框架,取之于民,用之于民,在github上开源了,地址如下:
菩提树下的杨过
2018/09/20
8040
Ajax的异步请求探究
在开发中经常使用ajax去请求接口,而ajax不是一项新的技术,基于原生的XmlHttpRequest对象和html css js共同完成 在了解ajax之前先搞清楚什么是http, 想要了解更多可访问mozllia(霸王龙)的 https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/send# Http
用户9347382
2022/01/10
8650
Rest API请求管理最佳实践:RestClient-cpp库的应用案例
在当今互联网时代,REST(Representational State Transfer)API已经成为了现代应用程序开发的重要组成部分。随着各种网络服务和应用程序的不断涌现,有效地管理和调用REST API变得至关重要。为了解决这一需求,开发人员们倾向于寻找可靠且易于使用的库来简化REST API请求的处理。
小白学大数据
2024/03/29
2930
AsyncContext异步请求的用法
在Servlet 3.0中,在ServletRequest上提供了startAsync()方法
全菜工程师小辉
2019/09/16
5.4K0
AsyncContext异步请求的用法
HarmonyOS 开发实践 —— 基于@ohos/axios的网络请求能力
Axios 是一个基于promise的网络请求库,可以运行node.js和浏览器中。基于Axios原库v1.3.4GitHub版本进行适配,使其可以运行在OpenHarmony并沿用其现有用法和特性。
小帅聊鸿蒙
2024/12/03
3110
HarmonyOS 开发实践 —— 基于@ohos/axios的网络请求能力
HarmonyOS 开发实践 —— 基于rcp的网络请求能力
rcp模块提供HTTP数据请求功能,请求性能如接口的易用性、性能、功耗方面,对比Network Kit HTTP网络API,rcp采用面向对象和场景的设计,API使用更简单、更灵活,满足不同场景的使用需求,具备更好的扩展性和更优的性能。支持如场景化网络API、网络代理、自定义DNS解析、自定义证书校验、服务器身份校验等特性。
小帅聊鸿蒙
2024/11/22
2220
HarmonyOS 开发实践 —— 基于rcp的网络请求能力
Angular 实践:如何优雅地发起和处理请求
Tips: 本文实现重度依赖 ObservableInput,灵感来自同事 @Mengqi Zhang 实现的 asyncData 指令,但之前没有 ObservableInput 的装饰器,处理响应 Input 变更相对麻烦一些,所以这里使用 ObservableInput 重新实现。
灵雀云
2020/02/26
8680
Angular 实践:如何优雅地发起和处理请求
Netflix 微服务异步迁移:从同步的“请求响应”模式转换为异步事件
假设我们正在运行一个基于 Web 的服务。请求处理变慢最终将会导致服务不可用。实际上,并不是所有的请求都需要立即处理。有些请求只要确认已收到即可。你有没有问过自己这样的问题:“我是否能够从异步请求处理中获益?如果确实如此的话,我该如何在一个实时的、大规模的关键任务系统中做出这种转变?”
深度学习与Python
2022/11/28
7870
Netflix 微服务异步迁移:从同步的“请求响应”模式转换为异步事件
Livy,基于Apache Spark的开源REST服务,加入Cloudera Labs
Hadoop生态圈的Spark(https://www.cloudera.com/products/open-source/apache-hadoop/apache-spark.html),一夜之间成为默认的数据处理引擎,并被作为高级分析的标准。但是它依旧有许多东西需要完善,特别是在大规模/多租户,开发与投产,以及可扩展性方面。
Fayson
2018/03/29
2.4K0
基于zookeeper的微服务实践
微服务的话题也火了好几年了,各类微服务架构的文章也是非常的多,这里也阐述下个人对微服务系统的见解。
DifficultWork
2019/06/03
1.2K0
Spring Boot快速开发REST服务实践
REST代表Representational State Transfer. 是一种架构风格,设计风格而不是标准,可用于设计Web服务,可以从各种客户端使用.
用户5224393
2019/08/30
8250
Spring Boot快速开发REST服务实践
基于 Docker 的微服务架构实践
基于 Docker 的容器技术是在2015年的时候开始接触的,两年多的时间,作为一名 Docker 的 DevOps,也见证了 Docker 的技术体系的快速发展。本文主要是结合在公司搭建的微服务架构的实践过程,做一个简单的总结。希望给在创业初期探索如何布局服务架构体系的 DevOps,或者想初步了解企业级架构的同学们一些参考。
烂猪皮
2018/08/03
2.6K0
基于 Docker 的微服务架构实践
Java调用外部REST请求的几种方式
1、RestOperations 提供了各种封装方法,非常方便直接将返回转成实体类。
伍六七AI编程
2022/03/23
8130
python-异步IO编程-异步HTTP请求的实现
在传统的同步IO编程中,当我们发起一个HTTP请求时,我们需要等待服务器返回响应,这样就会阻塞当前线程的执行。如果需要发起多个HTTP请求,就需要创建多个线程或进程来处理这些请求,这样会造成资源浪费和性能下降。为了解决这个问题,Python提供了异步IO编程模型,可以实现异步HTTP请求,从而提高程序的性能和并发能力。
玖叁叁
2023/04/21
7330
Spring 3.0支持基于rest的Web服务学习总结
尽管RESTful功能被添加到Spring MVC框架非常早期通过注释和其他API功能,支持基于rest的Web服务是Spring MVC有点晚。几个jax - rs(RESTful Web服务的Java API)实现,比如Restlet RESTEasy和球衣支持rest风格的Web服务,但Spring社区没有添加到Spring 3.0支持rest风格的Web服务功能。在这篇文章中,我讨论了Spring 3.0支持开发RESTful Web服务,检查类和注释。 快速复习,RESTful Web服务的Web
用户1289394
2018/02/27
1.3K0
小白需懂的异步请求的处理
在我们传统的服务中,当一个HTTP请求过来时,tomcat或者是其他的中间件都会有一个主线程来处理请求,所有的业务逻辑都会在这个线程里面处理完,最后会给出一个响应。由于我们的tomcat所管理的线程数是有限的,当线程到达一定程度后,再有请求过来将会无法去处理了。
用户7386338
2020/05/29
2.1K0
servlet异步请求
其中第二步处理业务逻辑时候很可以碰到比较耗时的任务,此时servlet主线程会阻塞等待完成业务处理,对于并发比较大的请求可能会产生性能瓶颈,则servlet3.0之后再此处做了调整,引入了异步的概念。
全栈程序员站长
2022/09/18
9130
servlet异步请求
ajax发送异步请求四个步骤,AJAX的异步请求的四个步骤[通俗易懂]
全部的现代浏览器均支持XMLHttpRrquest对象(IE5和IE6使用ActiveObject)async
全栈程序员站长
2022/08/29
1.4K0
Spring 异步请求
With the above in mind, the following is the sequence of events for async request processing with a Callable:
数媒派
2022/12/01
8110

相似问题

是否有可能将类似Lisp的宏构建为命令式语言?

34

是否有可能从eclipse构建过程中获得确切的maven命令?

14

是否有可能对无序元素进行响应式设计?

10

是否有可能脱离基于条件执行的bash命令?

12

是否有可能成功地包装退出方法?

13
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

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

洞察 腾讯核心技术

剖析业界实践案例

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