Chris Pollett > Old Classes >
CS156

( Print View )

Student Corner:
  [Grades Sec1]
 
  [Submit Sec1]
 
  [
Lecture Notes]

Course Info:
  [Texts & Links]
  [Topics]
  [Grading]
  [HW Info]
  [Exam Info]
  [Regrades]
  [Honesty]
  [Announcements]

HW Assignments:
  [Hw1]  [Hw2]  [Hw3]
  [Hw4]

Practice Exams:
  [Mid1]  [Mid2]  [Final]

                           












HW3 Solutions Page

Return to homework page.

Test documents

This test file archive contains the files I used to test your homeworks. The filename gives the correct classification. These are scanned OCR'd documents so contain many weird typos. The original documents in case you want to check them out are:

Promoting and Selling Your art. Carole Katchen. Watson Guptill Publications. 1978. pp68--69. Classifcation: N8600 K37

Chicago Architects Design. The Art Institute of Chicago. Rizzoli International Publications. 1982. pp71--72. Classification: NA2706 U6C45 1982.

All the Sculpture of Michelangelo. Vol 11. Franco Russoli. Complete Library of World Art. 1963. pp10-11. Classsifcation: NB 623. B9 R853 1963.

Course in Pencil Sketching. Book 3: Boats and Harbors. Ernest W. Watson. 1957. pp24--25. Classification: NC890 W29.vol3.

The History of Painting in Canada: Toward a people's art. Barry Lord. NC Press. 1974. pp28--29. ND240 L67.

Still Life Painting From Antiquity to the Twentieth Century. 2nd Ed. Charles Sterling. Harper and Row. 1981. p46. Classification: ND 1390 S713 1981.

Practical Guide to Etching and Other Intaglio Printmaking Techniques. Manly Banister. Dover 1986. pp7--8. Classification NE1625.B36 1986.

The American Chair 1630-1890. Marion Day Iverson. Hastings House Publishers. 1957. pp75--76 Classification: NK2715 I85. 1981.

California Pottery: From Missions to Modernism. Bill Stern. Chronicle Books. pp18--19. Classification: NK4025.C2 S74.

Art and Culture. Critical Essays. Clement Greenberg. Beacon Press. 1984. pp32--33. Classifcation: NX454 G 73. 1984.

The Experiment

I gave my wife a list of what the classification were and the samples above in a disguised order. She had no experience with the Library of Congress Classification schemes. She took about 10 minutes to do the test and got 5 out of 10 correct. I then placed the test samples in the each student's test directory and added the following test code in front of the student's code:

 test_all :- test_list(['n8600p68.txt',
                               'na2706p71.txt',
                               'nb623p10.txt',
                               'nc890p24.txt',
                               'nd1390p46.txt',
                               'nd240p28.txt',
                               'ne1625p7.txt',
                               'nk2751p75.txt',
                               'nk4025p18.txt',
                               'nx454p32.txt'] ).
    
 test_list([]) :- !.
 test_list([X| Rest]) :- art_classifier(X),
                         nl,
                         test_list(Rest).

The best program got 8 out of 10 samples correctly classified, but ran so slowly, 5 minutes per document, I originally misgraded it because I thought the program had hung itself. This program uses DCG's as I asked. The next best got 6 out of 10, but runs much faster (instantaneously on the documents in question). It does not use DCG's. I am including both programs below. The 6 out of 10 program is given first.

Program 1

/* This is a Prolog program that classifies a given text into
   sub-categories acording to the code of the Library of Congres
   numbering system.
   
   example/
   art_classifier('my_text.txt'). */

   
test_all :- test_list(['n8600p68.txt',
                              'na2706p71.txt',
                              'nb623p10.txt',
                              'nc890p24.txt',
                              'nd1390p46.txt',
                              'nd240p28.txt',
                              'ne1625p7.txt',
                              'nk2751p75.txt',
                              'nk4025p18.txt',
                              'nx454p32.txt'] ).
   
test_list([]) :- !.
test_list([X| Rest]) :- art_classifier(X),
                        nl,
                        test_list(Rest).



