###
# Modern Albufeira Prolog Interpreter
#
# Warranty & Liability
# To the extent permitted by applicable law and unless explicitly
# otherwise agreed upon, XLOG Technologies AG makes no warranties
# regarding the provided information. XLOG Technologies AG assumes
# no liability that any problems might be solved with the information
# provided by XLOG Technologies AG.
#
# Rights & License
# All industrial property rights regarding the information - copyright
# and patent rights in particular - are the sole property of XLOG
# Technologies AG. If the company was not the originator of some
# excerpts, XLOG Technologies AG has at least obtained the right to
# reproduce, change and translate the information.
#
# Reproduction is restricted to the whole unaltered document. Reproduction
# of the information is only allowed for non-commercial uses. Selling,
# giving away or letting of the execution of the library is prohibited.
# The library can be distributed as part of your applications and libraries
# for execution provided this comment remains unchanged.
#
# Restrictions
# Only to be distributed with programs that add significant and primary
# functionality to the library. Not to be distributed with additional
# software intended to replace any components of the library.
#
# Trademarks
# Jekejeke is a registered trademark of XLOG Technologies AG.
##
from collections import OrderedDict
from nova.core import (is_variable, set_to_list,
make_check, walk_vars, walk_compute,
exec_build, walk_uncompute, set, VAR_MASK_SEEN,
exec_unify, check_integer, make_error, Compound,
make_arithmetic, exec_eval)
import math
#######################################################################
# term_singletons/2 #
#######################################################################
###
# term_singletons(T, L):
# The built-in succeeds in L with the singleton variables of T.
##
def test_term_singletons(args):
alpha = exec_build(args[0])
try:
res = walk_compute(alpha, init_map, union_map)
finally:
walk_uncompute(alpha)
for key, val in list(res.items()):
if val:
del res[key]
res = set_to_list(res.keys())
return exec_unify(args[1], res)
EMPTY_MAP = OrderedDict()
def init_map(first):
if is_variable(first):
return dict([[first, False]])
else:
return EMPTY_MAP
def union_map(first, second):
if len(first) == 0:
return second
if len(second) == 0:
return first
first = OrderedDict(first)
for key, val in second.items():
value = first.get(key, NotImplemented)
if value is not NotImplemented:
value = True
else:
value = val
first[key] = value
return first
#######################################################################
# ground/1 and nonground/2 #
#######################################################################
###
# ground(T): [TC2 8.3.10]
# The built-in succceeds if T is ground.
##
def test_ground(args):
alpha = exec_build(args[0])
res = walk_vars(alpha, lambda node: True, VAR_MASK_SEEN)
walk_vars(alpha, lambda node: True, 0)
return not res
###
# nonground(T, V):
# The built-in succeeds if T is non-ground and V is the first variable.
##
def test_nonground(args):
alpha = exec_build(args[0])
hit = NotImplemented
def nonground2(node):
nonlocal hit
hit = node
return True
res = walk_vars(alpha, nonground2, VAR_MASK_SEEN)
walk_vars(alpha, lambda node: True, 0)
return res and exec_unify(args[1], hit)
#######################################################################
# divmod/4 and gcd/3 #
#######################################################################
###
# divmod(X, Y, Z, T):
# If X and Y are both integers then the predicate succeeds in
# Z with the division of X by Y, and in T with the modulo of X by Y.
##
def test_divmod(args):
alpha = exec_build(args[0])
check_integer(alpha)
beta = exec_build(args[1])
check_integer(beta)
if beta == 0:
raise make_error(Compound("evaluation_error", ["zero_divisor"]))
(divres, modres) = divmod(alpha, beta)
if not exec_unify(args[2], divres):
return False
return exec_unify(args[3], modres)
###
# gcd(X, Y, Z):
# If X and Y are integers then the predicate succeeds in Z
# with the greatest common divisor of X and Y.
##
def arit_gcd(args):
alpha = exec_eval(args[0])
check_integer(alpha)
beta = exec_eval(args[1])
check_integer(beta)
return math.gcd(alpha, beta)
#######################################################################
# Fast Lib Init #
#######################################################################
def main():
set("term_singletons", 2, make_check(test_term_singletons))
set("ground", 1, make_check(test_ground))
set("nonground", 2, make_check(test_nonground))
set("divmod", 4, make_check(test_divmod))
set("gcd", 3, make_arithmetic(arit_gcd))