A swipl command shell options to use pack zdd library to counting families of sets

Assuming pack pac 1.9.6 is installed by pack_install/2 under ~/.local/share/swi-prolog, query log below on counting family of sets expressed in zdd terms should be reproduced.

Nothing particular has been added to zdd library of mine for one year in my slow life, but only recently I am realizing usefulness swipl command line options (thanks to @jan), and this is first-step exercise to use it. As next exercise, I have in mind to try command line version which uses arguments. Advice on this are welcome.

In the below, test file “zdd-eval-count.pl” should be put under appropriate directory,
and the path variable EVALCOUNT to be set in the shell script ‘count-zdd-samples-local’

% count-zdd-samples-local
#(a)=1
#((a+b)*(a+c))=4
#((a+b)*(c+d))=4
#(a*b*c*a*b)=1
#(a*b+c)=2
#(a+b-(c+d))=2
#((a+b)/a)=1
#((a+b)//a)=1
#((a*c+b)//a)=1
#(*(numlist(1,5)))=1
#(*([1,2,3]))=1
#(+[0,1,2]* +[0,1,2])=6
#(+[1,b,1,1]* +[1,a])=4
#(+[1,2,3,4])=4
#(+numlist(1,100)* +numlist(1,100))=5050
#((a+b)*(a+c)+a*b)=4
#(pow([a,b])-(c+d))=4
#(pow([a,b])//(a+b))=3
#(pow([a,b])/(a+b))=2
#(pow(charlist(a,c)))=1
#(pow(append([1,2],[a,b])))=16
#(pow(subtract([1,2,3],[1,2,a])))=2
#(+atomlist($a(1,10)))=10
#(pow(atomlist($a(1,10))))=1024
#! /usr/bin/env sh

ROOT="${HOME}/.local/share/swi-prolog/pack/pac/prolog"
PAC="${ROOT}/pac"
SETUPAUX="${ROOT}/setup-aux"
EVALCOUNT=${HOME}/devel/zdd/prolog/zdd/zdd-eval-count
COUNT='zdd_count:count_all'
swipl -q -l ${SETUPAUX} -l ${PAC} -l ${EVALCOUNT} -g ${COUNT} -t halt
% cat zdd-eval-count.pl

:- module(count_zdd, [count_all/0]).

% ?- count_all.

:- use_module(zdd(zdd)).