art_classifier(X) :- seeing(Old),
		see(X),
		get0(C),
		process(C,0,N,0,Na,0,Nb,0,Nc,0,Nd,0,Ne,0,Nk,0,Nx),
		classify(N,Na,Nb,Nc,Nd,Ne,Nk,Nx),
		seen,
		see(Old).

classify(N,Na,Nb,Nc,Nd,Ne,Nk,Nx) :-
		max_list([N,'N',
			Na,'NA',
			Nb,'NB',
			Nc,'NC',
			Nd,'ND',
			Ne,'NE',
			Nk,'NK',
			Nx,'NX'],
			M),
		M = [_,Cat],
		display('The text is classified as: '),
		display(Cat).

/* get the num/subclass pair with max num */
max_list([X,C],[X,C]) :- !.
max_list([X,C|L],M) :-
	max_list(L,M1),
	M1 = [X1,C1],
	max([X,C],[X1,C1],M).

max(A,B,M) :- verify(A,B)->M is A;M is B.
verify([A|_],[B|_]) :- A > B.

process(-1,
	NCount,NTotal,
	NaCount,NaTotal,
	NbCount,NbTotal,
	NcCount,NcTotal,
	NdCount,NdTotal,
	NeCount,NeTotal,
	NkCount,NkTotal,
	NxCount,NxTotal) :- 
	NTotal is NCount,
	NaTotal is NaCount,
	NbTotal is NbCount,
	NcTotal is NcCount,
	NdTotal is NdCount,
	NeTotal is NeCount,
	NkTotal is NkCount,
	NxTotal is NxCount,
	!.

process(C,
	NCount,NTotal,
	NaCount,NaTotal,
	NbCount,NbTotal,
	NcCount,NcTotal,
	NdCount,NdTotal,
	NeCount,NeTotal,
	NkCount,NkTotal,
	NxCount,NxTotal) :- 
	process_sent(C,N,Na,Nb,Nc,Nd,Ne,Nk,Nx),
	NSubCount is NCount + N,
	NaSubCount is NaCount + Na,
	NbSubCount is NbCount + Nb,
	NcSubCount is NcCount + Nc,
	NdSubCount is NdCount + Nd,
	NeSubCount is NeCount + Ne,
	NkSubCount is NkCount + Nk,
	NxSubCount is NxCount + Nx,
	get0(C1),
	process(C1,
		NSubCount,NTotal,
		NaSubCount,NaTotal,
		NbSubCount,NbTotal,
		NcSubCount,NcTotal,
		NdSubCount,NdTotal,
		NeSubCount,NeTotal,
		NkSubCount,NkTotal,
		NxSubCount,NxTotal),!.

/* Read one sentence from the current input stream
   and count the keywords for each categories in the sentence */
process_sent(-1,_,_,_,_,_,_,_,_) :- !.
process_sent(C,N,Na,Nb,Nc,Nd,Ne,Nk,Nx) :- read_sent(C, W),
		count_n_words(W,0,N),
		count_na_words(W,0,Na),
		count_nb_words(W,0,Nb),
		count_nc_words(W,0,Nc),
		count_nd_words(W,0,Nd),
		count_ne_words(W,0,Ne),
		count_nk_words(W,0,Nk),
		count_nx_words(W,0,Nx).

/* Read a sentence and return a list of words */
read_sent(10, _) :- !.
read_sent(-1, _) :- !.
read_sent(C,[W|Ws]) :- read_word(C,W,C1),rest_sent(W,C1,Ws),!.

/* Given a word and the next character, read in the rest of the sentence
*/

rest_sent(W,_,[]) :- lastword(W).
rest_sent(_,C,[W1|Ws]) :- read_word(C,W1,C1),rest_sent(W1,C1,Ws).

read_word(-1,_,_) :- !.
read_word(C,W,C1) :- single_character(C),
		name(W,[C]),
		get0(C1).
read_word(C,W,C2) :- in_word(C,NewC),
		get0(C1),
		rest_word(C1,Cs,C2),
		name(W,[NewC|Cs]).
read_word(_,W,C2) :- get0(C1), read_word(C1,W,C2).

