3
4:- module(directives, [
5 directive/3, 6 directive/2, 7 is_directive_valid/2 8 ]). 9
10:- use_module(flags). 11:- use_module(utilities). 14
15:- use_module(library(lists)). 16
18
19:- set_prolog_flag(double_quotes, codes). 20
21ensure_loaded_wn :-
22 ensure_loaded(wn(wn_gen_prox_equations)),
23 ensure_loaded(wn(wn_utilities)).
24
37directive(Name, Arguments) :-
38 directive(Name, Arguments, _).
47directive(lambda_cut, [Lambda], []) :-
48 49 50 flags:set_bpl_flag(lambda_cut(Lambda)).
51
52directive(filtering, [Boolean], []) :-
53 54 55 flags:set_bpl_flag(filtering(Boolean)).
56
57directive(transitivity, [Type], []) :-
58 59 60 ClosureProperties = [symmetric, reflexive, transitive(Type)],
61 flags:remove_bpl_flag(relation_properties(sim, _OldClosureProperties)),
62 flags:add_bpl_flag(relation_properties(sim, ClosureProperties)).
63
64directive(fuzzy_rel, [RelName, ClosureProperties], []) :-
65 66 67 flags:remove_bpl_flag(relation_properties(RelName, _OldClosureProperties)),
68 flags:add_bpl_flag(relation_properties(RelName, ClosureProperties)).
69
70directive(domain, [Name, Min, Max, Unit], []) :-
71 72 flags:add_bpl_flag(fuzzy_domain(Name, [Min, Max, Unit])),
73 flags:add_bpl_flag(fuzzy_subsets(Name, [])).
74
75directive(fuzzy_set, [DomainName, Subsets], []) :-
76 77 78 79 flags:get_bpl_flag(fuzzy_subsets(DomainName, CurrentSubsets)),
80 append(CurrentSubsets, Subsets, NewSubsets),
81 82 list_to_set(NewSubsets, NewSubsetsNoDuplicates),
83 flags:remove_bpl_flag(fuzzy_subsets(DomainName, CurrentSubsets)),
84 flags:add_bpl_flag(fuzzy_subsets(DomainName, NewSubsetsNoDuplicates)).
85
86directive(weak_unification, [Type], []) :-
87 88 89 flags:set_bpl_flag(weak_unification(Type)).
90
91directive(ext_block_equs, [Boolean], []) :-
92 93 94 95 flags:set_bpl_flag(ext_block_equs(Boolean)).
96
97directive(fuzzy_logic, [TNorm], []) :-
98 99 100 retractall(evaluator:t_norm_current_op(_, _, _)),
101 clause(evaluator:t_norm_op(TNorm, L, R, D), Body),
102 assert((evaluator:t_norm_current_op(L, R, D) :- Body)),
103 flags:set_bpl_flag(fuzzy_logic(TNorm)).
104
105directive(wn_connect, [], []) :-
106 ensure_loaded_wn.
107
108directive(wn_connect, [QFolder], []) :-
109 110 111 utilities:remove_quotes(QFolder,Folder),
112 setenv('WNDB', Folder),
113 ensure_loaded_wn.
114
115directive(wn_gen_prox_equations, [Measure, ListOfListOfWords], Equations) :-
116 117 118 is_list(ListOfListOfWords),
119 !,
120 wn_gen_prox_equations:wn_gen_prox_equations_list(ListOfListOfWords, Measure, Equations).
121
122directive(wn_gen_prox_equations, [_Measure, _Auto], []).
123 125
126
132
133replaced_directive(wn_gen_prox_equations).
134
155
156is_directive_valid(lambda_cut, [Lambda]) :-
157 number(Lambda), Lambda >= 0, Lambda =< 1,
158 159 !.
160
161is_directive_valid(lambda_cut, [_Lambda]) :-
162 163 !,
164 throw_invalid_argument_error(lambda_cut, 1,
165 'Lambda-cut value must be a number in range [0.0, 1.0].').
166
167is_directive_valid(lambda_cut, Arguments) :-
168 169 length(Arguments, Arity),
170 throw_wrong_arity_error(lambda_cut, Arity, 1).
171
175
176is_directive_valid(filtering, [Boolean]) :-
177 memberchk(Boolean,[true,false]),
178 179 !.
180
181is_directive_valid(filtering, [_Boolean]) :-
182 183 !,
184 throw_invalid_argument_error(filtering, 1,
185 'Filtering value must be either \'true\' or \'false\'.').
186
187is_directive_valid(filtering, Arguments) :-
188 189 length(Arguments, Arity),
190 throw_wrong_arity_error(filtering, Arity, 1).
191
195
196is_directive_valid(transitivity, [Type]) :-
197 nonvar(Type),
198 member(Type, [yes, no, min, product, luka, drastic, nilpotent, hamacher]),
199 200 !.
201
202is_directive_valid(transitivity, [_Type]) :-
203 204 !,
205 throw_invalid_argument_error(transitivity, 1,
206 'Transitivity type must be in domain [yes, no, min, product, luka].').
207
208is_directive_valid(transitivity, Arguments) :-
209 210 length(Arguments, Arity),
211 throw_wrong_arity_error(transitivity, Arity, 1).
212
216
217is_directive_valid(weak_unification, [Type]) :-
218 nonvar(Type),
219 member(Type, [a1, a2, a3]),
220 221 !.
222
223is_directive_valid(weak_unification, [_Type]) :-
224 225 !,
226 throw_invalid_argument_error(weak_unification, 1,
227 'Weak unification algorithm must be in domain [a1, a2, a3].').
228
229is_directive_valid(weak_unification, Arguments) :-
230 231 length(Arguments, Arity),
232 throw_wrong_arity_error(weak_unification, Arity, 1).
233
237
238is_directive_valid(ext_block_equs, [Type]) :-
239 nonvar(Type),
240 member(Type, [true, false]),
241 242 !.
243
244is_directive_valid(ext_block_equs, [_Type]) :-
245 246 !,
247 throw_invalid_argument_error(ext_block_equs, 1,
248 'External block equations processing must be in domain [true, false].').
249
250is_directive_valid(ext_block_equs, Arguments) :-
251 252 length(Arguments, Arity),
253 throw_wrong_arity_error(ext_block_equs, Arity, 1).
254
258
259is_directive_valid(fuzzy_logic, [TNorm]) :-
260 nonvar(TNorm),
261 member(TNorm, [min, product, luka, drastic, nilpotent, hamacher]),
262 263 !.
264
265is_directive_valid(fuzzy_logic, [_TNorm]) :-
266 267 !,
268 throw_invalid_argument_error(fuzzy_logic, 1,
269 'Fuzzy logic t-norm must be in domain [min, product, luka, drastic, nilpotent, hamacher].').
270
271is_directive_valid(fuzzy_logic, Arguments) :-
272 273 length(Arguments, Arity),
274 throw_wrong_arity_error(fuzzy_logic, Arity, 1).
275
279
280is_directive_valid(fuzzy_rel, [RelName, Properties]) :-
281 nonvar(RelName), nonvar(Properties),
282 RelName \== sim,
283 utilities:relation_name(_RelSymbol, RelName),
284 is_list(Properties),
285 list_to_set(Properties, Properties),
286 subset(Properties, [symmetric, reflexive, transitive, transitive(_)]),
287 ((RelName == lEqThan ; RelName == gEqThan) ->
288 member(reflexive, Properties),
289 (member(transitive, Properties) ; member(transitive(_), Properties))
290 ;
291 true
292 ),
293 (member(transitive(TNorm), Properties) ->
294 member(TNorm, [yes, no, min, luka, product])
295 ;
296 true
297 ),
298 299 !.
300
301is_directive_valid(fuzzy_rel, [sim, _Properties]) :-
302 303 !,
304 throw_invalid_argument_error(fuzzy_rel, 2,
305 'Similarity relation properties can\'t be changed with this directive. \c
306 Use \'transitivity/1\' to add transitivity to similarity relation.').
307
308is_directive_valid(fuzzy_rel, [RelName, _Properties]) :-
309 (RelName == lEqThan ; RelName == gEqThan),
310 311 !,
312 throw_invalid_argument_error(fuzzy_rel, 2,
313 '"Less/Most general than" relations must be reflexive and transitive, \c
314 and transitive type must be in domain [yes, no, min, product, luka].').
315
316is_directive_valid(fuzzy_rel, [RelName, _Properties]) :-
317 nonvar(RelName),
318 utilities:relation_name(_RelSymbol, RelName),
319 320 !,
321 throw_invalid_argument_error(fuzzy_rel, 2,
322 'Closure properties must be a subset of {symmetric, reflexive, \c
323 transitive, transitive(Type)}, and transitive type must be in domain \c
324 [yes, no, min, product, luka].').
325
326is_directive_valid(fuzzy_rel, [_RelName, _Properties]) :-
327 328 !,
329 throw_invalid_argument_error(fuzzy_rel, 2,
330 'Relation symbol must be one of these: ~>, <~, ~1~, ~2~, ~3~.').
331
332is_directive_valid(fuzzy_rel, Arguments) :-
333 334 length(Arguments, Arity),
335 throw_wrong_arity_error(fuzzy_rel, Arity, 2).
336
340
341is_directive_valid(domain, [Name, Min, Max, Unit]) :-
342 atomic(Name), nonvar(Name), not(number(Name)),
343 not(utilities:atom_is_variable(Name)),
344 atomic(Unit), nonvar(Unit), not(number(Unit)),
345 not(utilities:atom_is_variable(Unit)),
346 integer(Min), integer(Max),
347 Min < Max,
348 not(flags:get_bpl_flag(fuzzy_domain(Name, [_, _, _]))),
349 350 !.
351
352is_directive_valid(domain, [Name, Min, Max, Unit]) :-
353 atomic(Name), nonvar(Name), not(number(Name)),
354 not(utilities:atom_is_variable(Name)),
355 atomic(Unit), nonvar(Unit), not(number(Unit)),
356 not(utilities:atom_is_variable(Unit)),
357 integer(Min), integer(Max),
358 Min < Max,
359 360 !,
361 swritef(Message, 'Fuzzy domain \'%w\' has already been defined.', [Name]),
362 throw_invalid_argument_error(domain, 4, Message).
363
364is_directive_valid(domain, [Name, Min, Max, Unit]) :-
365 atomic(Name), nonvar(Name), not(number(Name)),
366 not(utilities:atom_is_variable(Name)),
367 atomic(Unit), nonvar(Unit), not(number(Unit)),
368 not(utilities:atom_is_variable(Unit)),
369 integer(Min), integer(Max),
370 371 !,
372 throw_invalid_argument_error(domain, 4,
373 'Minimum value must be greater than maximum value.').
374
375is_directive_valid(domain, [Name, _Min, _Max, Unit]) :-
376 atomic(Name), nonvar(Name), not(number(Name)),
377 not(utilities:atom_is_variable(Name)),
378 atomic(Unit), nonvar(Unit), not(number(Unit)),
379 not(utilities:atom_is_variable(Unit)),
380 381 !,
382 throw_invalid_argument_error(domain, 4,
383 'Minimum and maximum values must be integers numbers.').
384
385is_directive_valid(domain, [Name, _Min, _Max, _Unit]) :-
386 (compound(Name) ; var(Name) ; number(Name)
387 ; utilities:atom_is_variable(Name)),
388 389 !,
390 throw_invalid_argument_error(domain, 4,
391 'Domain name must be an atom.').
392
393is_directive_valid(domain, [_Name, _Min, _Max, Unit]) :-
394 (compound(Unit) ; var(Unit) ; number(Unit)
395 ; utilities:atom_is_variable(Unit)),
396 397 !,
398 throw_invalid_argument_error(domain, 4,
399 'Domain measure unit must be an atom.').
400
401is_directive_valid(domain, Arguments) :-
402 403 length(Arguments, Arity),
404 throw_wrong_arity_error(domain, Arity, 4).
405
409
410is_directive_valid(fuzzy_set, [DomainName, Subsets]) :-
411 atomic(DomainName), nonvar(DomainName), not(number(DomainName)),
412 not(utilities:atom_is_variable(DomainName)),
413 flags:get_bpl_flag(fuzzy_domain(DomainName, _)),
414 findall(Name, flags:get_bpl_flag(fuzzy_domain(Name, [_Min, _Max, _Unit])), Domains),
415 get_subset_names(Domains, CurrentSubsetNames),
416 check_fuzzy_subsets(Subsets, CurrentSubsetNames),
417 418 !.
419
420is_directive_valid(fuzzy_set, [DomainName, _Subsets]) :-
421 (compound(DomainName) ; var(DomainName) ; number(DomainName)
422 ; utilities:atom_is_variable(DomainName)),
423 424 !,
425 swritef(Message, 'Domain name must be an atom.', [DomainName]),
426 throw_invalid_argument_error(fuzzy_set, 2, Message).
427
428is_directive_valid(fuzzy_set, [DomainName, _Subsets]) :-
429 430 !,
431 swritef(Message, 'Fuzzy domain \'%w\' is undefined.', [DomainName]),
432 throw_invalid_argument_error(fuzzy_set, 2, Message).
433
434is_directive_valid(fuzzy_set, Arguments) :-
435 436 length(Arguments, Arity),
437 throw_wrong_arity_error(fuzzy_set, Arity, 2).
438
439is_directive_valid(wn_connect, []) :-
440 (getenv('WNDB',_Folder)
441 ->
442 true
443 ;
444 utilities:checkwnenv(Folder),
445 (exists_directory(Folder)
446 ->
447 true
448 ;
449 450 throw_invalid_argument_error(wn_connect, 0,
451 'WNDB environment variable is not set or is incorrect. Please either set it at the OS terminal or use this directive with an argument indicating the directory of the Wordnet database.')
452 )
453 ).
454
455is_directive_valid(wn_connect, [QFolder]) :-
456 utilities:remove_quotes(QFolder,Folder),
457 (exists_directory(Folder)
458 ->
459 setenv('WNDB',QFolder)
460 ;
461 462 throw_invalid_argument_error(wn_connect, 1,
463 'Argument must be an existent directory.')).
464
465is_directive_valid(wn_gen_prox_equations, [Measure, ListOfListOfWords]) :-
466 is_list(ListOfListOfWords),
467 (maplist(is_list,ListOfListOfWords)
468 ->
469 ensure_loaded_wn,
470 (\+ wn_measure(Measure)
471 ->
472 473 throw_invalid_argument_error(wn_gen_prox_equations, 2,
474 'Argument must be a valid measure.')
475 ;
476 flatten(ListOfListOfWords, ListOfWords),
477 check_wn_words(ListOfWords, WordNotFound),
478 (var(WordNotFound)
479 ->
480 true
481 ;
482 483 atomic_list_concat(['Word not found in WordNet database: ', WordNotFound, '.'], ErrorMessage),
484 throw_invalid_argument_error(wn_gen_prox_equations, 2,
485 ErrorMessage)))
486 ;
487 488 throw_invalid_argument_error(wn_gen_prox_equations, 2,
489 'Second argument must be a list of lists.')
490 ).
491
492
494
495is_directive_valid(wn_gen_prox_equations, [Measure, Auto]) :-
496 ensure_loaded_wn,
497 (\+ wn_measure(Measure)
498 ->
499 500 throw_invalid_argument_error(wn_gen_prox_equations, 1,
501 'Argument must be a valid measure.')
502 ;
503 (\+ member(Auto, [auto, automatic, automatically])
504 ->
505 506 throw_invalid_argument_error(wn_gen_prox_equations, 1,
507 'Argument must be either ''auto'', or ''automatic'', or ''automatically''.')
508 ;
509 true)).
510
511
512
525check_fuzzy_subsets([], _DefinedSubsets).
526
527check_fuzzy_subsets([Subset|MoreSubsets], DefinedSubsets) :-
528 compound(Subset),
529 Subset =.. [SubsetName|Values],
530 atomic(SubsetName), nonvar(SubsetName), not(number(SubsetName)),
531 not((member(AnySubset, DefinedSubsets), AnySubset =.. [SubsetName|_])),
532 (length(Values, 3) ; length(Values, 4)),
533 ascending_numbers(Values),
534 535 !,
536 NewDefinedSubsets = [SubsetName|DefinedSubsets],
537 check_fuzzy_subsets(MoreSubsets, NewDefinedSubsets).
538
539check_fuzzy_subsets([Subset|_MoreSubsets], DefinedSubsets) :-
540 compound(Subset),
541 Subset =.. [SubsetName|Values],
542 atomic(SubsetName), nonvar(SubsetName), not(number(SubsetName)),
543 not((member(AnySubset, DefinedSubsets), AnySubset =.. [SubsetName|_])),
544 (length(Values, 3) ; length(Values, 4)),
545 546 547 !,
548 throw_invalid_argument_error(fuzzy_set, 2,
549 'The points that define a fuzzy subset must be integer numbers, \c
550 and they must be in ascending order.').
551
552check_fuzzy_subsets([Subset|_MoreSubsets], DefinedSubsets) :-
553 compound(Subset),
554 Subset =.. [SubsetName|_Values],
555 atomic(SubsetName), nonvar(SubsetName), not(number(SubsetName)),
556 not((member(AnySubset, DefinedSubsets), AnySubset =.. [SubsetName|_])),
557 558 !,
559 throw_invalid_argument_error(fuzzy_set, 2,
560 'Each linguistic term must be defined by a list with 3 integer \c
561 numbers for triangular subsets or 4 integer numbers for \c
562 trapezoidal subsets.').
563
564check_fuzzy_subsets([Subset|_MoreSubsets], _DefinedSubsets) :-
565 compound(Subset),
566 Subset =.. [SubsetName|_Values],
567 atomic(SubsetName), nonvar(SubsetName), not(number(SubsetName)),
568 569 !,
570 swritef(Message, 'Fuzzy subset \'%w\' is defined more than once.', [SubsetName]),
571 throw_invalid_argument_error(fuzzy_set, 2, Message).
572
573check_fuzzy_subsets([Subset|_MoreSubsets], _DefinedSubsets) :-
574 compound(Subset),
575 Subset =.. [SubsetName|_Values],
576 (compound(SubsetName) ; var(SubsetName) ; number(SubsetName)),
577 578 !,
579 swritef(Message, 'Fuzzy subset name must be an atom.', [SubsetName]),
580 throw_invalid_argument_error(fuzzy_set, 2, Message).
581
582check_fuzzy_subsets([_Subset|_MoreSubsets], _DefinedSubsets) :-
583 584 !,
585 throw_invalid_argument_error(fuzzy_set, 2,
586 'A fuzzy set must be defined using a compound term.').
587
588
589
604throw_invalid_argument_error(Name, Arity, Message) :-
605 swritef(ErrorMessage, 'BPL directive \'%w/%w\' is invalid. %w',
606 [Name, Arity, Message]),
607 throw(directive_error(ErrorMessage)).
618throw_wrong_arity_error(Name, Arity, CorrectArity) :-
619 swritef(ErrorMessage, 'BPL directive \'%w/%w\' is invalid. Use \'%w/%w\' \c
620 instead.', [Name, Arity, Name, CorrectArity]),
621 throw(directive_error(ErrorMessage)).
622
623
624
636get_subset_names(DomainNames, SubsetNames) :-
637 get_subset_names_aux(DomainNames, [], SubsetNames),
638 !.
650get_subset_names_aux([], FinalSubsetNames, FinalSubsetNames).
651
652get_subset_names_aux([Domain|MoreDomains], SubsetNames, FinalSubsetNames) :-
653 (
654 655 flags:get_bpl_flag(fuzzy_subsets(Domain, Subsets)),
656 findall(SubsetName, (member(SubsetDefinition, Subsets),
657 SubsetDefinition =.. [SubsetName|_]),
658 ThisSubsetNames)
659 ;
660 661 ThisSubsetNames = []
662 ),
663 664 append(SubsetNames, ThisSubsetNames, NextSubsetNames),
665 get_subset_names_aux(MoreDomains, NextSubsetNames, FinalSubsetNames)