1
votes

I am in my initial phase of writing code in Prolog and am still trying wrap my head around the paradigm so please pardon the primitiveness of this question.

I read in Wikipedia

A rule is of the form
Head :- Body.
and is read as "Head is true if Body is true".

That's simple enough. So I am building a knowledge base that simulates the functioning of a 1-bit adder.

In doing so, I am trying to create a rule for the following:

If there exists a gate X, and X is an AND gate, and X has a terminal going out of it, and that terminal has a signal and the signal is 0 THEN gate X must also have at least one input terminal that has a signal of 0.

As a Prolog rule, I wrote this to reflect my above sentence:

gate(X) /\ gate_type(X, and) /\ terminal(T, X, out) /\ signal(T, SIG) /\ (SIG is 0) :- (gate(X) /\ gate_type(X, and) /\ terminal_type(R, X, in) /\ signal(R, 0)).

To test my rule, I had a terminal t7 that is a terminal of an AND gate.

terminal_type(t7, a1, in).
gate_type(a1, and).

When I ask Prolog: signal(t7, 1), signal(t8, 1), signal(t9, X). or anything like that, Mr. Prolog tells me

X = 1;
X = 0;

The answer I get should be only X = 1.

1
I think that you might need to rewrite your rule as a Horn clause: en.wikipedia.org/wiki/Horn_clausePeter Hude

1 Answers

2
votes

Welcome to Prolog programming! It's very cool that you're coming at it from the hardware, almost as far from this as you can get.

I think I see two problems.

The first one is that your definition leaves out the defining characteristic of the AND gate, which is that when both inputs are 1 the output will be 1. Your translation into Prolog is a little odd-looking but certainly should take this into account. So I think in Prolog what you're trying to say is this:

signal(R, 0) :- 
  gate(X), gate_type(X, and), 
  terminal_type(R, X, out),
  terminal_type(R1, X, in), signal(R1, 0).

This isn't the whole story though. You'll need this too:

signal(R, 1) :- 
  gate(X), gate_type(X, and), 
  terminal_type(R, X, out),
  terminal_type(R1, X, in), terminal_type(R2, X, in), R1 \= R2,
  signal(R1, 1), signal(R2, 1).

This might be correct, but the second problem is that signal(t7, 1) is not an assertion, so it doesn't wind up in your fact database. It's just a bald structure, so it doesn't add anything to your query. The simplest solution would be to just add it to your database directly:

signal(t7, 1).
signal(t8, 1).

Then do your query:

signal(t9, X).

Or, you could assertz/1 it:

assertz(signal(t7, 1)), assertz(signal(t8, 1)), signal(t9, X).

But that's kind of sloppy, because assert is a side-effect that isn't undone on backtracking.

In practice, most of the time you either make something part of the dynamic query by passing it along, or you make it part of the fact database. Mixing the two gets hard to reason about.

If I were you, I would probably simplify things by reducing the number of different fact "types" to something more like this:

% gate(Name, Type, Input1, Input2, Output)
gate(a1, and, t7, t8, t9).

Then you could really simplify the predicates by quite a bit:

signal(Out, 0) :-
  gate(_, and, R1, R2, Out),
  ( signal(R1, 0) ; signal(R2, 0)).
signal(Out, 1) :-
  gate(_, and, R1, R2, Out),
  signal(R1, 1),
  signal(R2, 1).