rest_word(-1,_,_) :- !.
rest_word(C,[NewC|Cs],C2) :- in_word(C,NewC),
		get0(C1), 
		rest_word(C1,Cs,C2).
rest_word(C,[],C).

/* Single character words */
single_character(33).      % !
single_character(44).      % ,
single_character(46).      % .
single_character(58).      % :
single_character(59).      % ;
single_character(63).      % ?

/* Characters appear within a word */
in_word(C,C) :- C > 96, C < 123.               % a,b,...,z
in_word(C,L) :- C > 64, C < 91, L is C + 32.   % A,B,...,Z
in_word(C,C) :- C > 47, C < 58.                % 0,1,...,9
in_word(39,39).                                % '
in_word(45,45).                                % -

/* End of a sentence */
lastword('.').
lastword('!').
lastword('?').

/* Count # of N (visual arts) words in a sentence */
count_n_words([],Count,Total) :- Total is Count,!.
count_n_words(List,Count,Total) :-
	List = [First,Second|Rest],
	n_word(First,Second),
	SubCount is Count + 2,
	count_n_words(Rest,SubCount,Total).
count_n_words(List,Count,Total) :-
	List = [First|Rest],
	n_word(First),
	SubCount is Count + 1,
	count_n_words(Rest,SubCount,Total).
count_n_words(List,Count,Total) :-
	List = [First|Rest],
	not(n_word(First)),
	count_n_words(Rest,Count,Total).


n_word(film).
n_word(films).
n_word(photography).
n_word(photographies).
n_word(visual).
n_word(museum).
n_word(museums).
n_word(gallery).
n_word(galleries).
n_word(collection).
n_word(collections).
n_word(collector).
n_word(collectors).

n_word(W, art) :- n_word(W).
n_word(W, arts) :- n_word(W).
n_word(art, W) :- n_word(W).
n_word(arts, W) :- n_word(W).

/* Count # of na (architecture) words in a sentence */
count_na_words([],Count,Total) :- Total is Count,!.
count_na_words(List,Count,Total) :-
	List = [First,Second|Rest],
	na_word(First,Second),
	SubCount is Count + 2,
	count_na_words(Rest,SubCount,Total).
count_na_words(List,Count,Total) :-
	List = [First|Rest],
	na_word(First),
	SubCount is Count + 1,
	count_na_words(Rest,SubCount,Total).
count_na_words(List,Count,Total) :-
	List = [First|Rest],
	not(na_word(First)),
	count_na_words(Rest,Count,Total).

na_word(architecture).
na_word(architectures).
na_word(architectural).
na_word(architect).
na_word(architects).
na_word(building).
na_word(buildings).
na_word(cathedral).
na_word(castle).
na_word(castles).
na_word(city).
na_word(cities).
na_word(construction).
na_word(constructions).
na_word(constructing).
na_word(constructive).
na_word(deco).
na_word(house).
na_word(houses).
na_word(housing).
na_word(hat).
na_word(hats).
na_word(temple).
na_word(temples).
na_word(baroque).
na_word(parthenon).
na_word(garden).
na_word(gardens).
na_word(structure).
na_word(structural).
na_word(structures).
na_word(monument).
na_word(monuments).
na_word(palace).
na_word(palaces).
na_word(park).
na_word(parks).

na_word(W,design) :- na_word(W).
na_word(W,designs) :- na_word(W).
na_word(designing, W) :- na_word(W).


/* Count # of NB (Sculpture) words in a sentence */
count_nb_words([],Count,Total) :- Total is Count,!.
count_nb_words(List,Count,Total) :-
	List = [First,Second|Rest],
	nb_word(First,Second),
	SubCount is Count + 2,
	count_nb_words(Rest,SubCount,Total).
count_nb_words(List,Count,Total) :-
	List = [First|Rest],
	nb_word(First),
	SubCount is Count + 1,
	count_nb_words(Rest,SubCount,Total).
count_nb_words(List,Count,Total) :-
	List = [First|Rest],
	not(nb_word(First)),
	count_nb_words(Rest,Count,Total).