count_all:- forall(zdd_term(E), (zmod:zdd, once(count_one(E)))).
%
count_one(E):-
	call_with_time_limit(10, (X<< E, card(X, C))),
	writeln(#(E)=C).

% examples of zdd terms.
zdd_term( a ).
zdd_term( (a+b)*(a+c)).
zdd_term( (a+b)*(c+d)).
zdd_term( a*b*c*a*b).
zdd_term( a*b + c).
zdd_term( (a+b)-(c+d)).
zdd_term( (a+b)/a).
zdd_term( (a+b)//a).
zdd_term( (a*c+b)//a).
zdd_term( *(numlist(1, 5))).
zdd_term( *([1,2,3])).
zdd_term( +[0, 1, 2]* (+[0, 1, 2])).
zdd_term( +[1,b,1,1] * (+[1,a])).
zdd_term( +[1,2,3,4]).
zdd_term( +(numlist(1,100)) *  +(numlist(1,100))).
zdd_term( (a+b)*(a+c) +(a*b)).
zdd_term( pow([a,b])-(c+d)).
zdd_term( pow([a,b])//(a+b)).
zdd_term( pow([a,b])/(a+b)).
zdd_term( pow(charlist(a, c))).
zdd_term( pow(append([1,2],[a, b]))).
zdd_term( pow(subtract([1,2,3], [1,2,a]))).
zdd_term( +(atomlist($a(1,10)))).
zdd_term( pow(atomlist($a(1,10)))).

You can make this a lot simpler these days by adding a directory app in your pack and a file zdd.pl. Now.

 swipl zdd ...

runs this zdd.pl, so you can use Prolog’s commandline argument processing to so whatever you want. See the apps in SWI-Prolog’s own app directory for inspiration.

Thanks. I’m trying the modern way, but I got the following.

% swipl zdd hello
ERROR: Prolog initialisation failed:
ERROR: file `zdd' does not exist

But I think I will fix this soon. BTW, I found the pac-1.9.6 has invited a wrong ‘use_module’. I must update soon.

My mistake. This does not yet work for packs. I’ll look into that.

Take time. I’m not in hurry, though interested in the app functionality, which was new to me.

A simple test I have tried is this ( for pac-1.9.7 with the wrong use of use_module fixed.)

% cat ~/.local/share/swi-prolog/pack/pac/app/hello.pl
:-initialization(main, main).
main(A):- writeln(A).

% swipl hello world
ERROR: Prolog initialisation failed:

ERROR: file `hello’ does not exist

%

I have managed to write a swi-prolog script which counts the number of sets of a given family of sets in zdd term expression as argument of the script.
It is in an obsolete way of passing argument, but I have no idea for now to improve to smarter one.

#!/usr/bin/env swipl -q -t halt

% usage:  testscript.pl -- "pow([1,2,3,4])"
% #(pow([1,2,3,4]))=16

:- initialization(main, main).
:- expand_file_name('~/.local/share/swi-prolog/pack/pac/prolog/setup-aux', [AUX|_]),
   use_module(AUX).
:- expand_file_name('~/.local/share/swi-prolog/pack/pac/prolog/pac', [PAC|_]),
   use_module(PAC).
:- use_module(zdd(zdd)).
:- expand_file_name('~/devel/zdd/prolog/zdd/zdd-eval-count', [EVALCOUNT|_]),
   use_module(EVALCOUNT).

main(Args) :- atomics_to_string(Args, ' ', S),
			  term_string(Exp, S),
			  count_zdd:eval_count_one(Exp).

You can load a file from a specific pack using

:- use_module(pack('pac/prolog/setup-aux')).

The search path pack refers to the parent directories of all packs. Not that it is not wise toput libraries with a general name in the prolog directory of a pack as you can also load the above using

:- use_module(library('setup-aux')).

unless some other pack uses the same name. My general advise is

  • Put the user loadable modules in the prolog directory of the pack and give them a clear name that refers to the pack.

  • Put all other files in a directory private below the prolog directory and load them from the public files using e.g.

    :- use_module(private/my_nice_utility).

  • Make sure the module identifier of all module files is unique, for example, name all of them (in your case) pac_<name>, e.g, pac_utils.

Note that library(main) provides nice utilities for command line argument handling.

It works, and is much simpler, which seems enough for my current purpose.
I would like to use the private directory under the pack in the future. Thank you for your help. There seems a lot of things remain for me to learn about pack management.

Finally I have reached to a swipl commnand line zddcard below to count the members of a family of sets using my zdd library of pack pac 1.9.7. There are many things for me to learn about details of modern SWI-Prolog’s pack structure, I have to take time for that. For example, I found that the extension .pl seems not always necessary, and also with “–”. However
double quotes " around zdd term argument seems necessary. I am a little bit confusion about this.

#! /usr/bin/env swipl -q -t halt

% usage:  zddcard  "pow([1,2,3,4])"
% #(pow([1,2,3,4]))=16

:- initialization(main, main).

:- use_module(pack('pac/prolog/setup-aux')).
:- use_module(pack('pac/prolog/pac')).
:- use_module(zdd(zdd)).

main(Args) :- atomics_to_string(Args, ' ', S),
		term_string(Exp, S),
		zmod:zdd,
		call_with_time_limit(10, zmod: (X<< Exp, card(X, C))),
		writeln(#(Exp)=C).

% sample zdd terms.
sample( a ).
sample( (a+b)*(a+c)).
sample( (a+b)*(c+d)).
sample( a*b*c*a*b).
sample( a*b + c).
sample( (a+b)-(c+d)).
sample( (a+b)/a).
sample( (a+b)//a).
sample( (a*c+b)//a).
sample( *(numlist(1, 5))).
sample( *([1,2,3])).
sample( +[0, 1, 2]* (+[0, 1, 2])).
sample( +[1,b,1,1] * (+[1,a])).
sample( +[1,2,3,4]).
sample( +(numlist(1,100)) *  +(numlist(1,100))).
sample( (a+b)*(a+c) +(a*b)).
sample( pow([a,b])-(c+d)).
sample( pow([a,b])//(a+b)).
sample( pow([a,b])/(a+b)).
sample( pow(charlist(a, c))).
sample( pow(append([1,2],[a, b]))).
sample( pow(subtract([1,2,3], [1,2,a]))).
sample( +(atomlist($a(1,10)))).
sample( pow(atomlist($a(1,10)))).