Arithmetic function 'cputime' resolution

Motivated by this thread: Different results when using library(simplex) or R-package lpSolve / lpSolveAPI - #6 by ridgeworks
I’ve been looking at how to use library(simplex) in a CLP framework, the main issue being there’s an API mismatch. One of the main issues is that variables within a CLP system are represented by attributed variables while variables in simplex constraints are represented by atoms or compound terms, w.g., x or x(0). In building a CLP friendly wrapper for library(simplex), I wanted a light weight mechanism to associate a name with a CLP variable for relatively short period of time.

The first prototype used:

simplex_var_(V,var(Vstr)) :-  term_string(V,Vstr).

This looks up a variable name usable by simplex given a constrained variable V. Vstr is the “address” of the variable V converted to a string so it will be unique for any variable of interest. But it’s potentially not safe due to variable relocation during garbage collection. And it’s unlikely to be the most performant solution based on a simple benchmark.

A better approach is to use an attribute to store a unique ID of some kind. Using the cputime (a monotonically increasing value) was the first stab but appears to have platform dependancies and will probably start to fail at microsecond resolution (two successive queries may yield the same value). Using the inference counter neatly solves this problem. So the code becomes:

simplex_var_(V,SV) :- 
	(get_attr(V,clpBNR_toolkit,SV)
	 -> true
	 ;  statistics(inferences,Vname), SV = var(Vname), put_attr(V,clpBNR_toolkit,SV)
	).
		 
attr_unify_hook(var(_),_).     % unification always does nothing and succeeds

This works quite nicely and is 10 times faster than a term_string based implementation.

Using the new clpBNR wrapper module for Example 2 from library(simplex):

?- X1::real(0,1), X2::real(0,2), lin_maximize(7*X1+4*X2,{6*X1+4*X2=<8},Value).
X1 = 1,
X2 = 1r2,
Value = 9.

?- X1::integer(0,1), X2::integer(0,2), lin_maximize(7*X1+4*X2,{6*X1+4*X2=<8},Value).
X1 = 0,
X2 = 2,
Value = 8.

The new variable name attribute is removed before the completion of lin_minimize/3 so there’s no lingering effects.