nb_word(sculpture).
nb_word(sculptures).
nb_word(sculptural).
nb_word(sculptor).
nb_word(sculptors).
nb_word(bronze).
nb_word(casting).
nb_word(chisel).
nb_word(chisels).
nb_word(carver).
nb_word(carvers).
nb_word(curve).
nb_word(curving).
nb_word(forge).
nb_word(forging).
nb_word(forged).
nb_word(granite).
nb_word(hammer).
nb_word(limestone).
nb_word(mable).
nb_word(mallet).
nb_word(model).
nb_word(modeling).
nb_word(mold).
nb_word(molds).
nb_word(molding).
nb_word(object).
nb_word(objects).
nb_word(sculpt).
nb_word(sculpting).
nb_word(shape).
nb_word(shapes).
nb_word(shaping).
nb_word(soapstone).
nb_word(stone).
nb_word(statue).
nb_word(statues).
nb_word(monument).
nb_word(monuments).
nb_word(weld).
nb_word(welding).
nb_word(welding).

nb_word(metal, W) :- nb_word(W).
nb_word(wood, W) :- nb_word(W).
nb_word(W, tool) :- nb_word(W).
nb_word(W, tools) :- nb_word(W).
nb_word(W, design) :- nb_word(W).
nb_word(W, designs) :- nb_word(W).
nb_word(designing, W) :- nb_word(W).

/* Count # of NC (drawing, design, illustration) words in a sentence */
count_nc_words([],Count,Total) :- Total is Count,!.
count_nc_words(List,Count,Total) :-
	List = [First,Second|Rest],
	nc_word(First,Second),
	SubCount is Count + 2,
	count_nc_words(Rest,SubCount,Total).
count_nc_words(List,Count,Total) :-
	List = [First|Rest],
	nc_word(First),
	SubCount is Count + 1,
	count_nc_words(Rest,SubCount,Total).
count_nc_words(List,Count,Total) :-
	List = [First|Rest],
	not(nc_word(First)),
	count_nc_words(Rest,Count,Total).

nc_word(charcoal).
nc_word(charcoals).
nc_word(chalk).
nc_word(chalks).
nc_word(crayon).
nc_word(crayons).
nc_word(collage).
nc_word(draws).
nc_word(draw).
nc_word(drawing).
nc_word(drawings).
nc_word(design).
nc_word(designs).
nc_word(designing).
nc_word(designer).
nc_word(designers).
nc_word(eraser).
nc_word(erasers).
nc_word(graphite).
nc_word(graphic).
nc_word(illustration).
nc_word(illustrations).
nc_word(illustrating).
nc_word(illustrator).
nc_word(illustrators).
nc_word(ink).
nc_word(inks).
nc_word(lead).
nc_word(leads).
nc_word(pastel).
nc_word(pastels).
nc_word(pen).
nc_word(pens).
nc_word(pencil).
nc_word(sketch).
nc_word(sketches).
nc_word(poster).
nc_word(posters).
nc_word(portrait).
nc_word(ruler).
nc_word(rulers).
nc_word(portraits).
nc_word(stipple).
nc_word(stippling).

nc_word(W, tool) :- nc_word(W).
nc_word(W, tools) :- nc_word(W).
nc_word(figure, W) :- nc_word(W).

/* Count # of ND (painging) words in a sentence */
count_nd_words([],Count,Total) :- Total is Count,!.
count_nd_words(List,Count,Total) :-
	List = [First,Second|Rest],
	nd_word(First,Second),
	SubCount is Count + 2,
	count_nd_words(Rest,SubCount,Total).
count_nd_words(List,Count,Total) :-
	List = [First|Rest],
	nd_word(First),
	SubCount is Count + 1,
	count_nd_words(Rest,SubCount,Total).
count_nd_words(List,Count,Total) :-
	List = [First|Rest],
	not(nd_word(First)),
	count_nd_words(Rest,Count,Total).

nd_word(acrylic).
nd_word(canvas).
nd_word(conceptualism).
nd_word(expressionism).
nd_word(painting).
nd_word(paintings).
nd_word(painted).
nd_word(paint).
nd_word(painter).
nd_word(painters).
nd_word(watercolor).
nd_word(watercolors).
nd_word(mural).
nd_word(murals).
nd_word(modernism).
nd_word(oil).
nd_word(portrait).
nd_word(portraits).

