<p>Ad 3, current implementations of <code>clpfd/clpz</code> are all a library that has very few connections to the actual compilation process (&quot;preparation for execution&quot;). So there is no such predicate-wise optimization that you are hoping for. The clauses remain and are tried out one after the other — maybe with a little bit indexing due to the 0es  in the head.  If you want to get efficient code, you need to combine the common cases directly. E.g., you might first consider in a single rule <code>I in 1..3, J in 1..3</code> and then avoid all those other comparisons.  This means you would need some intermediary auxiliary predicate.</p>
<p>Also note the fine difference between <code>I #=&lt; 3, I #&gt; 0</code> and <code>I in 1..3</code>. The former succeeds for <code>I = 1+0</code> while the latter produces a type error. And for <code>0+0</code> OTOH, your program fails. You probably want at least consistent behaviour wherefore you may also use <code>(#)/1</code> in places where general expressions are expected.</p>
<p>Ad 4, <code>if_/3</code> or rather <code>reif</code> might be of interest, because you have just the special case of 0. Also, please note that often in stead of nesting <code>if_/3</code> you may use a more complex reified condition as <a href="https://arxiv.org/abs/1607.01590" rel="nofollow noreferrer">here</a> on page 8 in <code>treememberd_t/3</code>.</p>
<p>Ad 1&amp;2 there is some support for this in some systems, but it still is very bleeding edge. In particular if you want to use it together with constraints.</p>
<hr />
<p>One final remark about your code in general. What you did was to take one-by-one an existing algorithm and you recoded it directly. Think of the last clause where you explore two paths independently and then join their results.  You only can do this, because you know a lot about the actual problem, in particular both paths will have a solution.  The only case were actual non-determinism happens is the instantiation of the coordinates.</p>
CLPFD and recursive formulations
<p>Given a <code>field</code>, find the &quot;cheapest&quot; path from <code>(0, 0)</code> to <code>(3, 3)</code>. Only the moves <em>up</em> and <em>to the right</em> are allowed.</p>
<pre><code>field([
   [1, 1, 1, 1],
   [3, 3, 4, 3],
   [3, 3, 1, 3],
   [3, 3, 1, 1] 
]).

nth([A|_], 0, A).
nth([_|T], I, A) :- I #&gt; 0, J #= I - 1, nth(T, J, A).

at(I, J, E) :- field(M), nth(M, I, R), nth(R, J, E).
</code></pre>
<p>Here's my recursive solution:</p>
<pre><code>:- use_module(library(clpfd)).

price(0, 0, P) :- at(0, 0, P).
price(I, 0, P) :-
  I #=&lt; 3,
  I #&gt; 0,
  I0 #= I - 1,
  price(I0, 0, P0),
  at(I, 0, P1),
  P #= P0 + P1.
price(0, J, P) :-
  J #=&lt; 3,
  J #&gt; 0,
  J0 #= J - 1,
  price(0, J0, P0),
  at(0, J, P1),
  P #= P0 + P1.
price(I, J, P) :-
  I #=&lt; 3,
  J #=&lt; 3,
  I #&gt; 0,
  J #&gt; 0,
  I0 #= I - 1,
  J0 #= J - 1,
  price(I0, J, P0),
  price(I, J0, P1),
  at(I, J, P2),
  P #= min(P0, P1) + P2.
</code></pre>
<p>I can run it in different directions:</p>
<pre><code>?- price(3, 3, P).
?- price(I, J, P), I #= 3, J #= 3.
?- price(I, J, P), P #&gt; 10.
</code></pre>
<ol>
<li>Is it possible to memorize the intermediate steps, and is it strictly necessary?</li>
<li>Is there a way to use memorization only when <code>I</code> and <code>J</code> are grounded?</li>
<li>How does CLPFD deal with the fact that there are 4 rules for the predicate <code>price</code>? Does the library merge the different rules into one big if?</li>
<li>Is it better to write a single rule <code>price</code> with <code>if_</code>'s inside?</li>
</ol>