0

I have a question that is on the topic of this one (Create Prolog Vocabulary), but uses a slightly different vocabulary.

I've seen the answer, and, even though I know it's correct, I don't want to describe the circuit that way. I want to be able to determine terminals and signals.

The main difference between the vocabularies used is that mine uses

signal(in(inPortNumber, portName), signalValue)

With that in mind, I have a few questions:

SOLVED 1 - How do I write "If C is a circuit, let its arity be I, J (I = numInPorts, J = numOutPorts). For all possible values of N (0 < N < I), the in port number N of C is a terminal"?

This is what I have, but it's not working (infinite loop):

% Check arity of IN wires
% If more in wires than gate can support, it's an error
terminal(in(N, C)) :- circuit(C), arity(C, I, _J), N < I, N > 0.

EDIT 2 - How do I write "If terminals T1 and T2 are connected, and T2 has been assigned a signal, T1 is also assigned that signal value"?

This is what I have:

% FACTS
circuit('c1').
arity('c1', 3, 2).
gate('x1').
type('x1', xorGate).
are_connected(in(1, 'c1'), in(1, 'x1')).
are_connected(in(2, 'c1'), in(2, 'x1')).
signal(in(1, 'c1'), 1).
signal(in(2, 'c1'), 1).
signal(in(3, 'c1'), 1).

% RULES
% All gates are circuits
circuit(G) :- gate(G).

% Check arity of IN wires
terminal(in(N, G)) :- circuit(G), arity(G, I, _J), N =< I, N > 0.
% Check arity of OUT wires
terminal(out(N, G)) :- circuit(G), arity(G, _I, J), N =< J, N > 0.

% Signals do only exist in terminals
terminal(T) :- signal(T, _V).

% Arity
arity(G, 1, 1) :- gate(G), type(G, notGate). % NOT gate
arity(G, 2, 1) :- gate(G), type(G, V), not(V = notGate). % Other gates

% Commutativity
connected(T1, T2) :- are_connected(T1, T2), !.
connected(T2, T1) :- are_connected(T1, T2), !.

% Connectivity
same_signal(T1, T2) :- terminal(T1), terminal(T2), not(T1 = T2), connected(T1, T2).
signal(T1, V) :- same_signal(T1, T2), signal(T2, V), !.
signal(T2, V) :- same_signal(T1, T2), signal(T1, V), !.

The problem is that, when asking:

signal(in(1, x1), V).

It throws an error, as things aren't sufficiently instantiated. I know where and what the problem is, but I don't know how to solve it.

Looking forward to answers/suggestions. I'm new to Prolog, so all tips are welcome (but yes, I do know I should put clauses of the same predicate together).

Community
  • 1
  • 1
Daniel Carvalho
  • 473
  • 1
  • 5
  • 17
  • How is `circuit/1` defined? One problem circular logic point may be that you have `terminal(T) :- signal(T, V).` but also `signal(T1, V) :- terminal(T1), ...` These refer back to each other without any reduction to a terminal case. – lurker Jan 30 '14 at 11:50
  • One thing: I think you should get rid of your second `signal/2` clause (`signal(T2,V) :-...`). Since `same_signal` already deals with the commutativity of arguments, that second clause is redundant and could be a further cause of a loop later on. – lurker Feb 01 '14 at 18:47

1 Answers1

2

In case 1, If C is a circuit, let its arity be I, J (I = numInPorts, J = numOutPorts). For all possible values of N (0 < N < I), the in-port number N of C is a terminal

terminal(in(N, C)) :-   % in(N, C) is a terminal if...
    circuit(C),         % C is a circuit and...
    arity(C, I, _J),    % Arity of C is I, _ and...
    N < I, N > 0.       % 0 < N < I

This appears to match your natural language description. You mentioned that it causes an infinite loop, but there's nothing in this code by itself to cause such a loop. You would need to show the definition of circuit/1 to break that down further.

In case 2, If terminals T1 and T2 are connected, and T2 has been assigned a signal, T1 is also assigned that signal value

terminal(T) :- signal(T, V).  % T is a terminal if it is assigned a signal

signal(T1, V) :-       % T1 is assigned signal V if...
    terminal(T1),      % T1 is a terminal and...
    terminal(T2),      % T2 is another terminal and...
    connected(T1, T2), % T1 and T2 are connected and...
    signal(T2, V).     % T2 is assigned signal V

The second clause here already expresses your complete description.