nd_word(still, life).
nd_word(figure, W) :- nd_word(W).
nd_word(W, tool) :- nd_word(W).
nd_word(W, tools) :- nd_word(W).

/* Count # of NE (print media) words in a sentence */
count_ne_words([],Count,Total) :- Total is Count,!.
count_ne_words(List,Count,Total) :-
	List = [First,Second|Rest],
	ne_word(First,Second),
	SubCount is Count + 2,
	count_ne_words(Rest,SubCount,Total).
count_ne_words(List,Count,Total) :-
	List = [First|Rest],
	ne_word(First),
	SubCount is Count + 1,
	count_ne_words(Rest,SubCount,Total).
count_ne_words(List,Count,Total) :-
	List = [First|Rest],
	not(ne_word(First)),
	count_ne_words(Rest,Count,Total).

ne_word(print).
ne_word(prints).
ne_word(printing).
ne_word(printings).
ne_word(drypoint).
ne_word(engraving).
ne_word(engravings).
ne_word(printmaking).
ne_word(engrave).
ne_word(etching).
ne_word(etchings).
ne_word(serigraphy).
ne_word(serigraphies).
ne_word(monotype).
ne_word(monoprint).
ne_word(monoprints).
ne_word(lithography).
ne_word(lithographies).
ne_word(intaglio).

ne_word(stencil, W) :- ne_word(W).
ne_word(stone, W) :- ne_word(W).
ne_word(relief, W) :- ne_word(W).
ne_word(wood, W) :- ne_word(W).
ne_word(metal, W) :- ne_word(W).
ne_word(copper, W) :- ne_word(W).
ne_word(color, W) :- ne_word(W).
ne_word(japanese, W) :- ne_word(W).
ne_word(W, tool) :- ne_word(W).
ne_word(W, tools) :- ne_word(W).
ne_word(W, device) :- ne_word(W).
ne_word(W, devices) :- ne_word(W).

/* Count # of NK (decorative arts) words in a sentence */
count_nk_words([],Count,Total) :- Total is Count,!.
count_nk_words(List,Count,Total) :-
	List = [First,Second|Rest],
	nk_word(First,Second),
	SubCount is Count + 2,
	count_nk_words(Rest,SubCount,Total).
count_nk_words(List,Count,Total) :-
	List = [First|Rest],
	nk_word(First),
	SubCount is Count + 1,
	count_nk_words(Rest,SubCount,Total).
count_nk_words(List,Count,Total) :-
	List = [First|Rest],
	not(nk_word(First)),
	count_nk_words(Rest,Count,Total).

nk_word(decorative).
nk_word(decorating).
nk_word(decoration).
nk_word(decorations).
nk_word(deco).
nk_word(ornament).
nk_word(ornaments).
nk_word(interior).
nk_word(funiture).
nk_word(funitures).
nk_word(rags).
nk_word(carpets).
nk_word(carpet).
nk_word(rag).
nk_word(wallpapers).
nk_word(wallpaper).
nk_word(upholstery).
nk_word(upholsteries).
nk_word(tapestry).
nk_word(tapestries).

nk_word(charch, W) :- nk_word(W).
nk_word(W, arts) :- nk_word(W).
nk_word(W, design) :- nk_word(W).
nk_word(W, designs) :- nk_word(W).
nk_word(designing, W) :- nk_word(W).

/* Count # of NX (arts in general) words in a sentence */
count_nx_words([],Count,Total) :- Total is Count,!.
count_nx_words(List,Count,Total) :-
	List = [First,Second|Rest],
	nx_word(First,Second),
	SubCount is Count + 2,
	count_nx_words(Rest,SubCount,Total).
count_nx_words(List,Count,Total) :-
	List = [First|Rest],
	nx_word(First),
	SubCount is Count + 1,
	count_nx_words(Rest,SubCount,Total).
count_nx_words(List,Count,Total) :-
	List = [First|Rest],
	not(nx_word(First)),
	count_nx_words(Rest,Count,Total).

