Message-ID: <152310Z24011995@anon.penet.fi>
Path: cantaloupe.srv.cs.cmu.edu!das-news2.harvard.edu!news2.near.net!howland.reston.ans.net!EU.net!news.eunet.fi!anon.penet.fi
Newsgroups: comp.lang.prolog
From: an150641@anon.penet.fi
X-Anonymously-To: comp.lang.prolog
Organization: Anonymous contact service
Reply-To: an150641@anon.penet.fi
Date: Tue, 24 Jan 1995 15:19:35 UTC
Subject: problem?????
Lines: 205



/*
> SPE4HH@cf.ac.uk            University of Wales College of Cardiff, Cardiff, WALES, UK.


> Q) There is a set of 5 terminals.You are to provide a data file, 5x5 of 0s and
> 1s representing information about electrical connections such that 1 in row i
> and column j shows that terminal i is directly connected to terminal j; each
> terminal is treated as being directly connected to itself. Write a set of
> predicates which, given the number of any terminal lists the terminal to which
> it is connected, either directly or indirectly.The program must work for any
> data file in the correct format.

Refs:

Warshall, S. - "A Theorem on Boolean Matrices", J. ACM 9:1, 11-12

Aho, Hopcroft, Ullman - "The Design and Analysis of Computer Algorithms"
	(nice treatment of transitive closure).

O'Keefe - The Craft of Prolog
	(has a Prolog implementation of Warshall's Algorithm)

Here is my Prolog implementation using a partially instantiated "matrix",
(zeros are represented by free vars).

I assume connections are directed (ie i->j does not necessarily imply j->i ).
I don't like the limit of 5 in the spec so I've generalized.
I assume the file layout is n lines with n Boolean digits on each line
	with possibly newline chars at the end of each line. I ignore
	whitespace so this program will deal with more general layout 
	than the spec requires.
*/

go( Size ) :-	
	rd_bit_matrix( Size, Size, Matrix ),
	lazy_identity( Size, Matrix ),
	tran_close( Matrix, 1, Matrix ),
	wr_all( Matrix, 1 ).

tran_close( Matrix, I, Full_Matrix ) :-
	Matrix == [] ->
		true
	;
		Matrix = [H|T],
		or_rows( Full_Matrix, I, H ),
		% invariant: all rows of Full_Matrix have (at least) the correct
		%		result for all paths through vertices =< I
		I1 is I + 1,
		tran_close( T, I1, Full_Matrix ).

or_rows( Matrix, I, Ith_Row ) :-
	Matrix == [] ->
		true
	;
		Matrix = [ H | T ],
		nth_elem( I, H, Elem ),
		(
		Elem == 1 ->			% if Ith_Row is reachable from H
			or_row( Ith_Row, H )	% 	then "OR" Ith_Row into H
		;
			true
		),
		or_rows( T, I, Ith_Row ).

or_row( R1, R2 ) :-		% update R2 with everything reachable from R1
	R1 == [] ->
		true
	;
		R1 = [H1|T1],
		R2 = [H2|T2],
		(
		H1 == 1 ->
			H2 = 1
		;
			true
		),
		or_row( T1, T2 ).


wr_all( Matrix, N ) :-
	Matrix == [] ->
		true
	;
		Matrix = [V|Vs],
		write( N ),
		write(' is connected to '),
		wr_lst( V, 1 ),
		nl,
		N1 is N + 1,
		wr_all( Vs, N1 ).

wr_lst( L, I ) :-
	L == [] ->
		true
	;
		L = [H|T],
		(
		H == 1 ->
			write( I ), write(' ')
		;
			true
		),
		I1 is I + 1,
		wr_lst( T, I1 ).

rd_bit_vector( Num_Bits_To_Read, Vector ) :-
	Num_Bits_To_Read == 0 ->
		Vector = []
	;
		get( Ch ),
		Num_Bits_To_Read_1 is Num_Bits_To_Read - 1,
		(
		Ch == 0'0 ->
			Vector = [_|Rest],
			rd_bit_vector( Num_Bits_To_Read_1, Rest )
		; 
		Ch == 0'1 ->
			Vector = [1|Rest],
			rd_bit_vector( Num_Bits_To_Read_1, Rest )
		;
			write('Error: bad char in input'(Ch)), fail
		).

rd_bit_matrix( Num_Lines_To_Read, Matrix_Size, Matrix ) :-
	Num_Lines_To_Read == 0 ->
		Matrix = []
	;
		Matrix = [Vector|Vectors],
		rd_bit_vector( Matrix_Size, Vector ),
		Num_Lines_To_Read_1 is Num_Lines_To_Read - 1,
		rd_bit_matrix( Num_Lines_To_Read_1, Matrix_Size, Vectors ).


nth_elem( Col, [V|Vs], Elem ) :-
	Col == 1 ->
		V = Elem
	;
		Col_1 is Col - 1,
		nth_elem( Col_1, Vs, Elem ).

lazy_identity( Size, Identity ) :-
	lazy_identity( Size, 1, Identity ).

lazy_identity( Size, Row_Num, Identity ) :-
	Row_Num > Size ->
		Identity = []
	;
		Identity = [Row|Rows],
		nth_elem( Row_Num, Row, 1 ),
		Row_Num1 is Row_Num + 1,
		lazy_identity( Size, Row_Num1, Rows ).

/*

Here are some examples

yes
| ?- go(5).
|: 10000
|: 01000
|: 10100
|: 00110
|: 00001
1 is connected to 1 
2 is connected to 2 
3 is connected to 1 3 
4 is connected to 1 3 4 
5 is connected to 5 

yes
| ?- | ?- go(5).
|: 10000
|: 01000
|: 10100
|: 00110
|: 00011
1 is connected to 1 
2 is connected to 2 
3 is connected to 1 3 
4 is connected to 1 3 4 
5 is connected to 1 3 4 5 

yes
| ?- | ?- go(5).
|: 00011
|: 00110
|: 10100
|: 01000
|: 10000
1 is connected to 1 2 3 4 5 
2 is connected to 1 2 3 4 5 
3 is connected to 1 2 3 4 5 
4 is connected to 1 2 3 4 5 
5 is connected to 1 2 3 4 5 

yes
| ?- | ?- 
*/
-------------------------------------------------------------------------
To find out more about the anon service, send mail to help@anon.penet.fi.
Due to the double-blind, any mail replies to this message will be anonymized,
and an anonymous id will be allocated automatically. You have been warned.
Please report any problems, inappropriate use etc. to admin@anon.penet.fi.