[Edit based upon OP's comments] The first clause, terminal(T) :- signal(T, V) appears to be a source for your infinite loop since it creates a circular inference between signal and terminal in these two clauses. A potential solution would be to rename the signal/2 clause to same_signal/2 in order to avoid conflict with the fact name, signal/2.
[Edit based upon OP's updated problem statement] When indicating an error, it's best to state the precise error message, which in this case, is ERROR: =</2: Arguments are not sufficiently instantiated. In prolog, the inequality predicates like =</2 require that both sides of the inequality be fully instantiated.

The reason you are into this condition is that terminal(T1) or terminal(T2) in same_signal/2 will eventually call the predicate signal/2:

terminal(T) :- signal(T, _V).

For some iterations, signal/2 is satisfied by fully instantiated facts, and the search through these works. But then it will backtrack finally to the predicate signal/2 (you have two clauses for the predicate) and yield an uninstantiated terminal. This causes the terminal/1 predicate clauses to fail because N is uninstantiated.

Beyond this, there is still a potential danger of infinite recursion between terminal/1 and signal/2 due to the relationship between their predicates. Something to watch for.


[EDIT based upon OP's further comment] The root cause of the existing "uninstantiated variable" problem is that the terminal/1 predicate which checks arity is also being queried to generate a terminal. However, the logic for the arity check isn't designed to generate a new terminal, but to check an existing one (or at least check a terminal that already has the arity instantiated).

If the only purpose of the arity check clauses is just that, to check arity, then it might need a different name and to be called accordingly.

lurker
  • 56,987
  • 9
  • 69
  • 103
  • The first one was almost correct, I just forgot to add "N > 0" on my code, and it shouldn't be "N < I", but "N =< I". Circuit/1 is just a fact. On the second one, terminal :- signal(T, V) is essential, because one can only declare signals as facts, not terminals, so, in order to make the second rule work, the first rule must exist. Here's how I've worked around the problem: sameSignal(T1, T2) :- terminal(T1), terminal(T2), not(T1 = T2), connected(T1, T2). signal(T1, V) :- sameSignal(T1, T2), signal(T2, V), !. signal(T2, V) :- sameSignal(T1, T2), signal(T1, V), !. – Daniel Carvalho Jan 31 '14 at 13:27
  • @DanielCarvalho I see. Yes, renaming your `signal/2` predicate to `same_signal/2` (note typical Prolog naming convensions - under_scores generally used instead of camelCase) would be an appropriate solution then in this case. Out of context, it was difficult for me to tell what were fundamental facts versus derived terms. – lurker Jan 31 '14 at 13:31
  • Thanks for the naming tip, @mbratch. Yes, I should have mentioned what is a fact, and what isn't. I'm probably going to edit the post soon, so that it's clearer. I've got it almost finished, but it's still on infinite loops some times when I try to figure out the final output of the circuit. – Daniel Carvalho Jan 31 '14 at 13:34
  • I appreciate your answer, but, as I said, I know what and where the problem is. The main problem here is that I have no idea on how to rewrite my rules so that it won't happen. – Daniel Carvalho Jan 31 '14 at 15:04
  • @DanielCarvalho that depends upon the intent of your logic, which isn't totally clear. For example, are the clauses for `terminal/1` which check arity also intended to define a `terminal`? If not, then this should have a different name, such as `terminal_arity/1` and called as such where needed to avoid confusion in the logic between the two definitions. Similarly for `signal/2`: is a `signal` defined both by the facts and the predicates? Or do they serve two different purposes? – lurker Jan 31 '14 at 17:29
  • Yes, and signal is defined by both facts and predicates. That's because if an in or out gate exists, then it's a terminal. That's the purpose of the arity check - if an in gate number is higher than the arity, we've got an error. As for the signal, the facts state the input signals of the circuit, and we want to query the output signals. Thus, to calculate signal(out(1, circuit)), we have to calculate the in signals after passing through the logical gates. – Daniel Carvalho Feb 01 '14 at 18:42
  • I totally understand what's the problem, but I don't know how to write the solution in Prolog. I have a non-generic solution that can handle the current database, so I'm just continuing with this out of curiosity and to be able to figure out in the future, if I ever use Prolog again. Would you mind writing a solution, even if it's for another problem created by you? – Daniel Carvalho Feb 02 '14 at 23:14
  • Here's what an exact extract of the problem: We have a predicate (max_num/2) to say that the maximum value of the number in a function (func/2) that associates an element to a number elem is maxNum. We want to declare as facts as many valid numbers as we can. How I see the problem in Prolog (not properly written, though): valid_num(func(num, elem)) :- max_num(elem, maxNum), num < maxNum. max_num(elem, maxNum). But this won't work for the reason stated on this whole discussion. – Daniel Carvalho Feb 02 '14 at 23:17