nx_word(artists).
nx_word(arts).
nx_word(artwork).
nx_word(patronage).
nx_word(patronages).
nx_word(in, general).
nx_word(art, history).
nx_word(arts, history).



Return to homework page.

Program 2

/*-----------------------------------------------------------------------------
* art_classifier.P

* Description: A program to classify art documents accordiing to the 
*		Library of Congress numbering system. This program uses a 
*		knowledge base of rules to classify the documents.
* Version: 2.0
*-----------------------------------------------------------------------------*/


/******************************************************************************
* main goal
*******************************************************************************/
art_classifier(FileName) :- load_file(FileName, List),
			classify(List, Class),
			display('Classification: '),
			display(Class),
			nl.

/******************************************************************************
* I/O: open file, read file, close file
*******************************************************************************/
load_file([], []) :- !.
load_file(FileName, List) :- open_file(FileName, Y),
			read_file(List),
			close_file(Y).

open_file(FileName, Y) :- seeing(Y), see(FileName).
read_file(List) :- get0(X), read_file_helper(X, List).
read_file_helper(-1, []) :- !.
read_file_helper(X, [LowerX|Rest]) :- X =< 90,
			X >= 65,
			LowerX is X + 32,
			get0(Y), read_file_helper(Y, Rest).
read_file_helper(X, [X|Rest]) :- get0(Y), read_file_helper(Y, Rest).
close_file(Y) :- seen, see(Y).			

/******************************************************************************
* classify
*******************************************************************************/
classify([], 'Empty file') :- !.
classify(List, Class) :- list_to_tokens(List, Tokens),
			Counts = [0, 0, 0, 0, 0, 0, 0, 0],
			count_keywords(Tokens, Counts, Result),
			max_count_class(Result, Class).
			
/******************************************************************************
* convert list of characters to tokens
*******************************************************************************/
list_to_tokens([], []).
list_to_tokens(List, Tokens) :- get_token(List, First, RestList),
			First = [],
			list_to_tokens(RestList, Tokens).
list_to_tokens(List, Tokens) :- get_token(List, First, RestList),
			drop_token(First),
			list_to_tokens(RestList, Tokens).
list_to_tokens(List, Tokens) :- Tokens = [First|Rest],
			get_token(List, First, RestList),
			list_to_tokens(RestList, Rest).

get_token([], [], []).
get_token(List, Token, Rest) :- List = [First|Rest],
			Delimiter = [" ", ".", ",", "-", "?", "!", [13],
[10], 
			[9], "@", "<", ">", "=", "+", "*"],
			in_keyword_list([First], Delimiter),
			Token = [].
get_token(List, Token, Rest) :- List = [First|RestList],
			Token = [First|RestToken],
			get_token(RestList, RestToken, Rest).

/******************************************************************************
* definite clause grammar to parse text
*******************************************************************************/
text --> paragraph, return, text.
return --> [13, 10].
paragraph --> sentence, period, paragraph.
period --> [46].
sentence --> noun_phrase, verb_phrase.
noun_phrase --> determiner, noun | determiner, adjective, noun | 
		determiner, noun, [of], noun_phrase | determiner,
adjective, noun, 
		[of], noun_phrase.
verb_phrase --> verb | verb, noun_phrase.
determiner --> [the] | [a] | [an].
noun --> [history] | [study] | [teaching] | [competition] | [work] |
[design] |
	[technique] | [restoration] | [conservation] | [material] |
[examination] |
	[equipment] | [copying] | [movement] | [research] | [exhibition] | 
	[administration] | [patronage] | [theory] | [aesthetics] |
[artist] |
	[art] | [architecture] | [sculpture] | [drawing] | [illustration]
| 
	[painting] | [print] | [decoration] | [ornament] | [arts] |
	[museum] | [gallery] | [collection] | [collector] | [studio] |
	[architect] | [building] | [house] | [dwelling]	| [clubhouse] | 
	[outbuilding] | [statue] | [monument] | [shrine] | [graph] |
[ephemera] | 
	[imagerie] | [populaire] | [caricature] | [portrait] | [landscape]
|
	[watercolor] | [oil] | [mural] | [illumination] | [printmaking] | 
	[engraving] | [etching] | [aquatint] | [serigraphy] | [monotype] |
	[lithography] | [lumiprint] | [craft] | [ceramic] | [woodwork] | 
	[voluntarism] | [volunteer] | [facility] | [criticism] |
[planning] |
	[beautifying].
verb --> verb_to_be | [study] | [teach] | [research] | [exhibit] |
[collect] | 
	[conserve] | [build] | [draw] | [design] | [decorate] | [sculp] |
[restore] |
	[illustrate] | [advertise] | [paint] | [engrave] | [administrate].
verb_to_be --> [is] | [am] | [are] | [was] | [were].
adjective --> [visual] | [artistic] | [special] | [public] | [private]
| 
	[religious] | [domestic] | [sculptural] | [sepulchral] |
[commercial] | 
	[architectural] | [pictorial] | [oriental] | [european] | [asian]
| [african] |
	[metal] | [wood] | [decorative] | [general] | [interior].

/******************************************************************************
* drop tokens that cannot be keywords
*******************************************************************************/
drop_token(Token) :- Articles = ["a", "an", "the"],
			in_keyword_list(Token, Articles).
drop_token(Token) :- Prepositions = ["at", "by", "for", "in", "of", "on",
"to", 
			"out", "near", "above", "under"],
			in_keyword_list(Token, Prepositions).
drop_token(Token) :- Pronouns = ["i", "we", "you", "they", "he", "she",
"it",
			"my", "ours", "yours", "theirs", "his", "hers",
"its",
			"me", "mine", "myself", "yourself", "themselves", 
			"himself", "herself", "itself"],
			in_keyword_list(Token, Pronouns).
drop_token(Token) :- Conjunctions = ["and", "or", "not", "but",
"although", "if", 
			"then", "else",	"also", "therefore", "thus",
"moreover",
			"otherwise", "however"],
			in_keyword_list(Token, Conjunctions).
drop_token(Token) :- VerbToBes = ["is", "am", "are", "will", "be",
"being", "been"],
			in_keyword_list(Token, VerbToBes).

in_keyword_list(Token, []) :- fail.
in_keyword_list(Token, List) :- List = [First|Rest],
			Token = First.
in_keyword_list(Token, List) :- List = [First|Rest],
			substring(Token, First, 0).
in_keyword_list(Token, List) :- List = [First|Rest],
			in_keyword_list(Token, Rest).

/******************************************************************************
* count occurrences of keywords
*******************************************************************************/
count_keywords([], Counts, Counts).
count_keywords(Tokens, Counts, Result) :- Tokens = [First|Rest],
			set_count(First, Counts, NewCounts),
			count_keywords(Rest, NewCounts, Result).
			
set_count(Token, Counts, Result) :- match(Token, Class),
			increment(Class, Counts, Result).
						
match(Token, 0) :- 
	ListN = ["visual", "museum", "gallery", "galleries", "exhibition",
"collection",
		"collector", "artist", "studio", "material", "conserve",
"conservation"],
	is_keyword_of(Token, ListN).
match(Token, 1) :- 
	ListNA = ["architect", "architectural", "building", "house",
"dwelling",
		"clubhouse", "outbuilding"],
	is_keyword_of(Token, ListNA).
match(Token, 2) :- 
	ListNB = ["sculp", "sculpture", "statue", "monument", "shrine"], 
	is_keyword_of(Token, ListNB).
match(Token, 3) :- 
	ListNC = ["draw", "design", "illustrate", "illustration", "graph",
"ephemera", 
		"imagerie", "populaire", "caricature", "poster", "card",
"postcard", 
		"invitation"],
	is_keyword_of(Token, ListNC).
match(Token, 4) :- 
	ListND = ["paint", "painting", "portrait", "landscape",
"watercolor", "oil", 
		"mural", "illuminate", "illumination"],
	is_keyword_of(Token, ListND).
match(Token, 5) :- 
	ListNE = ["print", "printmaking", "engrave", "engraving",
"etching", "aquatint",
		"serigraphy", "monotype", "lithography", "lumiprint"], 
	is_keyword_of(Token, ListNE).
match(Token, 6) :- 
	ListNK = ["decorative", "decoration", "ornament", "craft",
"furniture", "rug",
		"carpet", "tapestries", "upholstery", "drapery",
"wallpaper", "ceramic",
		"costume", "glass", "glyptic", "textile", "woodwork"],
	is_keyword_of(Token, ListNK).
match(Token, 7) :- 
	ListNX = ["study", "teach", "patron", "administrate",
"administration", "voluntary",
		"voluntarism", "volunteer", "center", "facility",
"facilities"],
	is_keyword_of(Token, ListNX).
match(Token, 8).

is_keyword_of(Token, []) :- fail.
is_keyword_of(Token, List) :- List = [First|Rest],
			Token = First.
is_keyword_of(Token, List) :- List = [First|Rest],
			substring(First, Token, 0).
is_keyword_of(Token, List) :- List = [First|Rest],
			is_keyword_of(Token, Rest).

substring([], String2, MatchStarted).
substring(String1, [], MatchStarted) :- fail, !.
substring(String1, String2, 0) :- String1 = [Char11|Rest1],
			String2 = [Char21|Rest2],
			Char11 = Char21, 
			substring(Rest1, Rest2, 1).
substring(String1, String2, 1) :- String1 = [Char11|Rest1],
			String2 = [Char21|Rest2],
			Char11 = Char21, !,
			substring(Rest1, Rest2, 1).
substring(String1, String2, 0) :- String1 = [Char11|Rest1],
			String2 = [Char21|Rest2],
			substring(String1, Rest2, 0).

increment(8, Counts, Counts).
increment(0, [C0, C1, C2, C3, C4, C5, C6, C7], [NewC0, C1, C2, C3, C4, C5,
C6, C7]) :- 
			NewC0 is C0 + 1.
increment(1, [C0, C1, C2, C3, C4, C5, C6, C7], [C0, NewC1, C2, C3, C4, C5,
C6, C7]) :-
			NewC1 is C1 + 1.
increment(2, [C0, C1, C2, C3, C4, C5, C6, C7], [C0, C1, NewC2, C3, C4, C5,
C6, C7]) :-
			NewC2 is C2 + 1.
increment(3, [C0, C1, C2, C3, C4, C5, C6, C7], [C0, C1, C2, NewC3, C4, C5,
C6, C7]) :-
			NewC3 is C3 + 1.
increment(4, [C0, C1, C2, C3, C4, C5, C6, C7], [C0, C1, C2, C3, NewC4, C5,
C6, C7]) :-
			NewC4 is C4 + 1.
increment(5, [C0, C1, C2, C3, C4, C5, C6, C7], [C0, C1, C2, C3, C4, NewC5,
C6, C7]) :-
			NewC5 is C5 + 1.
increment(6, [C0, C1, C2, C3, C4, C5, C6, C7], [C0, C1, C2, C3, C4, C5,
NewC6, C7]) :-
			NewC6 is C6 + 1.
increment(7, [C0, C1, C2, C3, C4, C5, C6, C7], [C0, C1, C2, C3, C4, C5,
C6, NewC7]) :-
			NewC7 is C7 + 1.
			
/******************************************************************************
* determine classification
*******************************************************************************/
max_count_class(Counts, Class) :- Counts = [Max|Rest],
			iter(Rest, Max, 0, 1, ClassNum),
			class(ClassNum, Class).
			
iter([], Max, MaxIndex, CurrIndex, MaxIndex).
iter(Counts, Max, MaxIndex, CurrIndex, Result) :- 
			Counts = [Curr|Rest],
			Curr > Max,
			NextIndex is CurrIndex + 1,
			iter(Rest, Curr, CurrIndex, NextIndex, Result).
iter(Counts, Max, MaxIndex, CurrIndex, Result) :- 
			Counts = [Curr|Rest],
			NextIndex is CurrIndex + 1,
			iter(Rest, Max, MaxIndex, NextIndex, Result).

class(0, 'N').
class(1, 'NA').
class(2, 'NB').
class(3, 'NC').
class(4, 'ND').
class(5, 'NE').
class(6, 'NK').
class(7, 'NX').