[m-rev.] for review: using dice information in the declarative debugger

Ian MacLarty maclarty at cs.mu.OZ.AU
Fri Aug 5 04:52:09 AEST 2005


For review by anyone.

Estimated hours taken: 30
Branches: main

Use dicing information in the declarative debugger.  Each label in the program
is assigned a suspicion based on a supplied dice.  A new search mode then
performs divide and query using the total suspicion of a subtree as the
weighting of the subtree.

browser/declarative_analyser.m:
 	Parameterize the divide and query search mode by allowing it to work
 	with an arbitrary weighting heuristic.

 	Support two weighting heuristics: number of events and suspicion.

 	Since there is still only one weight field for each suspect,
 	if the weighting heuristic changes, then update all the weights of all
 	the suspects.

 	Return a different reason for asking a divide and query question,
 	depending on the weighting heuristic.

  	Some information (specifically how many suspect events remain and
 	the estimated number of questions remaining for divide and query)
 	returned by the info command depends on the current weighting heuristic
 	being the number of events.  If the current weighting heuristic is not
 	the number of events then do not show this information.

browser/declarative_debugger.m:
 	Pass the trace node store to set_fallback_search_mode so that the
 	weights can be recalculated if the search strategy changes.

browser/declarative_edt.m:
 	In the mercury_edt typeclass, rename the edt_weight method to
 	edt_number_of_events and add a new method edt_subtree_suspicion.

 	The weight field of each suspect in the search space can either
 	be based on suspicion or number of events.
 	Add a field to the search_space type to determine which weighting
 	heuristic to use.  Export predicates to get and set the current
 	weighting heuristic being used.  If the weighting heuristic
 	changes the recalculate the weights of all the suspects.

 	When calculating the weight of a suspect use the current weighting
 	heuristic.

browser/declarative_execution.m:
 	Record a suspicion accumulator at each interface event which
 	can be used to calculate the suspicion of a subtree in the EDT.

 	Move the label_layout and proc_layout types as well as all utility
 	predicates for those types to a new module, mdbcomp.label_layout.

browser/declarative_oracle.m:
browser/declarative_user.m:
browser/debugger_interface.m:
 	Import mdbcomp.label_layout.

browser/declarative_tree.m:
 	Adjust for the extra field in interface nodes in the annotated trace.

 	Look at the weighting heuristic when calculating the weight of a
 	subtree.

browser/util.m:
mdbcomp/program_representation.m:
 	Move goal_path_string to mdbcomp.program_representation since
 	it is needed in mdbcomp.label_layout.

doc/user_guide.texi:
 	Document the new search mode.

mdbcomp/label_layout.m:
 	This module contains the types label_layout and proc_layout and
 	supporting predicates which were in mdb.declarative_execution.
 	These types are needed in the mdbcomp.slice_and_dice module.

mdbcomp/mdbcomp.m:
 	Include label_layout.

mdbcomp/slice_and_dice.m:
 	Add functions for calculating different suspicion formulas.  The
 	intention is to experiment with different formulas in the future.

 	Export predicates for reading a dice from the C backend.

 	Export a predicate for retrieving the suspicion of a label
 	given a dice.  This predicate uses the suspicion_ratio_binary
 	formula, since that seems most effective in my (as yet very limited)
 	experience.  I will implement better ways to control and customise
 	the formula used in the future.

mdbcomp/trace_counts.m:
 	Add a function for constructing a path_port given a goal path and
 	a trace port.

 	If there is an unexpected exception when reading a trace counts
 	file then print the unexpected exception.

 	Add a predicate to convert trace count file types to a string and
 	vica versa.

runtime/mercury_stack_layout.h:
 	Fix a typo.

runtime/mercury_trace_base.c:
runtime/mercury_trace_base.h:
 	Export a function to look up the trace count slot for a label.
 	Use this function when recording trace counts.
 	This function will also be used in the declarative debugger backend to
 	look up suspicions for labels.

 	Add a function to initialise the array which records which ports
 	need a goal path to uniquely identifiy the label.
 	Initially I used this array elsewhere which is why I exported it.
 	I didn't actually end up needing to use it in the final version,
 	but I'm still exporting it, since it might be useful in the future.

tests/debugger/declarative/Mmakefile:
tests/debugger/declarative/dice.exp:
tests/debugger/declarative/dice.inp:
tests/debugger/declarative/dice.m:
 	Test the new search mode.

tests/debugger/declarative/info.exp:
 	The weigting heuristic is now printed with the info command.
 	Also some information, such as the number of suspect events,
 	is no longer printed if the weigthing heuristic is not the number
 	of events (since then that information is not available).

trace/mercury_trace_declarative.c:
 	Add a function to setup the trace counts array with a suspicion for
 	each label.  For efficiency the suspicion is converted from a
 	float to an integer between 0 and 100.

 	If a flag is set, then increment an accumulator with the
 	suspicion of each label executed as the annotated trace is being
 	constructed.  Store the value of the accumulator at interface events,
 	so that the frontend can efficiently calculate the suspicion of any
 	subtree.

 	Remove a redundant variable and comment: the goal path is no
 	longer passed to the frontend, because the frontend has access to
 	the label_layout from which it can get the goal path (the variable and
 	comment are artifacts of a previous change).

 	When checking if a search mode is valid also check if failing and
 	passing trace counts are required for the search mode.
 	Allow abbreviations for the search mode arguments.

trace/mercury_trace_declarative.h:
 	Export the predicate to set up the suspicions for each label.

trace/mercury_trace_internal.c:
 	Allow passing and failing test case(s) to be passed
 	as arguments to the dd command.

 	If passing and failing test case(s) are supplied then record
 	suspicions in the annotated trace even if the sdq search mode
 	is not specified.  The user could switch to the sdq search mode later
 	on.

 	Initialise some values which were causing warnings from the C
 	compiler.

Index: browser/debugger_interface.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/debugger_interface.m,v
retrieving revision 1.23
diff -u -r1.23 debugger_interface.m
--- browser/debugger_interface.m	11 Jul 2005 07:30:19 -0000	1.23
+++ browser/debugger_interface.m	4 Aug 2005 16:12:26 -0000
@@ -34,6 +34,7 @@
  :- import_module mdb.interactive_query.
  :- import_module mdb.util.
  :- import_module mdbcomp.prim_data.
+:- import_module mdbcomp.program_representation.

  :- import_module bool.
  :- import_module io.
Index: browser/declarative_analyser.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/declarative_analyser.m,v
retrieving revision 1.28
diff -u -r1.28 declarative_analyser.m
--- browser/declarative_analyser.m	28 Jul 2005 06:44:06 -0000	1.28
+++ browser/declarative_analyser.m	4 Aug 2005 09:37:26 -0000
@@ -58,6 +58,8 @@

  :- func divide_and_query_search_mode = search_mode.

+:- func suspicion_divide_and_query_search_mode = search_mode.
+
  :- func top_down_search_mode = search_mode.

  :- pred analyser_state_init(analyser_state(T)::out) is det.
@@ -69,8 +71,9 @@
  	% Make the given search mode the fallback search mode
  	% and the current search mode for the analyser.
  	%
-:- pred set_fallback_search_mode(search_mode::in, 
-	analyser_state(T)::in, analyser_state(T)::out) is det.
+:- pred set_fallback_search_mode(S::in, search_mode::in, 
+	analyser_state(T)::in, analyser_state(T)::out) 
+	is det <= mercury_edt(S, T).

  :- type analysis_type(T)
  			% Use the given tree to do analysis.  The tree will be
@@ -209,18 +212,14 @@
  		)
  	;
  			% 
-			% An adapted version of the divide and query approach
-			% proposed by Shapiro.  We weight each node with the
-			% number of events executed by descendent children
-			% plus the internal body events of the call.  This is
-			% mainly because it's hard to work out how many
-			% descendents are in unmaterialized portions of the EDT
-			% without using memory proportional to the
-			% unmaterialized portion.
+			% Divide and query using the given weighting
+			% heuristic.
  			%
-		divide_and_query.
+		divide_and_query(weighting_heuristic).

-divide_and_query_search_mode = divide_and_query.
+divide_and_query_search_mode = divide_and_query(number_of_events).
+
+suspicion_divide_and_query_search_mode = divide_and_query(suspicion).

  top_down_search_mode = top_down.

@@ -258,8 +257,13 @@
  			binary_reason_split	:: int
  		)
  	;	divide_and_query(
-			old_weight		:: int,
-			choosen_subtree_weight 	:: int
+			dq_weighting			:: weighting_heuristic,
+				% The weight of the search space before the question
+				% was asked.
+			dq_old_weight			:: int,
+				% The weight the searchspace will be if the user answers
+				% `no' to the current question.
+			dq_choosen_subtree_weight 	:: int
  		)
  	;	skipped
  	;	revise.
@@ -327,9 +331,19 @@
  	!:Analyser = analyser(empty_search_space, no, FallBack,
  		FallBack, no, no).

-set_fallback_search_mode(FallBackSearchMode, !Analyser) :-
+set_fallback_search_mode(Store, FallBackSearchMode, !Analyser) :-
  	!:Analyser = !.Analyser ^ fallback_search_mode := FallBackSearchMode,
-	!:Analyser = !.Analyser ^ search_mode := FallBackSearchMode.
+	!:Analyser = !.Analyser ^ search_mode := FallBackSearchMode,
+	(
+		FallBackSearchMode = divide_and_query(Weighting)
+	->
+		SearchSpace0 = !.Analyser ^ search_space,
+		update_weighting_heuristic(Store, Weighting, SearchSpace0, 
+			SearchSpace),
+		!:Analyser = !.Analyser ^ search_space := SearchSpace
+	;
+		true
+	).

  debug_analyser_state(Analyser, Analyser ^ debug_origin).

@@ -361,7 +375,10 @@
  			% start of a new declarative debugging session.
  			%
  			reset_analyser(!Analyser),
-			initialise_search_space(Store, Node, SearchSpace),
+			MaybeWeighting = get_maybe_weighting_from_search_mode(
+				!.Analyser ^ search_mode),
+			initialise_search_space(Store, MaybeWeighting, Node, 
+				SearchSpace),
  			!:Analyser = !.Analyser ^ search_space := SearchSpace,
  			topmost_det(SearchSpace, TopMostId),
  			!:Analyser = !.Analyser ^ last_search_question := 
@@ -374,6 +391,15 @@
  		decide_analyser_response(Store, Oracle, Response, !Analyser)
  	).

+:- func get_maybe_weighting_from_search_mode(search_mode) =
+	maybe(weighting_heuristic).
+
+get_maybe_weighting_from_search_mode(divide_and_query(Weighting)) =
+	yes(Weighting).
+get_maybe_weighting_from_search_mode(top_down) = no.
+get_maybe_weighting_from_search_mode(binary(_, _, _)) = no.
+get_maybe_weighting_from_search_mode(follow_subterm_end(_, _, _, _)) = no.
+
  reask_last_question(Store, Analyser, Response) :-
  	MaybeLastQuestion = Analyser ^ last_search_question,
  	(
@@ -614,9 +640,9 @@
  		LastTested, !SearchSpace, FallBackSearchMode, NewMode,
  		Response).

-search(Store, Oracle, !SearchSpace, divide_and_query, _, NewMode, 
+search(Store, Oracle, !SearchSpace, divide_and_query(Weighting), _, NewMode,
  		Response) :-
-	divide_and_query_search(Store, Oracle, !SearchSpace, 
+	divide_and_query_search(Store, Oracle, Weighting, !SearchSpace,
  		Response, NewMode).

  :- pred top_down_search(S::in, oracle_state::in, 
@@ -993,11 +1019,12 @@
  	).

  :- pred divide_and_query_search(S::in, oracle_state::in,
-	search_space(T)::in, search_space(T)::out, search_response::out,
+	weighting_heuristic::in, 
+	search_space(T)::in, search_space(T)::out, search_response::out,
  	search_mode::out) is det <= mercury_edt(S, T).

-divide_and_query_search(Store, Oracle, !SearchSpace, Response, 
-		NewMode) :-
+divide_and_query_search(Store, Oracle, Weighting, !SearchSpace, 
+		Response, divide_and_query(Weighting)) :-
  	%
  	% If there's no root yet (because the oracle hasn't asserted any nodes
  	% are erroneous yet), then use top-down search.
@@ -1005,44 +1032,42 @@
  	(
  		root(!.SearchSpace, RootId)
  	->
-		NewMode = divide_and_query,
  		(
  			children(Store, Oracle, RootId,
  				!SearchSpace, Children)
  		->
-			find_middle_weight(Store, Oracle, 
-				Children, RootId, no, !SearchSpace, Response)
+			find_middle_weight(Store, Oracle, Weighting, Children,
+				RootId, no, !SearchSpace, Response)
  		;
  			Response = require_explicit_subtree(RootId)
  		)
  	;
-		top_down_search(Store, Oracle, !SearchSpace, Response),
-		NewMode = divide_and_query
+		top_down_search(Store, Oracle, !SearchSpace, Response)
  	).

-	% Call find_middle_weight/8 if we are able to find the children of the
+	% Call find_middle_weight if we are able to find the children of the
  	% given suspect id, otherwise return a require_explicit_subtree
  	% search response in the last argument.
  	%
  :- pred find_middle_weight_if_children(S::in,
-	oracle_state::in, suspect_id::in, suspect_id::in,
-	maybe(suspect_id)::in, search_space(T)::in, search_space(T)::out,
-	search_response::out) is det <= mercury_edt(S, T).
+	oracle_state::in, weighting_heuristic::in, suspect_id::in, 
+	suspect_id::in, maybe(suspect_id)::in, 
+	search_space(T)::in, search_space(T)::out, search_response::out) 
+	is det <= mercury_edt(S, T).

-find_middle_weight_if_children(Store, Oracle, SuspectId, TopId, 
+find_middle_weight_if_children(Store, Oracle, Weighting, SuspectId, TopId,
  		MaybeLastUnknown, !SearchSpace, Response) :-
  	(
-		children(Store, Oracle, SuspectId, !SearchSpace, 
-			Children)
+		children(Store, Oracle, SuspectId, !SearchSpace, Children)
  	->
-		find_middle_weight(Store, Oracle, Children, TopId,
+		find_middle_weight(Store, Oracle, Weighting, Children, TopId,
  			MaybeLastUnknown, !SearchSpace, Response)
  	;
  		Response = require_explicit_subtree(SuspectId)
  	).

-	% find_middle_weight(Store, Oracle, SuspectIds, TopId, 
-	%	MaybeLastUnknown, !SearchSpace, Response).
+	% find_middle_weight(Store, Oracle, Weighting, SuspectIds, 
+	%	TopId, MaybeLastUnknown, !SearchSpace, Response).
  	% Find the unknown suspect whose weight is closest to half the weight
  	% of TopId, considering only the heaviest suspect in SuspectIds, the
  	% heaviest child of the heaviest suspect in SuspectIds and so on.
@@ -1050,18 +1075,19 @@
  	% any).
  	%
  :- pred find_middle_weight(S::in, oracle_state::in, 
-	list(suspect_id)::in, suspect_id::in,
-	maybe(suspect_id)::in, search_space(T)::in, 
-	search_space(T)::out, search_response::out)
+	weighting_heuristic::in, list(suspect_id)::in, suspect_id::in,
+	maybe(suspect_id)::in, 
+	search_space(T)::in, search_space(T)::out, search_response::out)
  	is det <= mercury_edt(S, T).

-find_middle_weight(Store, Oracle, [], TopId, MaybeLastUnknown,
-		!SearchSpace, Response) :-
+find_middle_weight(Store, Oracle, Weighting, [], TopId, 
+		MaybeLastUnknown, !SearchSpace, Response) :-
  	(
  		MaybeLastUnknown = yes(LastUnknown),
  		suspect_still_unknown(!.SearchSpace, LastUnknown)
  	->
  		Response = question(LastUnknown, divide_and_query(
+			Weighting,
  			get_weight(!.SearchSpace, TopId),
  			get_weight(!.SearchSpace, LastUnknown)))
  	;
@@ -1071,7 +1097,7 @@
  		top_down_search(Store, Oracle, !SearchSpace,
  			Response)
  	).
-find_middle_weight(Store, Oracle, [SuspectId | SuspectIds], TopId,
+find_middle_weight(Store, Oracle, Weighting, [SuspectId | SuspectIds], TopId,
  		MaybeLastUnknown, !SearchSpace, Response) :-
  	TopWeight = get_weight(!.SearchSpace, TopId),
  	Target = TopWeight // 2,
@@ -1091,7 +1117,7 @@
  		;
  			NewMaybeLastUnknown = MaybeLastUnknown
  		),
-		find_middle_weight_if_children(Store, Oracle, 
+		find_middle_weight_if_children(Store, Oracle, Weighting,
  			Heaviest, TopId, NewMaybeLastUnknown, !SearchSpace,
  			Response)
  	;
@@ -1100,7 +1126,7 @@
  		->
  			(
  				MaybeLastUnknown = yes(LastUnknown),
-				suspect_still_unknown(!.SearchSpace, 
+				suspect_still_unknown(!.SearchSpace,
  					LastUnknown)
  			->
  				LastUnknownWeight = get_weight(!.SearchSpace, 
@@ -1114,32 +1140,35 @@
  						Target - MaxWeight
  				->
  					Response = question(LastUnknown, 
-						divide_and_query(TopWeight,
+						divide_and_query(
+							Weighting, TopWeight,
  							LastUnknownWeight))
  				;
  					Response = question(Heaviest,
-						divide_and_query(TopWeight,
+						divide_and_query(Weighting, 
+							TopWeight,
  							MaxWeight))
  				)
  			;
  				Response = question(Heaviest, 
-					divide_and_query(TopWeight, MaxWeight))
+					divide_and_query(Weighting, TopWeight, 
+					MaxWeight))
  			)
  		;
  			(
  				MaybeLastUnknown = yes(LastUnknown),
-				suspect_still_unknown(!.SearchSpace, 
+				suspect_still_unknown(!.SearchSpace,
  					LastUnknown)
  			->
  				LastUnknownWeight = get_weight(!.SearchSpace,
  					LastUnknown),
  				Response = question(LastUnknown,
-					divide_and_query(TopWeight,
+					divide_and_query(Weighting, TopWeight,
  						LastUnknownWeight))
  			;
  				% Look deeper until we find an unknown:
-				find_middle_weight_if_children(
-					Store, Oracle, Heaviest, TopId, no,
+				find_middle_weight_if_children(Store, Oracle,
+					Weighting, Heaviest, TopId, no,
  					!SearchSpace, Response)
  			)
  		) 
@@ -1237,19 +1266,32 @@
  		++ " into two paths of length " ++
  		SubPath1LengthStr ++ " and " ++ SubPath2LengthStr ++ ".".

-reason_to_string(divide_and_query(OldWeight, SubtreeWeight)) = Str :-
-	Weight1Str = int_to_string_thousands(OldWeight - SubtreeWeight),
-	Weight2Str = int_to_string_thousands(SubtreeWeight),
-	Str = "this node divides the suspect area into " ++
-		"two regions of " ++ Weight1Str ++ " and " ++ Weight2Str ++
-		" events each.".
+reason_to_string(divide_and_query(Weighting, OldWeight, SubtreeWeight)) =
+	weighting_to_reason_string(Weighting, OldWeight - SubtreeWeight, 
+		SubtreeWeight).

  reason_to_string(skipped) = "there are no more non-skipped questions "
  	++ "left.".

-reason_to_string(revise) = "this node is being revised, because of "
+reason_to_string(revise) = "this question is being revisited, because of "
  	++ "an unsuccessful previous bug search.".

+:- func weighting_to_reason_string(weighting_heuristic, int, int) = string.
+
+weighting_to_reason_string(number_of_events, Weight1, Weight2) = Str :-
+	Weight1Str = int_to_string_thousands(Weight1),
+	Weight2Str = int_to_string_thousands(Weight2),
+	Str = "this node divides the suspect area into " ++
+		"two regions of " ++ Weight1Str ++ " and " ++ Weight2Str ++
+		" events each.".
+
+weighting_to_reason_string(suspicion, Weight1, Weight2) = Str :-
+	Weight1Str = int_to_string_thousands(Weight1),
+	Weight2Str = int_to_string_thousands(Weight2),
+	Str = "this node divides the suspect area into " ++
+		"two regions of suspicion " ++ Weight1Str ++ " and 
+		" ++ Weight2Str ++ ".".
+
  show_info(Store, OutStream, Analyser, Response, !IO) :-
  	SearchSpace = Analyser ^ search_space,
  	some [!FieldNames, !Data] (
@@ -1297,32 +1339,41 @@
  		list.append(!.Data, [search_mode_to_string(
  			Analyser ^ search_mode)], !:Data),

+		MaybeWeighting = get_current_maybe_weighting(SearchSpace),
  		(
-			Analyser ^ search_mode = divide_and_query
+			MaybeWeighting = yes(number_of_events)
  		->
-			list.append(!.FieldNames, 
-				["Estimated questions remaining"], 
+			(
+				root(SearchSpace, RootId)
+			->
+				StartId = RootId
+			;
+				topmost_det(SearchSpace, StartId)
+			),
+       			Weight = get_weight(SearchSpace, StartId),
+			(
+				Analyser ^ search_mode = 
+					divide_and_query(number_of_events)
+			->
+				list.append(!.FieldNames, 
+					["Estimated questions remaining"], 
+					!:FieldNames),
+				EstimatedQuestions = float.ceiling_to_int(
+					math.log2(float(Weight))),
+				list.append(!.Data, 
+					[int_to_string(EstimatedQuestions)],
+					!:Data)
+			;
+				true
+			),
+			list.append(!.FieldNames, ["Number of suspect events"],
  				!:FieldNames),
-			EstimatedQuestions = float.ceiling_to_int(
-				math.log2(float(Weight))),
-			list.append(!.Data, 
-				[int_to_string(EstimatedQuestions)], !:Data)
+			list.append(!.Data, [int_to_string_thousands(Weight)],
+				!:Data)
  		;
  			true
  		),

-		list.append(!.FieldNames, ["Number of suspect events"], 
-			!:FieldNames),
-		(
-			root(SearchSpace, RootId)
-		->
-			StartId = RootId
-		;
-			topmost_det(SearchSpace, StartId)
-		),
-		Weight = get_weight(SearchSpace, StartId),
-		list.append(!.Data, [int_to_string_thousands(Weight)], !:Data),
-
  		InfoMessage = string.format_table([left(!.FieldNames),
  			left(!.Data)], " : ")
  	),
@@ -1341,4 +1392,7 @@
  search_mode_to_string(follow_subterm_end(_, _, _, _)) =
  	"tracking marked sub-term".
  search_mode_to_string(binary(_, _, _)) = "binary search on path".
-search_mode_to_string(divide_and_query) = "divide and query".
+search_mode_to_string(divide_and_query(number_of_events)) = 
+	"divide and query using number of events".
+search_mode_to_string(divide_and_query(suspicion)) = 
+	"divide and query using suspicion".
Index: browser/declarative_debugger.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/declarative_debugger.m,v
retrieving revision 1.61
diff -u -r1.61 declarative_debugger.m
--- browser/declarative_debugger.m	28 Jul 2005 06:44:07 -0000	1.61
+++ browser/declarative_debugger.m	4 Aug 2005 16:13:04 -0000
@@ -332,12 +332,16 @@
  :- import_module mdb.declarative_edt.
  :- import_module mdb.declarative_oracle.
  :- import_module mdb.util.
+:- import_module mdbcomp.label_layout.
  :- import_module mdbcomp.prim_data.
+:- import_module mdbcomp.slice_and_dice.
+:- import_module mdbcomp.trace_counts.

  :- import_module bool.
  :- import_module exception.
  :- import_module int.
  :- import_module map.
+:- import_module require.

  unravel_decl_atom(DeclAtom, TraceAtom, MaybeIoActions) :-
  	(
@@ -586,18 +590,19 @@
  	diagnoser_state_init(InStr, OutStr, Browser, HelpSystem, Diagnoser).

  :- pred set_fallback_search_mode(
+	trace_node_store::in,
  	mdb.declarative_analyser.search_mode::in,
  	diagnoser_state(trace_node_id)::in,
  	diagnoser_state(trace_node_id)::out) is det.

  :- pragma export(
-	mdb.declarative_debugger.set_fallback_search_mode(in, in, out), 
+	mdb.declarative_debugger.set_fallback_search_mode(in, in, in, out),
  	"MR_DD_decl_set_fallback_search_mode").

-set_fallback_search_mode(SearchMode, !Diagnoser) :-
+set_fallback_search_mode(Store, SearchMode, !Diagnoser) :-
  	Analyser0 = !.Diagnoser ^ analyser_state,
-	mdb.declarative_analyser.set_fallback_search_mode(SearchMode,
-		Analyser0, Analyser),
+	mdb.declarative_analyser.set_fallback_search_mode(wrap(Store), 
+		SearchMode, Analyser0, Analyser),
  	!:Diagnoser = !.Diagnoser ^ analyser_state := Analyser.

  :- func top_down_search_mode = 
@@ -617,6 +622,16 @@
  :- pragma export(mdb.declarative_debugger.divide_and_query_search_mode = out,
  	"MR_DD_decl_divide_and_query_search_mode").

+:- func suspicion_divide_and_query_search_mode = 
+	mdb.declarative_analyser.search_mode.
+
+suspicion_divide_and_query_search_mode = 
+	mdb.declarative_analyser.suspicion_divide_and_query_search_mode.
+
+:- pragma export(
+	mdb.declarative_debugger.suspicion_divide_and_query_search_mode = out, 
+	"MR_DD_decl_suspicion_divide_and_query_search_mode").
+
  	% Export a monomorphic version of diagnosis/10 that passes a newly
  	% materialized tree for use with the C backend code.
  	%
Index: browser/declarative_edt.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/declarative_edt.m,v
retrieving revision 1.12
diff -u -r1.12 declarative_edt.m
--- browser/declarative_edt.m	11 Jul 2005 07:30:20 -0000	1.12
+++ browser/declarative_edt.m	4 Aug 2005 09:28:25 -0000
@@ -146,12 +146,20 @@
  		%
  	pred edt_topmost_node(S::in, T::in) is semidet,

- 		% edt_weight(Store, Node, Weight, ExcessWeight).
-		% Find the weight and excess weight for a node.  See the 
-		% comment at the top of this module for the meaning of 
-		% the weight of a node.
-		%
- 	pred edt_weight(S::in, T::in, int::out, int::out) is det,
+ 		% edt_number_of_events(Store, Node, Events, DuplicateEvents).
+		% Find the number of events in the subtree rooted at Node,
+		% including the CALL and final event of Node.  In
+		% DuplicateEvents return the number of events which will 
+		% be repeated in siblings to the right of Node, times
+		% by the number of repetitions of each event.
+		% 
+ 	pred edt_number_of_events(S::in, T::in, int::out, int::out) is det,
+
+		% edt_subtree_suspicion(Store, Node, Suspicion, Excess).
+		% Find the suspicion of the subtree rooted at Node.
+		% Return any suspicion duplicated in siblings of Node in
+		% Excess.
+	pred edt_subtree_suspicion(S::in, T::in, int::out, int::out) is det,

  		% Return the filename and line number of the predicate
  		% associated with the given node.  Also return the parent
@@ -246,8 +254,8 @@
  	% Creates a new search space containing just the one EDT node with
  	% an initial status of unknown.
  	%
-:- pred initialise_search_space(S::in, T::in, search_space(T)::out) 
-	is det <= mercury_edt(S, T).
+:- pred initialise_search_space(S::in, maybe(weighting_heuristic)::in, T::in, 
+	search_space(T)::out) is det <= mercury_edt(S, T).

  	% The root of the search space is the root of the subtree of the EDT
  	% that we think contains a bug, based on information received so far.
@@ -510,6 +518,23 @@
  :- func get_proc_label_for_suspect(S, search_space(T), suspect_id) = proc_label
  	<= mercury_edt(S, T).

+:- type weighting_heuristic
+	--->	number_of_events
+	;	suspicion.
+
+	% Recalculate the value of the `weight' fields for all suspects in the
+	% search space if the given weighting heuristic is different from the
+	% previous one.
+	%
+:- pred update_weighting_heuristic(S::in, weighting_heuristic::in, 
+	search_space(T)::in, search_space(T)::out) is det <= mercury_edt(S, T).
+
+	% Return the meaning of the values of the `weight' fields of suspects
+	% in the search space.
+	%
+:- func get_current_maybe_weighting(search_space(T)) = 
+	maybe(weighting_heuristic).
+
  %-----------------------------------------------------------------------------%

  :- implementation.
@@ -609,11 +634,15 @@
  				% We use a bimap so we can also find the
  				% implicit root given an explicit root.
  				%
-			implicit_roots_to_explicit_roots	:: bimap(T, T)
+			implicit_roots_to_explicit_roots	:: bimap(T, T),
+
+				% The weighting heuristic (if any) used to
+				% calculate the weights of suspects.
+			maybe_weighting_heuristic :: maybe(weighting_heuristic)
  	).

  empty_search_space = search_space(no, no, counter.init(0), counter.init(0), 
-	map.init, bimap.init).
+	map.init, bimap.init, no).

  root(SearchSpace, RootId) :- SearchSpace ^ root = yes(RootId).

@@ -1152,6 +1181,7 @@

  check_search_space_consistency(Store, SearchSpace, Context) :-
  	(
+		SearchSpace ^ maybe_weighting_heuristic = yes(_),
  		find_inconsistency_in_weights(Store, SearchSpace, Message)
  	->
  		throw(internal_error("check_search_space_consistency",
@@ -1178,9 +1208,9 @@
  	% zero.  If the node is ignored then the weight is the sum of the
  	% weights of the children plus the sum of the excess weights of the
  	% children.  Otherwise the weight is the original weight of the node
-	% as reported by edt_weight/4 minus the original weights of the
-	% children as reported by edt_weight/4 plus the current weight of
-	% the children plus any excess weight in the children.
+	% as reported by calc_weight/5 minus the original weights of the
+	% children plus the current weight of the children plus any excess
+	% weight in the children.
  	%
  :- pred calc_suspect_weight(S::in, T::in, maybe(list(suspect_id))::in,
  	suspect_status::in, search_space(T)::in, int::out, int::out) 
@@ -1189,39 +1219,50 @@
  calc_suspect_weight(Store, Node, MaybeChildren, Status, SearchSpace, Weight,
  		ExcessWeight) :-
  	(
-		( Status = correct
-		; Status = inadmissible
-		)
-	->
-		Weight = 0,
-		ExcessWeight = 0
-	;
-		edt_weight(Store, Node, OriginalWeight, ExcessWeight),
+		SearchSpace ^ maybe_weighting_heuristic = yes(Weighting),
  		(
-			MaybeChildren = no,
-			Weight = OriginalWeight
+			( Status = correct
+			; Status = inadmissible
+			)
+		->
+			Weight = 0,
+			ExcessWeight = 0
  		;
-			MaybeChildren = yes(Children),
-			list.map(lookup_suspect(SearchSpace), Children,
-				ChildrenSuspects),
-			ChildrenNodes = list.map(
-				func(S) = N :- N = S ^ edt_node, 
-				ChildrenSuspects),
-			list.foldl2(add_original_weight(Store), 
-				ChildrenNodes, 0, ChildrenOriginalWeight,
-				0, ChildrenExcess),
-			list.foldl(add_existing_weight, ChildrenSuspects, 0,
-				ChildrenWeight),
+			calc_weight(Weighting, Store, Node, OriginalWeight, 
+				ExcessWeight),
  			(
-				Status = ignored
-			->
-				Weight = ChildrenWeight + ChildrenExcess
+				MaybeChildren = no,
+				Weight = OriginalWeight
  			;
-				Weight = OriginalWeight - 
-					ChildrenOriginalWeight + ChildrenWeight
-					+ ChildrenExcess
+				MaybeChildren = yes(Children),
+				list.map(lookup_suspect(SearchSpace), Children,
+					ChildrenSuspects),
+				ChildrenNodes = list.map(
+					func(S) = N :- N = S ^ edt_node, 
+					ChildrenSuspects),
+				list.foldl2(add_original_weight(Weighting, 
+					Store), 
+					ChildrenNodes, 0,
+					ChildrenOriginalWeight, 0,
+					ChildrenExcess),
+				list.foldl(add_existing_weight,
+					ChildrenSuspects, 0, ChildrenWeight),
+				(
+					Status = ignored
+				->
+					Weight = ChildrenWeight +
+						ChildrenExcess 
+				;
+					Weight = OriginalWeight -
+						ChildrenOriginalWeight +
+						ChildrenWeight + ChildrenExcess
+				)
  			)
  		)
+	;
+		SearchSpace ^ maybe_weighting_heuristic = no,
+		Weight = 0,
+		ExcessWeight = 0
  	).

  	% Add the given weight to the ancestors of the given suspect
@@ -1257,12 +1298,12 @@
  		true
  	).

-:- pred add_original_weight(S::in, T::in, int::in, int::out, int::in, int::out) 
-	is det <= mercury_edt(S, T).
+:- pred add_original_weight(weighting_heuristic::in, S::in, T::in, int::in, 
+	int::out, int::in, int::out) is det <= mercury_edt(S, T).

-add_original_weight(Store, Node, Prev, Prev + Weight, PrevExcess, 
+add_original_weight(Weighting, Store, Node, Prev, Prev + Weight, PrevExcess,
  		PrevExcess + Excess) :-
-	edt_weight(Store, Node, Weight, Excess).
+	calc_weight(Weighting, Store, Node, Weight, Excess).

  :- pred add_existing_weight(suspect(T)::in, int::in, int::out) is det.

@@ -1270,8 +1311,8 @@

  	% recalc_weights_upto_ancestor(Store, Ancestor, Suspects, !SearchSpace)
  	% Recalculate the weights of the suspects in Suspects and all their
-	% ancestors below Ancestor.  Ancestor must be a common ancestor
-	% of all the suspects in Suspects.
+	% ancestors below and including Ancestor.  Ancestor must be a common
+	% ancestor of all the suspects in Suspects.
  	%
  :- pred recalc_weights_upto_ancestor(S::in, suspect_id::in,
  	list(suspect_id)::in, search_space(T)::in, search_space(T)::out) 
@@ -1572,12 +1613,18 @@
  		true
  	).

-initialise_search_space(Store, Node, SearchSpace) :-
-	edt_weight(Store, Node, Weight, _),
+initialise_search_space(Store, MaybeWeighting, Node, SearchSpace) :-
+	(
+		MaybeWeighting = yes(Weighting),
+		calc_weight(Weighting, Store, Node, Weight, _)
+	;
+		MaybeWeighting = no,
+		Weight = 0
+	),
  	map.set(init, 0, suspect(no, Node, unknown, 0, no, Weight),
  		SuspectStore),
  	SearchSpace = search_space(no, yes(0), counter.init(1), 
-		counter.init(0), SuspectStore, bimap.init).
+		counter.init(0), SuspectStore, bimap.init, MaybeWeighting).

  incorporate_explicit_subtree(SuspectId, Node, !SearchSpace) :-
  	lookup_suspect(!.SearchSpace, SuspectId, Suspect),
@@ -1994,3 +2041,41 @@

  get_proc_label_for_suspect(Store, SearchSpace, SuspectId) =
  	edt_proc_label(Store, get_edt_node(SearchSpace, SuspectId)).
+
+update_weighting_heuristic(Store, Weighting, !SearchSpace) :-
+	MaybePrevWeighting = !.SearchSpace ^ maybe_weighting_heuristic,
+	(
+		MaybePrevWeighting = yes(PrevWeighting),
+		PrevWeighting = Weighting
+	->
+		true
+	;
+		!:SearchSpace = !.SearchSpace ^ maybe_weighting_heuristic 
+			:= yes(Weighting),
+		(
+			map.is_empty(!.SearchSpace ^ store)
+		->
+			true
+		;
+			%
+			% Recompute the suspect weights from the bottom up.
+			%
+			map.keys(!.SearchSpace ^ store, AllSuspects),
+			list.filter(suspect_is_leaf(!.SearchSpace),
+				AllSuspects, Leaves),
+			topmost_det(!.SearchSpace, TopId),
+			recalc_weights_upto_ancestor(Store, TopId, Leaves, 
+				!SearchSpace)
+		)
+	).
+
+:- pred calc_weight(weighting_heuristic::in,
+	S::in, T::in, int::out, int::out) is det <= mercury_edt(S, T).
+
+calc_weight(number_of_events, Store, Node, Weight, Excess) :-
+	edt_number_of_events(Store, Node, Weight, Excess).
+calc_weight(suspicion, Store, Node, Weight, Excess) :-
+	edt_subtree_suspicion(Store, Node, Weight, Excess).
+
+get_current_maybe_weighting(SearchSpace) = 
+	SearchSpace ^ maybe_weighting_heuristic.
Index: browser/declarative_execution.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/declarative_execution.m,v
retrieving revision 1.43
diff -u -r1.43 declarative_execution.m
--- browser/declarative_execution.m	20 May 2005 05:40:17 -0000	1.43
+++ browser/declarative_execution.m	4 Aug 2005 16:10:51 -0000
@@ -18,8 +18,8 @@

  :- interface.

-:- import_module mdb.util.
  :- import_module mdb.term_rep.
+:- import_module mdbcomp.label_layout.
  :- import_module mdbcomp.prim_data.
  :- import_module mdbcomp.program_representation.

@@ -59,10 +59,14 @@
  						% The return label, if there
  						% is one.
  			call_label		:: label_layout,
-			call_io_seq_num		:: int
+			call_io_seq_num		:: int,
  						% The I/O action sequence
  						% number at the time of the
  						% call.
+			call_suspicion		:: suspicion_accumulator
+						% The value of the suspicion
+						% accumulator at the time of
+						% the call.
  		)
  	;	exit(
  			exit_preceding		:: R,
@@ -76,10 +80,14 @@
  			exit_event		:: event_number,
  						% Trace event number.
  			exit_label		:: label_layout,
-			exit_io_seq_num		:: int
+			exit_io_seq_num		:: int,
  						% The I/O action sequence
  						% number at the time of the
  						% exit.
+			exit_suspicion		:: suspicion_accumulator
+						% The value of the suspicion
+						% accumulator at the time of
+						% the exit.
  		)
  	;	redo(
  			redo_preceding		:: R,
@@ -88,7 +96,11 @@
  						% EXIT event.
  			redo_event		:: event_number,
  						% REDO event number.
-			redo_label		:: label_layout
+			redo_label		:: label_layout,
+			redo_suspicion		:: suspicion_accumulator
+						% The value of the suspicion
+						% accumulator at the time of
+						% the redo.
  		)
  	;	fail(
  			fail_preceding		:: R,
@@ -99,7 +111,11 @@
  						% Previous REDO event, if any.
  			fail_event		:: event_number,
  						% Trace event number.
-			fail_label		:: label_layout
+			fail_label		:: label_layout,
+			fail_suspicion		:: suspicion_accumulator
+						% The value of the suspicion
+						% accumulator at the time of
+						% the fail.
  		)
  	;	excp(
  			excp_preceding		:: R,
@@ -112,7 +128,11 @@
  						% Exception thrown.
  			excp_event		:: event_number,
  						% Trace event number.
-			excp_label		:: label_layout
+			excp_label		:: label_layout,
+			excp_suspicion		:: suspicion_accumulator
+						% The value of the suspicion
+						% accumulator at the time of
+						% the excp.
  		)
  	;	switch(
  			switch_preceding	:: R,
@@ -221,14 +241,6 @@
  :- mode get_trace_call_atom(in(trace_node_call)) = out is det.
  :- mode get_trace_call_atom(in) = out is semidet.

-:- type proc_layout. 
-
-:- func get_proc_label_from_layout(proc_layout) = proc_label.
-
-:- func get_proc_name(proc_label) = string.
-
-:- func get_all_modes_for_layout(proc_layout) = list(proc_layout).
-
  	% get_pred_attributes(ProcLabel, Module, Name, Arity, PredOrFunc).
  	% Return the predicate/function attributes common to both UCI and
  	% regular predicates/functions. 
@@ -236,17 +248,6 @@
  :- pred get_pred_attributes(proc_label::in, module_name::out, string::out,
  	int::out, pred_or_func::out) is det.

-:- type label_layout.
-
-:- func get_proc_layout_from_label_layout(label_layout) = proc_layout.
-
-:- func get_goal_path_from_label_layout(label_layout) = goal_path_string.
-
-:- func get_goal_path_from_maybe_label(maybe(label_layout)) = goal_path_string.
-
-:- pred get_context_from_label_layout(label_layout::in, string::out, int::out)
-	is semidet.
-
  :- pred call_node_maybe_proc_rep(trace_node(R)::in(trace_node_call),
  	maybe(proc_rep)::out) is det.

@@ -263,6 +264,8 @@
  :- type sequence_number == int.
  :- type event_number == int.

+:- type suspicion_accumulator == int.
+
  	% Members of this typeclass represent an entire annotated
  	% trace.  The second parameter is the type of references
  	% to trace nodes, and the first parameter is the type of
@@ -315,13 +318,13 @@
  :- pred det_trace_node_from_id(S::in, R::in, trace_node(R)::out) is det
  	<= annotated_trace(S, R).

-:- inst trace_node_call ---> call(ground, ground, ground, ground, ground,
-	ground, ground, ground, ground).
+:- inst trace_node_call ---> call(ground, ground, ground, ground, ground, 
+	ground, ground, ground, ground, ground).

  :- pred call_node_from_id(S::in, R::in, trace_node(R)::out(trace_node_call))
  	is det <= annotated_trace(S, R).

-:- inst trace_node_redo ---> redo(ground, ground, ground, ground).
+:- inst trace_node_redo ---> redo(ground, ground, ground, ground, ground).

  	% maybe_redo_node_from_id/3 fails if the argument is a
  	% NULL reference.
@@ -331,7 +334,7 @@
  	<= annotated_trace(S, R).

  :- inst trace_node_exit ---> exit(ground, ground, ground, ground,
-	ground, ground, ground).
+	ground, ground, ground, ground).

  :- pred exit_node_from_id(S::in, R::in, trace_node(R)::out(trace_node_exit))
  	is det <= annotated_trace(S, R).
@@ -427,179 +430,6 @@

  %-----------------------------------------------------------------------------%

-:- pragma foreign_type("C", proc_layout, "const MR_Proc_Layout *",
-	[can_pass_as_mercury_type, stable]).
-:- pragma foreign_type("Java", proc_layout, "java.lang.Object", []). %stub only
-
-get_proc_label_from_layout(Layout) = ProcLabel :-
-	( proc_layout_is_uci(Layout) ->
-		proc_layout_get_uci_fields(Layout, TypeName, TypeModule,
-			DefModule, PredName, TypeArity, ModeNum),
-		( PredName = "__Unify__" ->
-			SpecialId = unify
-		; PredName = "__Index__" ->
-			SpecialId = index
-		; PredName = "__Compare__" ->
-			SpecialId = compare
-		;
-			error("get_proc_label_from_layout: " ++ 
-				"bad special_pred_id")
-		),
-		string_to_sym_name(DefModule, ".", SymDefModule),
-		string_to_sym_name(TypeModule, ".", SymTypeModule),
-		ProcLabel = special_proc(SymDefModule, SpecialId, 
-			SymTypeModule, TypeName, TypeArity, ModeNum)
-	;
-		proc_layout_get_non_uci_fields(Layout, PredOrFunc,
-			DeclModule, DefModule, PredName, Arity, ModeNum),
-		string_to_sym_name(DefModule, ".", SymDefModule),
-		string_to_sym_name(DeclModule, ".", SymDeclModule),
-		ProcLabel = proc(SymDefModule, PredOrFunc, SymDeclModule, 
-			PredName, Arity, ModeNum)
-	).
-
-get_proc_name(proc(_, _, _, ProcName, _, _)) = ProcName.
-get_proc_name(special_proc(_, _, _, ProcName , _, _)) = ProcName. 
-
-:- pred proc_layout_is_uci(proc_layout::in) is semidet.
-
-:- pragma foreign_proc("C",
-	proc_layout_is_uci(Layout::in),
-	[will_not_call_mercury, thread_safe, promise_pure],
-"
-	if (MR_PROC_ID_IS_UCI(Layout->MR_sle_proc_id)) {
-		SUCCESS_INDICATOR = MR_TRUE;
-	} else {
-		SUCCESS_INDICATOR = MR_FALSE;
-	}
-").
-
-:- pred proc_layout_get_uci_fields(proc_layout::in, string::out,
-	string::out, string::out, string::out, int::out, int::out) is det.
-
-:- pragma foreign_proc("C",
-	proc_layout_get_uci_fields(Layout::in, TypeName::out, TypeModule::out,
-		DefModule::out, PredName::out, TypeArity::out, ModeNum::out),
-	[will_not_call_mercury, thread_safe, promise_pure],
-"
-	const MR_UCI_Proc_Id	*proc_id;
-
-	proc_id = &Layout->MR_sle_uci;
-
-	/* The casts are there to cast away const without warnings */
-	TypeName   = (MR_String) (MR_Integer) proc_id->MR_uci_type_name;
-	TypeModule = (MR_String) (MR_Integer) proc_id->MR_uci_type_module;
-	DefModule  = (MR_String) (MR_Integer) proc_id->MR_uci_def_module;
-	PredName   = (MR_String) (MR_Integer) proc_id->MR_uci_pred_name;
-	TypeArity  = proc_id->MR_uci_type_arity;
-	ModeNum    = proc_id->MR_uci_mode;
-").
-
-:- pred proc_layout_get_non_uci_fields(proc_layout::in, pred_or_func::out,
-	string::out, string::out, string::out, int::out, int::out) is det.
-
-:- pragma foreign_proc("C",
-	proc_layout_get_non_uci_fields(Layout::in, PredOrFunc::out,
-		DeclModule::out, DefModule::out, PredName::out,
-		Arity::out, ModeNum::out),
-	[will_not_call_mercury, thread_safe, promise_pure],
-"
-	const MR_User_Proc_Id	*proc_id;
-
-	proc_id = &Layout->MR_sle_user;
-
-	/* The casts are there to cast away const without warnings */
-	PredOrFunc = proc_id->MR_user_pred_or_func;
-	DeclModule = (MR_String) (MR_Integer) proc_id->MR_user_decl_module;
-	DefModule  = (MR_String) (MR_Integer) proc_id->MR_user_def_module;
-	PredName   = (MR_String) (MR_Integer) proc_id->MR_user_name;
-	Arity      = proc_id->MR_user_arity;
-	ModeNum    = proc_id->MR_user_mode;
-").
-
-:- pragma foreign_proc("C",
-	get_all_modes_for_layout(Layout::in) = (Layouts::out),
-	[will_not_call_mercury, thread_safe, promise_pure],
-"
-	const MR_Module_Layout	*module;
-	const MR_Proc_Layout	*proc;
-	int			i;
-	MR_Word			list;
-	MR_bool			match;
-	const MR_Proc_Layout	*selected_proc;
-
-	selected_proc = Layout;
-
-	if (! MR_PROC_LAYOUT_HAS_EXEC_TRACE(selected_proc)) {
-		MR_fatal_error(
-			""get_all_modes_for_layout: selected_proc"");
-	}
-
-	module = selected_proc->MR_sle_module_layout;
-	list = MR_list_empty();
-	for (i = 0; i < module->MR_ml_proc_count; i++) {
-		proc = module->MR_ml_procs[i];
-		if (! MR_PROC_LAYOUT_HAS_EXEC_TRACE(selected_proc)) {
-			MR_fatal_error(
-				""get_all_modes_for_layout: proc"");
-		}
-
-		if (MR_PROC_LAYOUT_IS_UCI(selected_proc)
-			&& MR_PROC_LAYOUT_IS_UCI(proc))
-		{
-			const MR_UCI_Proc_Id	*proc_id;
-			const MR_UCI_Proc_Id	*selected_proc_id;
-
-			proc_id = &proc->MR_sle_uci;
-			selected_proc_id = &selected_proc->MR_sle_uci;
-
-			if (MR_streq(proc_id->MR_uci_type_name,
-				selected_proc_id->MR_uci_type_name)
-			&& MR_streq(proc_id->MR_uci_type_module,
-				selected_proc_id->MR_uci_type_module)
-			&& MR_streq(proc_id->MR_uci_pred_name,
-				selected_proc_id->MR_uci_pred_name)
-			&& (proc_id->MR_uci_type_arity ==
-				selected_proc_id->MR_uci_type_arity))
-			{
-				match = MR_TRUE;
-			} else {
-				match = MR_FALSE;
-			}
-		} else if (!MR_PROC_LAYOUT_IS_UCI(selected_proc)
-			&& !MR_PROC_LAYOUT_IS_UCI(proc))
-		{
-			const MR_User_Proc_Id	*proc_id;
-			const MR_User_Proc_Id	*selected_proc_id;
-
-			proc_id = &proc->MR_sle_user;
-			selected_proc_id = &selected_proc->MR_sle_user;
-
-			if ((proc_id->MR_user_pred_or_func ==
-				selected_proc_id->MR_user_pred_or_func)
-			&& MR_streq(proc_id->MR_user_decl_module,
-				selected_proc_id->MR_user_decl_module)
-			&& MR_streq(proc_id->MR_user_name,
-				selected_proc_id->MR_user_name)
-			&& (proc_id->MR_user_arity ==
-				selected_proc_id->MR_user_arity))
-			{
-				match = MR_TRUE;
-			} else {
-				match = MR_FALSE;
-			}
-		} else {
-			match = MR_FALSE;
-		}
-
-		if (match) {
-			list = MR_int_list_cons((MR_Integer) proc, list);
-		}
-	}
-
-	Layouts = list;
-	").
-
  :- func get_special_pred_id_name(special_pred_id) = string.

  get_special_pred_id_name(unify) = "__Unify__".
@@ -626,42 +456,6 @@

  %-----------------------------------------------------------------------------%

-:- pragma foreign_type("C", label_layout, "const MR_Label_Layout *",
-	[can_pass_as_mercury_type, stable]).
-
-	% stub only
-:- pragma foreign_type("Java", label_layout, "java.lang.Object", []). 
-
-:- pragma foreign_proc("C",
-	get_proc_layout_from_label_layout(Label::in) = (ProcLayout::out),
-	[will_not_call_mercury, thread_safe, promise_pure],
-"
-	ProcLayout = Label->MR_sll_entry;
-").
-
-:- pragma foreign_proc("C",
-	get_goal_path_from_label_layout(Label::in) = (GoalPath::out),
-	[will_not_call_mercury, thread_safe, promise_pure],
-"
-	GoalPath = (MR_String)MR_label_goal_path(Label);
-").
-
-get_goal_path_from_maybe_label(yes(Label)) 
-	= get_goal_path_from_label_layout(Label).
-get_goal_path_from_maybe_label(no) = "".
-
-:- pragma foreign_proc("C",
-	get_context_from_label_layout(Label::in, FileName::out, LineNo::out), 
-	[will_not_call_mercury, thread_safe, promise_pure],
-"
-	const char	*filename;
- 
-	SUCCESS_INDICATOR = MR_find_context(Label, &filename, &LineNo);
-	MR_TRACE_USE_HP(
-		MR_make_aligned_string(FileName, (MR_String) filename);
-	);
-").
-
  :- pragma promise_pure(call_node_maybe_proc_rep/2).

  call_node_maybe_proc_rep(CallNode, MaybeProcRep) :-
@@ -765,20 +559,20 @@

  %-----------------------------------------------------------------------------%

-get_trace_exit_atom(exit(_, _, _, AtomArgs, _, Label, _)) = Atom :-
+get_trace_exit_atom(exit(_, _, _, AtomArgs, _, Label, _, _)) = Atom :-
  	ProcLayout = get_proc_layout_from_label_layout(Label),
  	Atom = atom(ProcLayout, AtomArgs).

-get_trace_call_atom(call(_, _, AtomArgs, _, _, _, _, Label, _)) = Atom :-
+get_trace_call_atom(call(_, _, AtomArgs, _, _, _, _, Label, _, _)) = Atom :-
  	ProcLayout = get_proc_layout_from_label_layout(Label),
  	Atom = atom(ProcLayout, AtomArgs).

  %-----------------------------------------------------------------------------%

-step_left_in_contour(Store, exit(_, Call, _, _, _, _, _)) = Prec :-
+step_left_in_contour(Store, exit(_, Call, _, _, _, _, _, _)) = Prec :-
  	call_node_from_id(Store, Call, CallNode),
  	Prec = CallNode ^ call_preceding.
-step_left_in_contour(Store, excp(_, Call, _, _, _, _)) = Prec :-
+step_left_in_contour(Store, excp(_, Call, _, _, _, _, _)) = Prec :-
  	call_node_from_id(Store, Call, CallNode),
  	Prec = CallNode ^ call_preceding.
  step_left_in_contour(_, switch(Prec, _)) = Prec.
@@ -803,7 +597,7 @@
  	% The following cases are possibly at the left end of a contour,
  	% where we cannot step any further.
  	%
-step_left_in_contour(_, call(_, _, _, _, _, _, _, _, _)) = _ :-
+step_left_in_contour(_, call(_, _, _, _, _, _, _, _, _, _)) = _ :-
  	throw(internal_error("step_left_in_contour", "unexpected CALL node")).
  step_left_in_contour(_, neg(Prec, _, Status)) = Next :-
  	(
@@ -824,10 +618,10 @@
  	% step to the previous contour instead.
  	%
  step_left_in_contour(Store, Node) = Prec :-
-	Node = fail(_, _, _, _, _),
+	Node = fail(_, _, _, _, _, _),
  	find_prev_contour(Store, Node, Prec).
  step_left_in_contour(Store, Node) = Prec :-
-	Node = redo(_, _, _, _),
+	Node = redo(_, _, _, _, _),
  	find_prev_contour(Store, Node, Prec).
  step_left_in_contour(Store, Node) = Prec :-
  	Node = neg_fail(_, _, _),
@@ -841,14 +635,14 @@
  :- mode find_prev_contour(in, in(trace_node_reverse), out) is det.

  :- inst trace_node_reverse
-	---> 	fail(ground, ground, ground, ground, ground)
-	;	redo(ground, ground, ground, ground)
+	---> 	fail(ground, ground, ground, ground, ground, ground)
+	;	redo(ground, ground, ground, ground, ground)
  	;	neg_fail(ground, ground, ground).

-find_prev_contour(Store, fail(_, Call, _, _, _), OnContour) :-
+find_prev_contour(Store, fail(_, Call, _, _, _, _), OnContour) :-
  	call_node_from_id(Store, Call, CallNode),
  	OnContour = CallNode ^ call_preceding.
-find_prev_contour(Store, redo(_, Exit, _, _), OnContour) :-
+find_prev_contour(Store, redo(_, Exit, _, _, _), OnContour) :-
  	exit_node_from_id(Store, Exit, ExitNode),
  	OnContour = ExitNode ^ exit_preceding.
  find_prev_contour(Store, neg_fail(_, Neg, _), OnContour) :-
@@ -857,20 +651,20 @@
  	% The following cases are at the left end of a contour,
  	% so there are no previous contours in the same stratum.
  	%
-find_prev_contour(_, call(_, _, _, _, _, _, _, _, _), _) :-
+find_prev_contour(_, call(_, _, _, _, _, _, _, _, _, _), _) :-
  	throw(internal_error("find_prev_contour", "reached CALL node")).
  find_prev_contour(_, cond(_, _, _), _) :-
  	throw(internal_error("find_prev_contour", "reached COND node")).
  find_prev_contour(_, neg(_, _, _), _) :-
  	throw(internal_error("find_prev_contour", "reached NEGE node")).

-step_in_stratum(Store, exit(_, Call, MaybeRedo, _, _, _, _)) =
+step_in_stratum(Store, exit(_, Call, MaybeRedo, _, _, _, _, _)) =
  	step_over_redo_or_call(Store, Call, MaybeRedo).
-step_in_stratum(Store, fail(_, Call, MaybeRedo, _, _)) =
+step_in_stratum(Store, fail(_, Call, MaybeRedo, _, _, _)) =
  	step_over_redo_or_call(Store, Call, MaybeRedo).
-step_in_stratum(Store, excp(_, Call, MaybeRedo, _, _, _)) =
+step_in_stratum(Store, excp(_, Call, MaybeRedo, _, _, _, _)) =
  	step_over_redo_or_call(Store, Call, MaybeRedo).
-step_in_stratum(Store, redo(_, Exit, _, _)) = Next :-
+step_in_stratum(Store, redo(_, Exit, _, _, _)) = Next :-
  	exit_node_from_id(Store, Exit, ExitNode),
  	Next = ExitNode ^ exit_preceding.
  step_in_stratum(_, switch(Next, _)) = Next.
@@ -895,7 +689,7 @@
  	% The following cases mark the boundary of the stratum,
  	% so we cannot step any further.
  	%
-step_in_stratum(_, call(_, _, _, _, _, _, _, _, _)) = _ :-
+step_in_stratum(_, call(_, _, _, _, _, _, _, _, _, _)) = _ :-
  	throw(internal_error("step_in_stratum", "unexpected CALL node")).
  step_in_stratum(_, neg(_, _, _)) = _ :-
  	throw(internal_error("step_in_stratum", "unexpected NEGE node")).
@@ -906,7 +700,7 @@
  	(
  		maybe_redo_node_from_id(Store, MaybeRedo, Redo)
  	->
-		Redo = redo(Next, _, _, _)
+		Redo = redo(Next, _, _, _, _)
  	;
  		call_node_from_id(Store, Call, CallNode),
  		Next = CallNode ^ call_preceding
@@ -924,7 +718,7 @@
  call_node_from_id(Store, NodeId, Node) :-
  	(
  		trace_node_from_id(Store, NodeId, Node0),
-		Node0 = call(_, _, _, _, _, _, _, _, _)
+		Node0 = call(_, _, _, _, _, _, _, _, _, _)
  	->
  		Node = Node0
  	;
@@ -934,7 +728,7 @@
  maybe_redo_node_from_id(Store, NodeId, Node) :-
  	trace_node_from_id(Store, NodeId, Node0),
  	(
-		Node0 = redo(_, _, _, _)
+		Node0 = redo(_, _, _, _, _)
  	->
  		Node = Node0
  	;
@@ -945,7 +739,7 @@
  exit_node_from_id(Store, NodeId, Node) :-
  	(
  		trace_node_from_id(Store, NodeId, Node0),
-		Node0 = exit(_, _, _, _, _, _, _)
+		Node0 = exit(_, _, _, _, _, _, _, _)
  	->
  		Node = Node0
  	;
@@ -1042,7 +836,7 @@

  call_node_get_last_interface(Call) = Last :-
  	(
-		Call = call(_, Last0, _, _, _, _, _, _, _)
+		Call = call(_, Last0, _, _, _, _, _, _, _, _)
  	->
  		Last = Last0
  	;
@@ -1058,7 +852,7 @@

  call_node_set_last_interface(Call0, Last) = Call :-
  	(
-		Call0 = call(_, _, _, _, _, _, _, _, _)
+		Call0 = call(_, _, _, _, _, _, _, _, _, _)
  	->
  		Call1 = Call0
  	;
@@ -1078,7 +872,7 @@

  call_node_update_implicit_tree_info(Call0, IdealDepth) = Call :-
  	(
-		Call0 = call(_, _, _, _, _, _, _, _, _)
+		Call0 = call(_, _, _, _, _, _, _, _, _, _)
  	->
  		Call1 = Call0
  	;
@@ -1165,11 +959,11 @@
  :- pragma export(trace_node_port(in) = out,
  		"MR_DD_trace_node_port").

-trace_node_port(call(_, _, _, _, _, _, _, _, _))	= call.
-trace_node_port(exit(_, _, _, _, _, _, _))		= exit.
-trace_node_port(redo(_, _, _, _))			= redo.
-trace_node_port(fail(_, _, _, _, _))			= fail.
-trace_node_port(excp(_, _, _, _, _, _))			= exception.
+trace_node_port(call(_, _, _, _, _, _, _, _, _, _))	= call.
+trace_node_port(exit(_, _, _, _, _, _, _, _))		= exit.
+trace_node_port(redo(_, _, _, _, _))			= redo.
+trace_node_port(fail(_, _, _, _, _, _))			= fail.
+trace_node_port(excp(_, _, _, _, _, _, _))		= exception.
  trace_node_port(switch(_, _))				= switch.
  trace_node_port(first_disj(_, _))			= disj.
  trace_node_port(later_disj(_, _, _))			= disj.
@@ -1189,11 +983,11 @@

  :- func get_trace_node_label(trace_node(R)) = label_layout.

-get_trace_node_label(call(_, _, _, _, _, _, _, Label, _)) = Label.
-get_trace_node_label(exit(_, _, _, _, _, Label, _)) = Label.
-get_trace_node_label(redo(_, _, _, Label)) = Label.
-get_trace_node_label(fail(_, _, _, _, Label)) = Label.
-get_trace_node_label(excp(_, _, _, _, _, Label)) = Label.
+get_trace_node_label(call(_, _, _, _, _, _, _, Label, _, _)) = Label.
+get_trace_node_label(exit(_, _, _, _, _, Label, _, _)) = Label.
+get_trace_node_label(redo(_, _, _, Label, _)) = Label.
+get_trace_node_label(fail(_, _, _, _, Label, _)) = Label.
+get_trace_node_label(excp(_, _, _, _, _, Label, _)) = Label.
  get_trace_node_label(switch(_, Label)) = Label.
  get_trace_node_label(first_disj(_, Label)) = Label.
  get_trace_node_label(later_disj(_, Label, _)) = Label.
@@ -1225,12 +1019,12 @@

  :- pragma export(trace_node_call(in, in, out), "MR_DD_trace_node_call").

-trace_node_call(_, exit(_, Call, _, _, _, _, _), Call).
-trace_node_call(S, redo(_, Exit, _, _), Call) :-
+trace_node_call(_, exit(_, Call, _, _, _, _, _, _), Call).
+trace_node_call(S, redo(_, Exit, _, _, _), Call) :-
  	exit_node_from_id(S, Exit, ExitNode),
  	Call = ExitNode ^ exit_call.
-trace_node_call(_, fail(_, Call, _, _, _), Call).
-trace_node_call(_, excp(_, Call, _, _, _, _), Call).
+trace_node_call(_, fail(_, Call, _, _, _, _), Call).
+trace_node_call(_, excp(_, Call, _, _, _, _, _), Call).

  :- pred trace_node_first_disj(trace_node(trace_node_id)::in,
  	trace_node_id::out) is semidet.
@@ -1294,13 +1088,13 @@
  	%

  :- func construct_call_node(trace_node_id, list(trace_atom_arg), 
-	sequence_number, event_number, bool, maybe(label_layout), label_layout,
-	int) = trace_node(trace_node_id).
-:- pragma export(construct_call_node(in, in, in, in, in, in, in, in) = out,
-	"MR_DD_construct_call_node").
+	sequence_number, event_number, bool, maybe(label_layout), 
+	label_layout, int, suspicion_accumulator) = trace_node(trace_node_id).
+:- pragma export(construct_call_node(in, in, in, in, in, in, in, in, in) 
+	= out, "MR_DD_construct_call_node").

  construct_call_node(Preceding, AtomArgs, SeqNo, EventNo, AtMaxDepth, 
-		MaybeReturnLabel, Label, IoSeqNum) = Call :-
+		MaybeReturnLabel, Label, IoSeqNum, Suspicion) = Call :-
  	(
  		AtMaxDepth = no,
  		MaybeImplicitTreeInfo = no
@@ -1313,7 +1107,8 @@
  	),
  	null_trace_node_id(LastInterface),
  	Call = call(Preceding, LastInterface, AtomArgs, SeqNo, EventNo, 
-		MaybeImplicitTreeInfo, MaybeReturnLabel, Label, IoSeqNum).
+		MaybeImplicitTreeInfo, MaybeReturnLabel, Label, IoSeqNum,
+		Suspicion).

  :- func make_yes_maybe_label(label_layout) = maybe(label_layout).
  :- pragma export(make_yes_maybe_label(in) = out, "MR_DD_make_yes_maybe_label").
@@ -1326,41 +1121,44 @@
  make_no_maybe_label = no.

  :- func construct_exit_node(trace_node_id, trace_node_id, trace_node_id,
-	list(trace_atom_arg), event_number, label_layout, int) 
-	= trace_node(trace_node_id).
-:- pragma export(construct_exit_node(in, in, in, in, in, in, in) = out,
+	list(trace_atom_arg), event_number, label_layout, int,
+	suspicion_accumulator) = trace_node(trace_node_id).
+:- pragma export(construct_exit_node(in, in, in, in, in, in, in, in) = out,
  	"MR_DD_construct_exit_node").

  construct_exit_node(Preceding, Call, MaybeRedo, AtomArgs, EventNo, Label, 
-		IoSeqNum) = 
-	exit(Preceding, Call, MaybeRedo, AtomArgs, EventNo, Label, IoSeqNum).
+		IoSeqNum, Suspicion) = 
+	exit(Preceding, Call, MaybeRedo, AtomArgs, EventNo, Label, IoSeqNum,
+		Suspicion).

  :- func construct_redo_node(trace_node_id, trace_node_id, event_number,
-	label_layout) = trace_node(trace_node_id).
-:- pragma export(construct_redo_node(in, in, in, in) = out,
+	label_layout, suspicion_accumulator) = trace_node(trace_node_id).
+:- pragma export(construct_redo_node(in, in, in, in, in) = out,
  	"MR_DD_construct_redo_node").

-construct_redo_node(Preceding, Exit, Event, Label) 
-	= redo(Preceding, Exit, Event, Label).
+construct_redo_node(Preceding, Exit, Event, Label, Suspicion) 
+	= redo(Preceding, Exit, Event, Label, Suspicion).

  :- func construct_fail_node(trace_node_id, trace_node_id, trace_node_id,
-	event_number, label_layout) = trace_node(trace_node_id).
-:- pragma export(construct_fail_node(in, in, in, in, in) = out,
+	event_number, label_layout, suspicion_accumulator) 
+	= trace_node(trace_node_id).
+:- pragma export(construct_fail_node(in, in, in, in, in, in) = out,
  	"MR_DD_construct_fail_node").

-construct_fail_node(Preceding, Call, Redo, EventNo, Label) =
-		fail(Preceding, Call, Redo, EventNo, Label).
+construct_fail_node(Preceding, Call, Redo, EventNo, Label, Suspicion) =
+		fail(Preceding, Call, Redo, EventNo, Label, Suspicion).

  :- pred construct_excp_node(trace_node_id::in, trace_node_id::in,
  	trace_node_id::in, univ::in, event_number::in, label_layout::in,
-	trace_node(trace_node_id)::out) is cc_multi.
-:- pragma export(construct_excp_node(in, in, in, in, in, in, out),
+	suspicion_accumulator::in, trace_node(trace_node_id)::out) is cc_multi.
+:- pragma export(construct_excp_node(in, in, in, in, in, in, in, out),
  	"MR_DD_construct_excp_node").

  construct_excp_node(Preceding, Call, MaybeRedo, Exception, EventNo, Label, 
-		Excp) :-
+		Suspicion, Excp) :-
  	term_rep.univ_to_rep(Exception, ExceptionRep),
-	Excp = excp(Preceding, Call, MaybeRedo, ExceptionRep, EventNo, Label).
+	Excp = excp(Preceding, Call, MaybeRedo, ExceptionRep, EventNo, Label,
+		Suspicion).

  :- func construct_switch_node(trace_node_id, label_layout)
  		= trace_node(trace_node_id).
@@ -1601,20 +1399,20 @@
  	%
  :- func preceding_node(trace_node(T)) = T.

-preceding_node(call(P, _, _, _, _, _, _, _, _)) = P.
-preceding_node(exit(P, _, _, _, _, _, _))	= P.
-preceding_node(redo(P, _, _, _))		= P.
-preceding_node(fail(P, _, _, _, _))		= P.
-preceding_node(excp(P, _, _, _, _, _))		= P.
-preceding_node(switch(P, _))			= P.
-preceding_node(first_disj(P, _))		= P.
-preceding_node(later_disj(P, _, _))		= P.
-preceding_node(cond(P, _, _))			= P.
-preceding_node(then(P, _, _))			= P.
-preceding_node(else(P, _, _))			= P.
-preceding_node(neg(P, _, _))			= P.
-preceding_node(neg_succ(P, _, _))		= P.
-preceding_node(neg_fail(P, _, _))		= P.
+preceding_node(call(P, _, _, _, _, _, _, _, _, _))	= P.
+preceding_node(exit(P, _, _, _, _, _, _, _))		= P.
+preceding_node(redo(P, _, _, _, _))			= P.
+preceding_node(fail(P, _, _, _, _, _))			= P.
+preceding_node(excp(P, _, _, _, _, _, _))		= P.
+preceding_node(switch(P, _))				= P.
+preceding_node(first_disj(P, _))			= P.
+preceding_node(later_disj(P, _, _))			= P.
+preceding_node(cond(P, _, _))				= P.
+preceding_node(then(P, _, _))				= P.
+preceding_node(else(P, _, _))				= P.
+preceding_node(neg(P, _, _))				= P.
+preceding_node(neg_succ(P, _, _))			= P.
+preceding_node(neg_fail(P, _, _))			= P.

  %-----------------------------------------------------------------------------%

Index: browser/declarative_oracle.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/declarative_oracle.m,v
retrieving revision 1.44
diff -u -r1.44 declarative_oracle.m
--- browser/declarative_oracle.m	28 Jul 2005 06:44:07 -0000	1.44
+++ browser/declarative_oracle.m	4 Aug 2005 16:15:29 -0000
@@ -28,9 +28,9 @@

  :- import_module mdb.browser_info.
  :- import_module mdb.declarative_debugger.
-:- import_module mdb.declarative_execution.
  :- import_module mdb.help.
  :- import_module mdbcomp.prim_data.
+:- import_module mdbcomp.label_layout.

  :- import_module bool.
  :- import_module io. 
@@ -146,6 +146,7 @@

  :- implementation.

+:- import_module mdb.declarative_execution.
  :- import_module mdb.declarative_user.
  :- import_module mdb.util.
  :- import_module mdbcomp.prim_data.
Index: browser/declarative_tree.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/declarative_tree.m,v
retrieving revision 1.31
diff -u -r1.31 declarative_tree.m
--- browser/declarative_tree.m	27 Jul 2005 05:09:25 -0000	1.31
+++ browser/declarative_tree.m	4 Aug 2005 16:16:06 -0000
@@ -50,6 +50,7 @@
  :- import_module mdb.declarative_debugger.
  :- import_module mdb.io_action.
  :- import_module mdb.util.
+:- import_module mdbcomp.label_layout.
  :- import_module mdbcomp.prim_data.
  :- import_module mdbcomp.program_representation.

@@ -75,7 +76,8 @@
  		pred(edt_is_implicit_root/2) is trace_is_implicit_root,
  		pred(edt_same_nodes/3) is trace_same_event_numbers,
  		pred(edt_topmost_node/2) is trace_topmost_node,
- 		pred(edt_weight/4) is trace_weight,
+ 		pred(edt_number_of_events/4) is trace_number_of_events,
+ 		pred(edt_subtree_suspicion/4) is trace_subtree_suspicion,
   		pred(edt_context/4) is trace_context,
  		func(edt_proc_label/2) is trace_node_proc_label,
  		func(edt_arg_pos_to_user_arg_num/3) is
@@ -116,13 +118,13 @@
  get_edt_node_initial_atom(Store, Ref, Atom) :-
  	det_edt_return_node_from_id(Store, Ref, Node),
  	(
-		Node = exit(_, CallId, _, _, _, _, _),
+		Node = exit(_, CallId, _, _, _, _, _, _),
  		Atom = call_node_decl_atom(Store, CallId)
  	;
-		Node = fail(_, CallId, _, _, _),
+		Node = fail(_, CallId, _, _, _, _),
  		Atom = call_node_decl_atom(Store, CallId)
  	;
-		Node = excp(_, CallId, _, _, _, _),
+		Node = excp(_, CallId, _, _, _, _, _),
  		Atom = call_node_decl_atom(Store, CallId)
  	).

@@ -132,11 +134,11 @@
  get_edt_node_event_number(Store, Ref, Event) :-
  	det_edt_return_node_from_id(Store, Ref, Node),
  	(
-		Node = exit(_, _, _, _, Event, _, _)
+		Node = exit(_, _, _, _, Event, _, _, _)
  	;
-		Node = fail(_, _, _, Event, _)
+		Node = fail(_, _, _, Event, _, _)
  	;
-		Node = excp(_, _, _, _, Event, _)
+		Node = excp(_, _, _, _, Event, _, _)
  	).

  %-----------------------------------------------------------------------------%
@@ -147,17 +149,17 @@
  trace_question(wrap(Store), dynamic(Ref), Root) :-
  	det_edt_return_node_from_id(Store, Ref, Node),
  	(
-		Node = fail(_, CallId, RedoId, _, _),
+		Node = fail(_, CallId, RedoId, _, _, _),
  		DeclAtom = call_node_decl_atom(Store, CallId),
  		get_answers(Store, RedoId, [], Answers),
  		Root = missing_answer(dynamic(Ref), DeclAtom, Answers)
  	;
-		Node = exit(_, CallId, _, _, _, _, _),
+		Node = exit(_, CallId, _, _, _, _, _, _),
  		InitDeclAtom = call_node_decl_atom(Store, CallId),
  		FinalDeclAtom = exit_node_decl_atom(Store, Node),
  		Root = wrong_answer(dynamic(Ref), InitDeclAtom, FinalDeclAtom)
  	;
-		Node = excp(_, CallId, _, Exception, _, _),
+		Node = excp(_, CallId, _, Exception, _, _, _),
  		DeclAtom = call_node_decl_atom(Store, CallId),
  		Root = unexpected_exception(dynamic(Ref), DeclAtom, Exception)
  	).
@@ -168,7 +170,8 @@

  get_answers(Store, RedoId, DeclAtoms0, DeclAtoms) :-
  	(
-		maybe_redo_node_from_id(Store, RedoId, redo(_, ExitId, _, _))
+		maybe_redo_node_from_id(Store, RedoId, redo(_, ExitId, _, _,
+			_))
  	->
  		exit_node_from_id(Store, ExitId, ExitNode),
  		NextId = ExitNode ^ exit_prev_redo,
@@ -184,18 +187,18 @@
  trace_get_e_bug(wrap(Store), dynamic(Ref), Bug) :-
  	det_edt_return_node_from_id(Store, Ref, Node),
  	(
-		Node = exit(_, CallId, _, _, Event, _, _),
+		Node = exit(_, CallId, _, _, Event, _, _, _),
  		InitDeclAtom = call_node_decl_atom(Store, CallId),
  		FinalDeclAtom = exit_node_decl_atom(Store, Node),
  		get_exit_atoms_in_contour(Store, Node, Contour),
  		Bug = incorrect_contour(InitDeclAtom, FinalDeclAtom, Contour,
  			Event)
  	;
-		Node = fail(_, CallId, _, Event, _),
+		Node = fail(_, CallId, _, Event, _, _),
  		DeclAtom = call_node_decl_atom(Store, CallId),
  		Bug = partially_uncovered_atom(DeclAtom, Event)
  	;
-		Node = excp(_, CallId, _, Exception, Event, _),
+		Node = excp(_, CallId, _, Exception, Event, _, _),
  		DeclAtom = call_node_decl_atom(Store, CallId),
  		Bug = unhandled_exception(DeclAtom, Exception, Event)
  	).
@@ -226,11 +229,11 @@
  trace_last_parent(wrap(Store), dynamic(Ref), dynamic(Parent)) :-
  	det_edt_return_node_from_id(Store, Ref, Node),
  	(
-		Node = fail(_, CallId, _, _, _)
+		Node = fail(_, CallId, _, _, _, _)
  	;
-		Node = exit(_, CallId, _, _, _, _, _)
+		Node = exit(_, CallId, _, _, _, _, _, _)
  	;
-		Node = excp(_, CallId, _, _, _, _)
+		Node = excp(_, CallId, _, _, _, _, _)
  	),
  	call_node_from_id(Store, CallId, Call),
  	CallPrecId = Call ^ call_preceding,
@@ -244,14 +247,14 @@
  	det_edt_return_node_from_id(Store, Ref1, Node1),
  	det_edt_return_node_from_id(Store, Ref2, Node2),
  	(
-		Node1 = exit(_, _, _, _, Event, _, _),
-		Node2 = exit(_, _, _, _, Event, _, _)
+		Node1 = exit(_, _, _, _, Event, _, _, _),
+		Node2 = exit(_, _, _, _, Event, _, _, _)
  	;
-		Node1 = fail(_, _, _, Event, _),
-		Node2 = fail(_, _, _, Event, _)
+		Node1 = fail(_, _, _, Event, _, _),
+		Node2 = fail(_, _, _, Event, _, _)
  	;
-		Node1 = excp(_, _, _, _, Event, _),
-		Node2 = excp(_, _, _, _, Event, _)
+		Node1 = excp(_, _, _, _, Event, _, _),
+		Node2 = excp(_, _, _, _, Event, _, _)
  	).

  :- pred trace_topmost_node(wrap(S)::in, edt_node(R)::in) is semidet
@@ -260,14 +263,14 @@
  trace_topmost_node(wrap(Store), dynamic(Ref)) :-
  	det_edt_return_node_from_id(Store, Ref, Node),
  	(
-		Node = exit(_, CallId, _, _, _, _, _)
+		Node = exit(_, CallId, _, _, _, _, _, _)
  	;
-		Node = fail(_, CallId, _, _, _)
+		Node = fail(_, CallId, _, _, _, _)
  	;
-		Node = excp(_, CallId, _, _, _, _)
+		Node = excp(_, CallId, _, _, _, _, _)
  	),
  	% The node is topmost of the call sequence number is 1.
-	call_node_from_id(Store, CallId, call(_, _, _, 1, _, _, _, _, _)).
+	call_node_from_id(Store, CallId, call(_, _, _, 1, _, _, _, _, _, _)).

  :- pred trace_children(wrap(S)::in, edt_node(R)::in, list(edt_node(R))::out)
  	is semidet <= annotated_trace(S, R).
@@ -275,11 +278,11 @@
  trace_children(wrap(Store), dynamic(Ref), Children) :-
  	det_edt_return_node_from_id(Store, Ref, Node),
  	(
-		Node = fail(PrecId, CallId, _, _, _),
+		Node = fail(PrecId, CallId, _, _, _, _),
  		not_at_depth_limit(Store, CallId),
  		stratum_children(Store, PrecId, CallId, [], Children)
  	;
-		Node = exit(PrecId, CallId, _, _, _, _, _),
+		Node = exit(PrecId, CallId, _, _, _, _, _, _),
  		Atom = get_trace_exit_atom(Node),
  		not_at_depth_limit(Store, CallId),
  		(
@@ -292,7 +295,7 @@
  				[], Children)
  		)
  	;
-		Node = excp(PrecId, CallId, _, _, _, _),
+		Node = excp(PrecId, CallId, _, _, _, _, _),
  		not_at_depth_limit(Store, CallId),
  		contour_children(exception, Store, PrecId, CallId, [],
  			Children)
@@ -310,86 +313,123 @@
  	call_node_from_id(Store, CallId, CallNode),
  	CallNode ^ call_at_max_depth = yes(ImplicitTreeInfo).

-:- pred trace_weight(wrap(S)::in, edt_node(R)::in, int::out, int::out)
-	is det <= annotated_trace(S, R).
-
-trace_weight(Store, NodeId, Weight, ExcessWeight) :- 
-	node_events(Store, NodeId, 0, Weight, no, 0, 0, ExcessWeight).
+:- pred trace_number_of_events(wrap(S)::in, edt_node(R)::in, int::out,
+	int::out) is det <= annotated_trace(S, R).

-	% Conservatively guess the number of events in the descendents of the
-	% call corresponding to the given final event plus the number of
-	% internal body events for the call.  Also return the number of events
-	% that could be duplicated in siblings of the node in the EDT if the 
-	% node is a FAIL event.
-	%
-	% We include all the events between the final event and the last
-	% REDO before the final event, plus all the events between previous
-	% EXITs and REDOs and the initial CALL.  For EXIT events
-	% this is an over approximation, but we can't know which events
-	% will be included in descendent contours when those descendent
-	% events are in unmaterialized portions of the annotated trace.
-	%
-	% node_events(Store, Node, PrevEvents, Events, RecordDups,
-	%	DupFactor, PrevDupEvents, DupEvents)
-	% True iff Events is the (conservative approximation of) the number of
-	% descendent events of Node and DupEvents is the number of events that
-	% could be duplicated in siblings.  PrevEvents and PrevDupEvents are
+trace_number_of_events(Store, NodeId, Events, DuplicatedEvents) :- 
+	trace_weight(number_of_events, Store, NodeId, 0, Events, no, 0, 0, 
+		DuplicatedEvents).
+
+:- pred trace_subtree_suspicion(wrap(S)::in, edt_node(R)::in, int::out,
+	int::out) is det <= annotated_trace(S, R).
+
+trace_subtree_suspicion(Store, NodeId, Suspicion, Excess) :- 
+	trace_weight(suspicion, Store, NodeId, 0, Suspicion, no, 0, 0, Excess).
+
+	% trace_weight(Weighting, Store, Node, PrevWeight, Weight, RecordDups,
+	%	DupFactor, PrevDupWeight, Excess)
+	% Calculate the difference between the value of a field in an EXIT,
+	% FAIL or EXCP node and the same field in the corresponding CALL node
+	% (the field that is used depends on the value of Weighting).  If Node
+	% is a FAIL or EXCP, then sum the differences between the first
+	% CALL and the first EXIT, subsequence REDOs and EXITs and the final
+	% REDO and FAIL/EXCP.  If Node is a FAIL or EXCP then all the previous
+	% EXITS will be included in the EDT and the subtrees rooted at these
+	% EXITS will have common annotated trace nodes.  Excess is the total
+	% weight of all duplicated nodes.  PrevWeight and PrevDupWeight are
  	% accumulators which should initially be zero.  RecordDups keeps track
-	% of whether the final node was a FAIL or not - duplicates need only be
-	% recorded for FAIL nodes.  This should be `no' initially.  DupFactor
-	% keeps track of how many times the events before the last REDO could
-	% have been duplicated and should initially be zero.
+	% of whether the final node was a FAIL or EXCP. This should be `no'
+	% initially.  DupFactor keeps track of how many times the nodes before
+	% the last REDO could have been duplicated and should initially be
+	% zero.
  	%
-:- pred node_events(wrap(S)::in, edt_node(R)::in, int::in, int::out, bool::in,
-	int::in, int::in, int::out) is det <= annotated_trace(S, R).
+:- pred trace_weight(weighting_heuristic::in, wrap(S)::in, edt_node(R)::in, 
+	int::in, int::out, bool::in, int::in, int::in, int::out) 
+	is det <= annotated_trace(S, R).

-node_events(wrap(Store), dynamic(Ref), PrevEvents, Events, RecordDups,
-		DupFactor, PrevDupEvents, DupEvents) :-
+trace_weight(Weighting, wrap(Store), dynamic(Ref), PrevWeight, Weight,
+		RecordDups, DupFactor, PrevDupWeight, Excess) :-
  	det_trace_node_from_id(Store, Ref, Final),
  	(
  		(
-			Final = exit(_, CallId, RedoId, _, FinalEvent, _, _),
+			Final = exit(_, CallId, RedoId, _, FinalEvent, _, _, 
+				FinalSuspicion),
  			NewRecordDups = RecordDups
  		;
-			Final = fail(_, CallId, RedoId, FinalEvent, _),
+			Final = fail(_, CallId, RedoId, FinalEvent, _, 
+				FinalSuspicion),
  			NewRecordDups = yes
  		;
-			Final = excp(_, CallId, RedoId, _, FinalEvent, _),
+			Final = excp(_, CallId, RedoId, _, FinalEvent, _, 
+				FinalSuspicion),
  			NewRecordDups = yes
  		)
  	->
  		(
  			maybe_redo_node_from_id(Store, RedoId, Redo),
-			Redo = redo(_, ExitId, RedoEvent, _)
+			Redo = redo(_, ExitId, RedoEvent, _, RedoSuspicion)
  		->
  			(
  				NewRecordDups = yes,
-				NewPrevDupEvents = PrevDupEvents + DupFactor 
-					* (FinalEvent - RedoEvent + 1)
+				(
+					Weighting = number_of_events,
+					NewPrevDupWeight = PrevDupWeight +
+						DupFactor * (FinalEvent -
+							RedoEvent + 1)
+				;
+					Weighting = suspicion,
+					NewPrevDupWeight = PrevDupWeight +
+						DupFactor * (FinalSuspicion -
+							RedoSuspicion)
+				)
  			;
  				NewRecordDups = no,
-				NewPrevDupEvents = 0
+				NewPrevDupWeight = 0
  			),
-			node_events(wrap(Store), dynamic(ExitId), PrevEvents +
-				FinalEvent - RedoEvent + 1, Events, 
-				NewRecordDups, DupFactor + 1, 
-				NewPrevDupEvents, DupEvents)
+			(
+				Weighting = number_of_events,
+				NewPrevWeight = PrevWeight + FinalEvent 
+					- RedoEvent + 1
+			;
+				Weighting = suspicion,
+				NewPrevWeight = PrevWeight + FinalSuspicion
+					- RedoSuspicion
+			),
+			trace_weight(Weighting, wrap(Store), dynamic(ExitId),
+				NewPrevWeight, Weight, NewRecordDups, 
+				DupFactor + 1, NewPrevDupWeight, Excess)
  		;
  			call_node_from_id(Store, CallId, Call),
  			CallEvent = Call ^ call_event,
-			Events = PrevEvents + FinalEvent - CallEvent + 1,
+			CallSuspicion = Call ^ call_suspicion,
+			(
+				Weighting = number_of_events,
+				Weight = PrevWeight + FinalEvent - 
+					CallEvent + 1
+			;
+				Weighting = suspicion,
+				Weight = PrevWeight + FinalSuspicion -
+					CallSuspicion
+			),
  			(
  				NewRecordDups = yes,
-				DupEvents = PrevDupEvents + DupFactor *
-					(FinalEvent - CallEvent + 1)
+				(
+					Weighting = number_of_events,
+					Excess = PrevDupWeight + DupFactor *
+						(FinalEvent - CallEvent + 1)
+				;
+					Weighting = suspicion,
+					Excess = PrevDupWeight + DupFactor *
+						(FinalSuspicion 
+							- CallSuspicion)
+				)
  			;
  				NewRecordDups = no,
-				DupEvents = 0
+				Excess = 0
  			)
  		)
  	;
-		throw(internal_error("node_events",
-			"not a final event"))
+		throw(internal_error("trace_weight", "not a final event"))
  	).

  :- pred trace_context(wrap(S)::in, edt_node(R)::in, pair(string, int)::out,
@@ -399,11 +439,11 @@
  		:-
  	det_trace_node_from_id(Store, Ref, Final),
  	(
-		Final = exit(_, CallId, _, _, _, Label, _)
+		Final = exit(_, CallId, _, _, _, Label, _, _)
  	;
-		Final = fail(_, CallId, _, _, Label)
+		Final = fail(_, CallId, _, _, Label, _)
  	;
-		Final = excp(_, CallId, _, _, _, Label)
+		Final = excp(_, CallId, _, _, _, Label, _)
  	),
  	get_context_from_label_layout(Label, FileName, LineNo),
  	call_node_from_id(Store, CallId, Call),
@@ -445,11 +485,11 @@
  trace_node_proc_label(wrap(Store), dynamic(Ref)) = ProcLabel :-
  	det_edt_return_node_from_id(Store, Ref, Node),
  	(
-		Node = fail(_, _, _, _, Label)
+		Node = fail(_, _, _, _, Label, _)
  	;
-		Node = exit(_, _, _, _, _, Label, _)
+		Node = exit(_, _, _, _, _, Label, _, _)
  	;
-		Node = excp(_, _, _, _, _, Label)
+		Node = excp(_, _, _, _, _, Label, _)
  	),
  	ProcLayout = get_proc_layout_from_label_layout(Label),
  	ProcLabel = get_proc_label_from_layout(ProcLayout).
@@ -482,7 +522,7 @@
  	det_trace_node_from_id(Store, NodeId, Node),
  	(
  		( 
-			Node = call(_, _, _, _, _, _, _, _, _)
+			Node = call(_, _, _, _, _, _, _, _, _, _)
  		;
  			%
  			% A non-failed NEGE could be encountered when gathering
@@ -503,14 +543,14 @@
  		throw(internal_error("contour_children_2",
  			"unexpected start of contour"))
  	;
-		Node = exit(_, _, _, _, _, _, _)
+		Node = exit(_, _, _, _, _, _, _, _)
  	->
  			%
  			% Add a child for this node.
  			%
  		Ns1 = [dynamic(NodeId) | Ns0]
  	;
-		Node = fail(_, CallId, _, _, _)
+		Node = fail(_, CallId, _, _, _, _)
  	->
  			%
  			% Fail events can be reached here if there
@@ -553,7 +593,7 @@
  			%
  		stratum_children(Store, Prec, NestedStartId, Ns0, Ns1)
  	; 
-		Node = excp(_, CallId, _, _, _, _)
+		Node = excp(_, CallId, _, _, _, _, _)
  	->
  			%
  			% If the contour ends in an exception, then add this
@@ -615,7 +655,7 @@
  stratum_children_2(Store, NodeId, StartId, Ns0, Ns) :-
  	det_trace_node_from_id(Store, NodeId, Node),
  	(
-		( Node = call(_, _, _, _, _, _, _, _, _)
+		( Node = call(_, _, _, _, _, _, _, _, _, _)
  		; Node = neg(_, _, _)
  		; Node = cond(_, _, failed)
  		)
@@ -623,8 +663,8 @@
  		throw(internal_error("stratum_children_2",
  			"unexpected start of contour"))
  	;
-		( Node = fail(_, _, _, _, _)
-		; Node = excp(_, _, _, _, _, _)
+		( Node = fail(_, _, _, _, _, _)
+		; Node = excp(_, _, _, _, _, _, _)
  		)
  	->
  			%
@@ -646,7 +686,7 @@
  			%
  		stratum_children(Store, Prec, NestedStartId, Ns0, Ns1)
  	;
-		Node = exit(_, CallId, _, _, _, _, _)
+		Node = exit(_, CallId, _, _, _, _, _, _)
  	->
  			%
  			% Only include an exit node as a missing answer child
@@ -859,7 +899,7 @@
  find_chain_start(Store, Ref, ArgPos, TermPath, ChainStart) :-
  	det_edt_return_node_from_id(Store, Ref, Node),
  	(
-		Node = exit(_, CallId, _, _, _, _, _),
+		Node = exit(_, CallId, _, _, _, _, _, _),
  		ExitAtom = get_trace_exit_atom(Node),
  		call_node_from_id(Store, CallId, CallNode),
  		CallAtom = get_trace_call_atom(CallNode),
@@ -880,7 +920,7 @@
  				"unbound wrong answer term"))
  		)
  	;
-		Node = fail(_, CallId, _, _, _),
+		Node = fail(_, CallId, _, _, _, _),
  		call_node_from_id(Store, CallId, CallNode),
  		CallAtom = get_trace_call_atom(CallNode),
  		( trace_atom_subterm_is_ground(CallAtom, ArgPos, TermPath) ->
@@ -891,7 +931,7 @@
  				"unbound missing answer term"))
  		)
  	;
-		Node = excp(_, CallId, _, _, _, _),
+		Node = excp(_, CallId, _, _, _, _, _),
  		call_node_from_id(Store, CallId, CallNode),
  		CallAtom = get_trace_call_atom(CallNode),
  		%
@@ -964,7 +1004,7 @@

  step_left_to_call(Store, NodeId, ParentCallNode) :-
  	trace_node_from_id(Store, NodeId, Node),
-	( Node = call(_, _, _, _, _, _, _, _, _) ->
+	( Node = call(_, _, _, _, _, _, _, _, _, _) ->
  		ParentCallNode = Node
  	;
  		%
@@ -992,7 +1032,7 @@
  	is det <= annotated_trace(S, R).

  materialize_contour(Store, NodeId, Node, Nodes0, Nodes) :-
-	( Node = call(_, _, _, _, _, _, _, _, _) ->
+	( Node = call(_, _, _, _, _, _, _, _, _, _) ->

  		Nodes = Nodes0
  	;
@@ -1039,7 +1079,7 @@
  	final_decl_atom::out) is semidet <= annotated_trace(S, R).

  get_exit_atom(Store, _ - Exit, FinalAtom) :-
-	Exit = exit(_, _, _, _, _, _, _),
+	Exit = exit(_, _, _, _, _, _, _, _),
  	FinalAtom = exit_node_decl_atom(Store, Exit).

  :- type primitive_list_and_var(R)
@@ -1138,7 +1178,7 @@
  :- pred contour_at_end_path(assoc_list(R, trace_node(R))::in,
  	maybe(goal_path)::in) is semidet.

-contour_at_end_path([_ - call(_, _, _, _, _, _, MaybeReturnLabel, _, _)], 
+contour_at_end_path([_ - call(_, _, _, _, _, _, MaybeReturnLabel, _, _, _)],
  		yes(EndPath)) :-
  	CallPathStr = get_goal_path_from_maybe_label(MaybeReturnLabel),
  	path_from_string_det(CallPathStr, CallPath),
@@ -1316,9 +1356,9 @@
  	Contour0 = [_ - ContourHeadNode | ContourTail],
  	(
  		(
-			ContourHeadNode = exit(_, _, _, _, _, _, _)
+			ContourHeadNode = exit(_, _, _, _, _, _, _, _)
  		;
-			ContourHeadNode = fail(_, _, _, _, _)
+			ContourHeadNode = fail(_, _, _, _, _, _)
  		)
  	->
  		remove_leading_exit_fail_events(ContourTail, 
@@ -1354,7 +1394,7 @@
  	->
  		(
  			ContourHeadNode = call(_, _, _, _, _, _, 
-				MaybeReturnLabel, _, _),
+				MaybeReturnLabel, _, _, _),
  			Atom = get_trace_call_atom(ContourHeadNode),
  			CallPathStr = get_goal_path_from_maybe_label(
  				MaybeReturnLabel),
@@ -1723,20 +1763,21 @@
  edt_subtree_details(Store, dynamic(Ref), Event, SeqNo, CallPreceding) :-
  	det_edt_return_node_from_id(Store, Ref, Node),
  	(
-		Node = exit(_, Call, _, _, Event, _, _)
+		Node = exit(_, Call, _, _, Event, _, _, _)
  	;
-		Node = fail(_, Call, _, Event, _)
+		Node = fail(_, Call, _, Event, _, _)
  	;
-		Node = excp(_, Call, _, _, Event, _)
+		Node = excp(_, Call, _, _, Event, _, _)
  	),
  	call_node_from_id(Store, Call, CallNode),
  	SeqNo = CallNode ^ call_seq,
  	CallPreceding = CallNode ^ call_preceding.

  :- inst edt_return_node 
-	--->	exit(ground, ground, ground, ground, ground, ground, ground)
-	;	fail(ground, ground, ground, ground, ground)
-	;	excp(ground, ground, ground, ground, ground, ground).
+	--->	exit(ground, ground, ground, ground, ground, ground, ground,
+			ground)
+	;	fail(ground, ground, ground, ground, ground, ground)
+	;	excp(ground, ground, ground, ground, ground, ground, ground).

  :- pred det_edt_return_node_from_id(S::in, R::in,
  	trace_node(R)::out(edt_return_node)) is det <= annotated_trace(S, R).
@@ -1745,11 +1786,11 @@
  	(
  		trace_node_from_id(Store, Ref, Node0),
  		(
-			Node0 = exit(_, _, _, _, _, _, _)
+			Node0 = exit(_, _, _, _, _, _, _, _)
  		;
-			Node0 = fail(_, _, _, _, _)
+			Node0 = fail(_, _, _, _, _, _)
  		;
-			Node0 = excp(_, _, _, _, _, _)
+			Node0 = excp(_, _, _, _, _, _, _)
  		)
  	->
  		Node = Node0
@@ -1765,11 +1806,11 @@
  	(
  		trace_node_from_id(Store, Ref, Node0),
  		(
-			Node0 = exit(_, CallId0, _, _, _, _, _)
+			Node0 = exit(_, CallId0, _, _, _, _, _, _)
  		;
-			Node0 = fail(_, CallId0, _, _, _)
+			Node0 = fail(_, CallId0, _, _, _, _)
  		;
-			Node0 = excp(_, CallId0, _, _, _, _)
+			Node0 = excp(_, CallId0, _, _, _, _, _)
  		)
  	->
  		CallId = CallId0
Index: browser/declarative_user.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/declarative_user.m,v
retrieving revision 1.50
diff -u -r1.50 declarative_user.m
--- browser/declarative_user.m	28 Jul 2005 06:44:07 -0000	1.50
+++ browser/declarative_user.m	4 Aug 2005 16:26:30 -0000
@@ -83,6 +83,7 @@
  :- import_module mdb.parse.
  :- import_module mdb.term_rep.
  :- import_module mdb.util.
+:- import_module mdbcomp.label_layout.
  :- import_module mdbcomp.prim_data.
  :- import_module mdbcomp.program_representation.

Index: browser/util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/util.m,v
retrieving revision 1.29
diff -u -r1.29 util.m
--- browser/util.m	11 Jul 2005 07:30:21 -0000	1.29
+++ browser/util.m	4 Aug 2005 15:55:59 -0000
@@ -18,11 +18,6 @@
  :- func util__is_predicate(pred_or_func) = bool.
  :- func util__is_function(pred_or_func) = bool.

-% This is similar to the type goal_path defined in the module
-% compiler/hlds_goal.m.
-
-:- type goal_path_string == string.
-
  :- type line_number == int.

  	% Get user input via the same method used by the internal
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.448
diff -u -r1.448 user_guide.texi
--- doc/user_guide.texi	1 Aug 2005 02:40:05 -0000	1.448
+++ doc/user_guide.texi	4 Aug 2005 13:48:18 -0000
@@ -3351,7 +3351,7 @@
  @ref{Declarative debugging} for details.
  @sp 1
  @table @code
- at item dd [-r] [-n at var{nodes}] [-s at var{search-mode}]
+ at item dd [-r] [-n at var{nodes}] [-s at var{search-mode}] [-p at var{passfile}] [-f at var{failfile}]
  @c @item dd [--assume-all-io-is-tabled] [-d at var{depth}]
  @c The --assume-all-io-is-tabled option is for developers only. Specifying it
  @c makes an assertion, and if the assertion is incorrect, the resulting
@@ -3376,10 +3376,10 @@
  @sp 1
  The @samp{-s at var{search-mode}} or @samp{--search-mode @var{search-mode}}
  option tells the declarative debugger which 
-search mode to use.  Either @samp{top_down} or @samp{divide_and_query}
-may be specified.  See @ref{Search Modes} for a more detailed description of
-the available search modes.  @samp{top_down} is the default when this option is
-not given.
+search mode to use.  Valid search modes are @samp{top_down} (or @samp{td}), 
+ at samp{divide_and_query} (or @samp{dq}) and @samp{suspicion_divide_and_query}
+(or @samp{sdq}).
+ at samp{top_down} is the default when this option is not given.
  @sp 1
  Use the @samp{-r} or @samp{--resume} option to continue your previous
  declarative debugging session.  If the @samp{--resume} option is given and
@@ -3389,6 +3389,18 @@
  to change the search mode of a previously started declarative debugging
  session.
  @sp 1
+The arguments supplied to the @samp{--pass-trace-counts} (or @samp{-p}) and 
+ at samp{--fail-trace-counts} (or @samp{-f}) options are either trace count
+files or files containing a list of trace count files.
+The supplied trace counts are used to assign
+a suspicion to each event based on which parts of program were executed in
+the failing test case(s), but not the passing test case(s). 
+This is used to guide the declarative debugger when
+the suspicion-divide-and-query search mode is used.  If the 
+suspicion-divide-and-query search mode is specified then either both the
+ at samp{-p} and @samp{-f} options must be given, or the @samp{fail_trace_counts}
+and @samp{pass_trace_counts} configuration parameters must be set (using
+the @samp{set} command).
  @item trust @var{module-name}|@var{proc-spec}
  @kindex trust (mdb command)
  Tells the declarative debugger to trust the given module, predicate or
@@ -3573,12 +3585,12 @@
  @kindex lines (mdb command)
  @kindex xml_browser_cmd (mdb command)
  @kindex xml_tmp_filename (mdb command)
- at kindex fail_trace_count (mdb command)
+ at kindex fail_trace_counts (mdb command)
  @kindex pass_trace_counts (mdb command)
  Updates the given configuration parameter.
  The parameters that can be configured are
  @samp{format}, @samp{depth}, @samp{size}, @samp{width}, @samp{lines}, 
- at samp{xml_browser_cmd}, @samp{xml_tmp_filename}, @samp{fail_trace_count},
+ at samp{xml_browser_cmd}, @samp{xml_tmp_filename}, @samp{fail_trace_counts},
  @samp{pass_trace_counts}.
  @sp 1
  @itemize @bullet
@@ -4280,7 +4292,7 @@
  @node Search Modes
  @subsection Search Modes

-Currently the declarative debugger can operate in one of two modes when
+Currently the declarative debugger can operate in one of three modes when
  searching for a bug.  The mode to use can be specified as an option to the
  @samp{dd} command.  See @ref{Declarative debugging mdb commands} for
  information on how to do this.
@@ -4298,8 +4310,8 @@

  @subsubsection Divide and Query Search

-With this search mode the declarative debugger will attempt to halve the size of
-the search space with each question.  In many cases this will result in the 
+With this search mode the declarative debugger will attempt to halve the size
+of the search space with each question.  In many cases this will result in the
  bug being found after O(log(N)) questions where N is the number of events
  between the event where the @samp{dd} command was given and the corresponding
  @samp{CALL} event.  This makes the search feasible for deeply recursive runs
@@ -4307,6 +4319,15 @@
  to be answered.  However, the questions may appear to come from unrelated parts
  of the program which can make them harder to answer.

+ at subsubsection Suspicion Divide and Query Search
+
+In this search mode the declarative debugger assigns a suspicion level to
+each event based on which parts of the program were executed in failing
+test cases, but not in passing test cases.  It then attempts to divide the
+search space into two areas of equal suspicion with each question.  This tends
+to result in questions about parts of the program executed in a failing test
+case, but not in passing test cases.
+
  @subsubsection When different search modes are used

  If a search mode is given when invoking the declarative debugger then that
@@ -4317,7 +4338,7 @@
  one question.

  If you do not specify a search mode when giving the @samp{dd} command then the
-behaviour depends on wether the @samp{--resume} option is present.  If it is
+behaviour depends on whether the @samp{--resume} option is present.  If it is
  then the previous search mode will be used, otherwise top-down search will
  be used.

Index: mdbcomp/label_layout.m
===================================================================
RCS file: mdbcomp/label_layout.m
diff -N mdbcomp/label_layout.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mdbcomp/label_layout.m	4 Aug 2005 17:01:30 -0000
@@ -0,0 +1,282 @@
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2005 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+%
+% File: label_layout.m.
+% Main authors: zs, maclarty
+%
+% This module contains an interface to the label_layout and proc_layout
+% types which are used in the C backend of the debugger.
+
+:- module mdbcomp.label_layout.
+
+:- interface.
+
+:- import_module list.
+:- import_module std_util.
+
+:- import_module mdbcomp.prim_data.
+:- import_module mdbcomp.program_representation.
+:- import_module mdbcomp.trace_counts.
+
+:- type label_layout.
+
+:- func get_proc_layout_from_label_layout(label_layout) = proc_layout.
+
+:- func get_goal_path_from_label_layout(label_layout) = goal_path_string.
+
+:- func get_goal_path_from_maybe_label(maybe(label_layout)) = goal_path_string.
+
+:- func get_port_from_label_layout(label_layout) = trace_port.
+
+:- func get_path_port_from_label_layout(label_layout) = path_port.
+
+:- pred get_context_from_label_layout(label_layout::in, string::out, int::out)
+	is semidet.
+
+:- type proc_layout. 
+
+:- func get_proc_label_from_layout(proc_layout) = proc_label.
+
+:- func get_proc_name(proc_label) = string.
+
+:- func get_all_modes_for_layout(proc_layout) = list(proc_layout).
+
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module require.
+:- import_module string.
+
+:- pragma foreign_type("C", label_layout, "const MR_Label_Layout *",
+	[can_pass_as_mercury_type, stable]).
+
+	% stub only
+:- pragma foreign_type("Java", label_layout, "java.lang.Object", []). 
+
+:- pragma foreign_proc("C",
+	get_proc_layout_from_label_layout(Label::in) = (ProcLayout::out),
+	[will_not_call_mercury, thread_safe, promise_pure],
+"
+	ProcLayout = Label->MR_sll_entry;
+").
+
+:- pragma foreign_proc("C",
+	get_goal_path_from_label_layout(Label::in) = (GoalPath::out),
+	[will_not_call_mercury, thread_safe, promise_pure],
+"
+	GoalPath = (MR_String)MR_label_goal_path(Label);
+").
+
+get_goal_path_from_maybe_label(yes(Label)) 
+	= get_goal_path_from_label_layout(Label).
+get_goal_path_from_maybe_label(no) = "".
+
+:- pragma foreign_proc("C",
+	get_context_from_label_layout(Label::in, FileName::out, LineNo::out), 
+	[will_not_call_mercury, thread_safe, promise_pure],
+"
+	const char	*filename;
+ 
+	SUCCESS_INDICATOR = MR_find_context(Label, &filename, &LineNo);
+	MR_TRACE_USE_HP(
+		MR_make_aligned_string(FileName, (MR_String) filename);
+	);
+").
+
+:- pragma foreign_proc("C",
+	get_port_from_label_layout(Label::in) = (Port::out), 
+	[will_not_call_mercury, thread_safe, promise_pure],
+"
+	Port = Label->MR_sll_port;
+").
+
+get_path_port_from_label_layout(Label) = PathPort :-
+	Port = get_port_from_label_layout(Label),
+	GoalPathStr = get_goal_path_from_label_layout(Label),
+	( if path_from_string(GoalPathStr, ValidGoalPath) then
+		GoalPath = ValidGoalPath
+	else
+		error("get_path_port_from_label_layout: invalid goal path")
+	),
+	PathPort = make_path_port(GoalPath, Port).
+
+:- pragma foreign_type("C", proc_layout, "const MR_Proc_Layout *",
+	[can_pass_as_mercury_type, stable]).
+:- pragma foreign_type("Java", proc_layout, "java.lang.Object", []). %stub only
+
+get_proc_label_from_layout(Layout) = ProcLabel :-
+	( proc_layout_is_uci(Layout) ->
+		proc_layout_get_uci_fields(Layout, TypeName, TypeModule,
+			DefModule, PredName, TypeArity, ModeNum),
+		( PredName = "__Unify__" ->
+			SpecialId = unify
+		; PredName = "__Index__" ->
+			SpecialId = index
+		; PredName = "__Compare__" ->
+			SpecialId = compare
+		;
+			error("get_proc_label_from_layout: " ++ 
+				"bad special_pred_id")
+		),
+		string_to_sym_name(DefModule, ".", SymDefModule),
+		string_to_sym_name(TypeModule, ".", SymTypeModule),
+		ProcLabel = special_proc(SymDefModule, SpecialId, 
+			SymTypeModule, TypeName, TypeArity, ModeNum)
+	;
+		proc_layout_get_non_uci_fields(Layout, PredOrFunc,
+			DeclModule, DefModule, PredName, Arity, ModeNum),
+		string_to_sym_name(DefModule, ".", SymDefModule),
+		string_to_sym_name(DeclModule, ".", SymDeclModule),
+		ProcLabel = proc(SymDefModule, PredOrFunc, SymDeclModule, 
+			PredName, Arity, ModeNum)
+	).
+
+get_proc_name(proc(_, _, _, ProcName, _, _)) = ProcName.
+get_proc_name(special_proc(_, _, _, ProcName , _, _)) = ProcName. 
+
+:- pred proc_layout_is_uci(proc_layout::in) is semidet.
+
+:- pragma foreign_proc("C",
+	proc_layout_is_uci(Layout::in),
+	[will_not_call_mercury, thread_safe, promise_pure],
+"
+	if (MR_PROC_ID_IS_UCI(Layout->MR_sle_proc_id)) {
+		SUCCESS_INDICATOR = MR_TRUE;
+	} else {
+		SUCCESS_INDICATOR = MR_FALSE;
+	}
+").
+
+:- pred proc_layout_get_uci_fields(proc_layout::in, string::out,
+	string::out, string::out, string::out, int::out, int::out) is det.
+
+:- pragma foreign_proc("C",
+	proc_layout_get_uci_fields(Layout::in, TypeName::out, TypeModule::out,
+		DefModule::out, PredName::out, TypeArity::out, ModeNum::out),
+	[will_not_call_mercury, thread_safe, promise_pure],
+"
+	const MR_UCI_Proc_Id	*proc_id;
+
+	proc_id = &Layout->MR_sle_uci;
+
+	/* The casts are there to cast away const without warnings */
+	TypeName   = (MR_String) (MR_Integer) proc_id->MR_uci_type_name;
+	TypeModule = (MR_String) (MR_Integer) proc_id->MR_uci_type_module;
+	DefModule  = (MR_String) (MR_Integer) proc_id->MR_uci_def_module;
+	PredName   = (MR_String) (MR_Integer) proc_id->MR_uci_pred_name;
+	TypeArity  = proc_id->MR_uci_type_arity;
+	ModeNum    = proc_id->MR_uci_mode;
+").
+
+:- pred proc_layout_get_non_uci_fields(proc_layout::in, pred_or_func::out,
+	string::out, string::out, string::out, int::out, int::out) is det.
+
+:- pragma foreign_proc("C",
+	proc_layout_get_non_uci_fields(Layout::in, PredOrFunc::out,
+		DeclModule::out, DefModule::out, PredName::out,
+		Arity::out, ModeNum::out),
+	[will_not_call_mercury, thread_safe, promise_pure],
+"
+	const MR_User_Proc_Id	*proc_id;
+
+	proc_id = &Layout->MR_sle_user;
+
+	/* The casts are there to cast away const without warnings */
+	PredOrFunc = proc_id->MR_user_pred_or_func;
+	DeclModule = (MR_String) (MR_Integer) proc_id->MR_user_decl_module;
+	DefModule  = (MR_String) (MR_Integer) proc_id->MR_user_def_module;
+	PredName   = (MR_String) (MR_Integer) proc_id->MR_user_name;
+	Arity      = proc_id->MR_user_arity;
+	ModeNum    = proc_id->MR_user_mode;
+").
+
+:- pragma foreign_proc("C",
+	get_all_modes_for_layout(Layout::in) = (Layouts::out),
+	[will_not_call_mercury, thread_safe, promise_pure],
+"
+	const MR_Module_Layout	*module;
+	const MR_Proc_Layout	*proc;
+	int			i;
+	MR_Word			list;
+	MR_bool			match;
+	const MR_Proc_Layout	*selected_proc;
+
+	selected_proc = Layout;
+
+	if (! MR_PROC_LAYOUT_HAS_EXEC_TRACE(selected_proc)) {
+		MR_fatal_error(
+			""get_all_modes_for_layout: selected_proc"");
+	}
+
+	module = selected_proc->MR_sle_module_layout;
+	list = MR_list_empty();
+	for (i = 0; i < module->MR_ml_proc_count; i++) {
+		proc = module->MR_ml_procs[i];
+		if (! MR_PROC_LAYOUT_HAS_EXEC_TRACE(selected_proc)) {
+			MR_fatal_error(
+				""get_all_modes_for_layout: proc"");
+		}
+
+		if (MR_PROC_LAYOUT_IS_UCI(selected_proc)
+			&& MR_PROC_LAYOUT_IS_UCI(proc))
+		{
+			const MR_UCI_Proc_Id	*proc_id;
+			const MR_UCI_Proc_Id	*selected_proc_id;
+
+			proc_id = &proc->MR_sle_uci;
+			selected_proc_id = &selected_proc->MR_sle_uci;
+
+			if (MR_streq(proc_id->MR_uci_type_name,
+				selected_proc_id->MR_uci_type_name)
+			&& MR_streq(proc_id->MR_uci_type_module,
+				selected_proc_id->MR_uci_type_module)
+			&& MR_streq(proc_id->MR_uci_pred_name,
+				selected_proc_id->MR_uci_pred_name)
+			&& (proc_id->MR_uci_type_arity ==
+				selected_proc_id->MR_uci_type_arity))
+			{
+				match = MR_TRUE;
+			} else {
+				match = MR_FALSE;
+			}
+		} else if (!MR_PROC_LAYOUT_IS_UCI(selected_proc)
+			&& !MR_PROC_LAYOUT_IS_UCI(proc))
+		{
+			const MR_User_Proc_Id	*proc_id;
+			const MR_User_Proc_Id	*selected_proc_id;
+
+			proc_id = &proc->MR_sle_user;
+			selected_proc_id = &selected_proc->MR_sle_user;
+
+			if ((proc_id->MR_user_pred_or_func ==
+				selected_proc_id->MR_user_pred_or_func)
+			&& MR_streq(proc_id->MR_user_decl_module,
+				selected_proc_id->MR_user_decl_module)
+			&& MR_streq(proc_id->MR_user_name,
+				selected_proc_id->MR_user_name)
+			&& (proc_id->MR_user_arity ==
+				selected_proc_id->MR_user_arity))
+			{
+				match = MR_TRUE;
+			} else {
+				match = MR_FALSE;
+			}
+		} else {
+			match = MR_FALSE;
+		}
+
+		if (match) {
+			list = MR_int_list_cons((MR_Integer) proc, list);
+		}
+	}
+
+	Layouts = list;
+	").
+
+%-----------------------------------------------------------------------------%
+:- end_module mdbcomp.label_layout.
+%-----------------------------------------------------------------------------%
Index: mdbcomp/mdbcomp.m
===================================================================
RCS file: /home/mercury1/repository/mercury/mdbcomp/mdbcomp.m,v
retrieving revision 1.2
diff -u -r1.2 mdbcomp.m
--- mdbcomp/mdbcomp.m	29 Apr 2005 01:03:14 -0000	1.2
+++ mdbcomp/mdbcomp.m	4 Aug 2005 15:58:27 -0000
@@ -20,6 +20,7 @@

  :- pred mdbcomp__version(string::out) is det.

+:- include_module label_layout.
  :- include_module prim_data.
  :- include_module program_representation.
  :- include_module slice_and_dice.
Index: mdbcomp/program_representation.m
===================================================================
RCS file: /home/mercury1/repository/mercury/mdbcomp/program_representation.m,v
retrieving revision 1.6
diff -u -r1.6 program_representation.m
--- mdbcomp/program_representation.m	14 Jun 2005 08:15:05 -0000	1.6
+++ mdbcomp/program_representation.m	4 Aug 2005 17:31:32 -0000
@@ -175,6 +175,11 @@

  :- type goal_path == list(goal_path_step).

+% This is similar to the type goal_path defined in the module
+% compiler/hlds_goal.m.
+
+:- type goal_path_string == string.
+
  :- type goal_path_step  --->    conj(int)
                          ;       disj(int)
                          ;       switch(int)
Index: mdbcomp/slice_and_dice.m
===================================================================
RCS file: /home/mercury1/repository/mercury/mdbcomp/slice_and_dice.m,v
retrieving revision 1.1
diff -u -r1.1 slice_and_dice.m
--- mdbcomp/slice_and_dice.m	29 Apr 2005 01:03:14 -0000	1.1
+++ mdbcomp/slice_and_dice.m	4 Aug 2005 17:38:22 -0000
@@ -124,6 +124,12 @@
  :- pred read_dice(slice_source::in, string::in, slice_source::in, string::in,
      maybe_error(dice)::out, io::di, io::uo) is det.

+    % Same as read_dice/7, but with PassSource and FailSource both 
+    % try_single_first.
+    %
+:- pred read_dice_try_single_first(string::in, string::in,
+    maybe_error(dice)::out, io::di, io::uo) is det.
+
      % read_dice_to_string(PassFile, FailFile, SortStr, N, Module, DiceStr,
      %   Problem, !IO):
      %
@@ -150,10 +156,33 @@
  :- pred read_dice_to_string(string::in, string::in, string::in, int::in,
      string::in, string::out, string::out, io::di, io::uo) is det.

+    % suspicion_ratio(PassCount, FailCount) = Suspicion.
+    % suspicion_ratio gives an indication of how likely a label is to
+    % be buggy based on how many times it was executed in passing and
+    % failing test runs.
+    %
+:- func suspicion_ratio(int, int) = float.
+
+    % suspicion_ratio_normalised(PassCount, PassTests, FailCount, FailTests) 
+    %   = Suspicion.
+    % suspicion_ratio_normalised gives an indication of how likely a label is
+    % to be buggy based on how many times it was executed in passing and
+    % failing test runs and on how many passing and failing test runs there
+    % were.
+    %
+:- func suspicion_ratio_normalised(int, int, int, int) = float.
+
+    % suspicion_ratio_binary(PassCount, FailCount) = Suspicion.
+    % suspicion_ration_binary returns 1 if PassCount is 0 and FailCount is
+    % > 0 and 0 otherwise.
+    %
+:- func suspicion_ratio_binary(int, int) = float.
+
  %-----------------------------------------------------------------------------%

  :- implementation.

+:- import_module mdbcomp.label_layout.
  :- import_module mdbcomp.program_representation.

  :- import_module assoc_list.
@@ -266,6 +295,31 @@
          Result = error(Problem)
      ).

+:- pragma export(read_dice_try_single_first(in, in, out, di, uo),
+    "MR_MDB_read_dice_try_single_first").
+
+read_dice_try_single_first(PassFile, FailFile, Result, !IO) :-
+    read_dice(try_single_first, PassFile, try_single_first, FailFile, Result,
+        !IO).
+
+:- pred maybe_dice_error_to_problem_string(maybe_error(dice)::in, string::out) 
+	is det.
+
+:- pragma export(maybe_dice_error_to_problem_string(in, out),
+	"MR_DD_maybe_dice_error_to_problem_string").
+
+maybe_dice_error_to_problem_string(ok(_), "").
+maybe_dice_error_to_problem_string(error(ErrorStr), ErrorStr).
+
+:- pred det_maybe_dice_error_to_dice(maybe_error(dice)::in, dice::out) is det.
+
+:- pragma export(det_maybe_dice_error_to_dice(in, out),
+	"MR_DD_det_maybe_dice_error_to_dice").
+
+det_maybe_dice_error_to_dice(ok(Dice), Dice).
+det_maybe_dice_error_to_dice(error(_), _) :- 
+	error("det_maybe_dice_error_to_dice: result is error").
+
  :- type trace_counts_kind
      --->    pass
      ;       fail.
@@ -714,16 +768,61 @@
      ++ string.pad_left(int_to_string(FailCount), ' ', 12)
      ++ string.pad_left("(" ++ int_to_string(FailTests) ++ ")", ' ', 8).

-    % suspicion_ratio gives an indication of how likely a label is to
-    % be buggy based on how many times it was executed in passing and
-    % failing test runs.
-    %
-:- func suspicion_ratio(int, int) = float.
+suspicion_ratio(PassCount, FailCount) = R1 :-
+    Denominator = PassCount + FailCount,
+    (
+        Denominator \= 0
+    ->
+        R = float(FailCount) / float(Denominator),
+        ( R >= 0.20 ->
+            R1 = R
+          ; R1 = 0.0
+        )
+    ;
+        % The denominator could be zero if user_all trace counts were
+        % provided.
+        R1 = 0.0
+    ).
+
+suspicion_ratio_normalised(PassCount, PassTests, FailCount, FailTests) = R :-
+    ( FailCount = 0 ->
+        R = 0.0
+    ;
+        ( PassTests = 0 ->
+            PassNorm = 0.0
+        ; 
+            PassNorm = float(PassCount) / float(PassTests)
+        ),
+        FailNorm = float(FailCount) / float(FailTests),
+        R = float.max(FailNorm - PassNorm, 0.0) / FailNorm
+    ).

-suspicion_ratio(PassCount, FailCount) =
-    % PassCount + FailCount should never be zero since if a label
-    % isn't executed in any tests then it wouldn't be included in the dice.
-    float(FailCount) / float(PassCount + FailCount).
+suspicion_ratio_binary(PassCount, FailCount) = R :-
+    ( FailCount > 0, PassCount = 0 ->
+        R = 1.0
+    ;
+        R = 0.0
+    ).
+
+:- func get_suspicion_for_label_layout(dice, label_layout) = float.
+
+:- pragma export(get_suspicion_for_label_layout(in, in) = out,
+	"MR_DD_get_suspicion_for_label_layout").
+
+get_suspicion_for_label_layout(Dice, LabelLayout) = Suspicion :-
+	ProcLayout = get_proc_layout_from_label_layout(LabelLayout),
+	ProcLabel = get_proc_label_from_layout(ProcLayout),
+	PathPort = get_path_port_from_label_layout(LabelLayout),
+	( map.search(Dice ^ dice_proc_map, ProcLabel, PathPortMap) ->
+		( map.search(PathPortMap, PathPort, ExecCount) ->
+			Suspicion = suspicion_ratio_binary(
+			      ExecCount ^ pass_count, ExecCount ^ fail_count)
+		;
+			Suspicion = 0.0
+		)
+	;
+		Suspicion = 0.0
+	).

  %-----------------------------------------------------------------------------%
  %
Index: mdbcomp/trace_counts.m
===================================================================
RCS file: /home/mercury1/repository/mercury/mdbcomp/trace_counts.m,v
retrieving revision 1.5
diff -u -r1.5 trace_counts.m
--- mdbcomp/trace_counts.m	29 Apr 2005 01:03:15 -0000	1.5
+++ mdbcomp/trace_counts.m	4 Aug 2005 17:49:32 -0000
@@ -37,7 +37,7 @@
              % The file contains counts for all labels from user-defined
              % procedures, provided the count is nonzero.

-:- type trace_counts        == map(proc_label, proc_trace_counts).
+:- type trace_counts == map(proc_label, proc_trace_counts).

  :- type proc_trace_counts   == map(path_port, context_and_count).

@@ -53,6 +53,8 @@
                  exec_count  :: int
              ).

+:- func make_path_port(goal_path, trace_port) = path_port.
+
  :- pred summarize_trace_counts_list(list(trace_counts)::in, trace_counts::out)
      is det.

@@ -327,13 +329,8 @@
      io__read_line_as_string(IdResult, !IO),
      (
          IdResult = ok(IdStr),
-        (
-            IdStr = "user_all\n",
-            FileType = user_all
-        ;
-            IdStr = "user_nonzero\n",
-            FileType = user_nonzero
-        )
+        string.append(IdStrNoNL, "\n", IdStr),
+        file_type_string(FileType, IdStrNoNL)
      ->
          try_io(read_trace_counts_setup(map__init), Result, !IO),
          (
@@ -349,7 +346,7 @@
                  ReadResult = syntax_error(Error)
              ;
                  error("read_trace_counts_from_cur_stream: " ++
-                    "unexpected exception type")
+                    "unexpected exception type: " ++ string(Exception))
              )
          ;
              Result = failed,
@@ -523,6 +520,34 @@
      string__substring(String, 1, Length-2, SubString),
      path_from_string(SubString, Path).

+    % This function should be kept in sync with the MR_named_count_port array
+    % in runtime/mercury_trace_base.c.
+    %
+make_path_port(_GoalPath, call) = port_only(call).
+make_path_port(_GoalPath, exit) = port_only(exit).
+make_path_port(_GoalPath, redo) = port_only(redo).
+make_path_port(_GoalPath, fail) = port_only(fail).
+make_path_port(_GoalPath, exception) = port_only(exception).
+make_path_port(GoalPath, ite_cond) = path_only(GoalPath).
+make_path_port(GoalPath, ite_then) = path_only(GoalPath).
+make_path_port(GoalPath, ite_else) = path_only(GoalPath).
+make_path_port(GoalPath, neg_enter) = port_and_path(neg_enter, GoalPath).
+make_path_port(GoalPath, neg_success) = port_and_path(neg_success, GoalPath).
+make_path_port(GoalPath, neg_failure) = port_and_path(neg_failure, GoalPath).
+make_path_port(GoalPath, disj) = path_only(GoalPath).
+make_path_port(GoalPath, switch) = path_only(GoalPath).
+make_path_port(GoalPath, nondet_pragma_first) = path_only(GoalPath).
+make_path_port(GoalPath, nondet_pragma_later) = path_only(GoalPath).
+
+%-----------------------------------------------------------------------------%
+
+:- pred file_type_string(trace_count_file_type, string).
+:- mode file_type_string(in, out) is det.
+:- mode file_type_string(out, in) is semidet.
+
+file_type_string(user_all, "user_all").
+file_type_string(user_nonzero, "user_nonzero").
+
  %-----------------------------------------------------------------------------%

  restrict_trace_counts_to_module(ModuleName, TraceCounts0, TraceCounts) :-
Index: runtime/mercury_stack_layout.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stack_layout.h,v
retrieving revision 1.91
diff -u -r1.91 mercury_stack_layout.h
--- runtime/mercury_stack_layout.h	21 Jun 2005 03:12:03 -0000	1.91
+++ runtime/mercury_stack_layout.h	4 Aug 2005 09:28:42 -0000
@@ -1167,7 +1167,7 @@
  ** The MR_ml_label_exec_count field points to an array of integers, with each
  ** integer holding the number of times execution has reached a given label.
  ** Each label's layout structure records the index of that label in this array.
-** To most direct way to go the other way, to find out which label owns a
+** The most direct way to go the other way, to find out which label owns a
  ** particular slot in this array, is to search the label arrays in the file
  ** layout structures, and test their MR_sll_label_num_in_module fields.
  ** (If we needed faster access, we could add another array with elements
Index: runtime/mercury_trace_base.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trace_base.c,v
retrieving revision 1.69
diff -u -r1.69 mercury_trace_base.c
--- runtime/mercury_trace_base.c	2 Aug 2005 03:35:47 -0000	1.69
+++ runtime/mercury_trace_base.c	4 Aug 2005 09:28:42 -0000
@@ -164,26 +164,19 @@
  MR_Code *
  MR_trace_count(const MR_Label_Layout *label_layout)
  {
-    const MR_Module_Layout  *module_layout;
-    const MR_Proc_Layout    *proc_layout;
-    MR_uint_least16_t       label_number;
-
-    proc_layout = label_layout->MR_sll_entry;
-    if (! MR_PROC_LAYOUT_HAS_EXEC_TRACE(proc_layout)) {
-        MR_fatal_error("MR_trace_count: no exec trace");
-    }
-
-    module_layout = proc_layout->MR_sle_module_layout;
-    label_number = label_layout->MR_sll_label_num_in_module;
-    if (label_number >= module_layout->MR_ml_num_label_exec_counts) {
-        MR_fatal_error("MR_trace_count: invalid label number");
-    }
+    MR_Unsigned     *exec_count;

+    exec_count = MR_trace_lookup_trace_count(label_layout);
+
  #ifdef  MR_TRACE_COUNT_DEBUG
      {
          const MR_Label_Layout   *call_label_layout;
          MR_uint_least16_t       call_label_number;
+        const MR_Module_Layout  *module_layout;
+        const MR_Proc_Layout    *proc_layout;

+        proc_layout = label_layout->MR_sll_entry;
+        module_layout = proc_layout->MR_sle_module_layout;
          call_label_layout = proc_layout->MR_sle_call_label;
          if (label_layout != call_label_layout) {
              /*
@@ -206,10 +199,31 @@
      }
  #endif

-    ++module_layout->MR_ml_label_exec_count[label_number];
+    *exec_count += 1;
      return NULL;
  }

+MR_Unsigned *
+MR_trace_lookup_trace_count(const MR_Label_Layout *label_layout)
+{
+    const MR_Module_Layout  *module_layout;
+    const MR_Proc_Layout    *proc_layout;
+    MR_uint_least16_t       label_number;
+
+    proc_layout = label_layout->MR_sll_entry;
+    if (! MR_PROC_LAYOUT_HAS_EXEC_TRACE(proc_layout)) {
+        MR_fatal_error("MR_trace_lookup_trace_count: no exec trace");
+    }
+
+    module_layout = proc_layout->MR_sle_module_layout;
+    label_number = label_layout->MR_sll_label_num_in_module;
+    if (label_number >= module_layout->MR_ml_num_label_exec_counts) {
+        MR_fatal_error("MR_trace_lookup_trace_count: invalid label number");
+    }
+
+    return &(module_layout->MR_ml_label_exec_count[label_number]);
+}
+
  #define INIT_MODULE_TABLE_SIZE  10

  const MR_Module_Layout  **MR_module_infos;
@@ -229,15 +243,11 @@
      MR_module_infos[slot] = module;
  }

-typedef enum {
-    PATH_ONLY, PORT_ONLY, PORT_AND_PATH
-} MR_PathPort;
-
-static MR_PathPort MR_named_count_port[MR_PORT_NONE + 1];
-
  static  void    MR_trace_write_quoted_atom(FILE *fp, const char *atom);
  static  void    MR_trace_write_label_exec_counts(FILE *fp);

+MR_PathPort     MR_named_count_port[MR_PORT_NONE + 1];
+
  #define MERCURY_TRACE_COUNTS_PREFIX  "mercury_trace_counts"

  void
@@ -297,18 +307,7 @@
      MR_Unsigned                 exec_count;
      MR_PathPort                 path_port;

-    for (port = MR_PORT_CALL; port <= MR_PORT_NONE; port++) {
-        MR_named_count_port[port] = PATH_ONLY;
-    }
-
-    MR_named_count_port[MR_PORT_CALL] = PORT_ONLY;
-    MR_named_count_port[MR_PORT_EXIT] = PORT_ONLY;
-    MR_named_count_port[MR_PORT_REDO] = PORT_ONLY;
-    MR_named_count_port[MR_PORT_FAIL] = PORT_ONLY;
-
-    MR_named_count_port[MR_PORT_NEG_ENTER] = PORT_AND_PATH;
-    MR_named_count_port[MR_PORT_NEG_SUCCESS] = PORT_AND_PATH;
-    MR_named_count_port[MR_PORT_NEG_FAILURE] = PORT_AND_PATH;
+    MR_trace_name_count_port_ensure_init();

      fprintf(fp, "%s", MR_TRACE_COUNT_FILE_ID);
      if (MR_coverage_test_enabled) {
@@ -388,6 +387,31 @@
      }
  }

+void
+MR_trace_name_count_port_ensure_init()
+{
+    static MR_bool  done = MR_FALSE;
+ 
+    if (! done) {
+        MR_Trace_Port   port;
+
+        for (port = MR_PORT_CALL; port <= MR_PORT_NONE; port++) {
+            MR_named_count_port[port] = PATH_ONLY;
+        }
+
+        MR_named_count_port[MR_PORT_CALL] = PORT_ONLY;
+        MR_named_count_port[MR_PORT_EXIT] = PORT_ONLY;
+        MR_named_count_port[MR_PORT_REDO] = PORT_ONLY;
+        MR_named_count_port[MR_PORT_FAIL] = PORT_ONLY;
+
+        MR_named_count_port[MR_PORT_NEG_ENTER] = PORT_AND_PATH;
+        MR_named_count_port[MR_PORT_NEG_SUCCESS] = PORT_AND_PATH;
+        MR_named_count_port[MR_PORT_NEG_FAILURE] = PORT_AND_PATH;
+ 
+        done = MR_TRUE;
+    }
+}
+
  /*
  ** The output of this is supposed to be equivalent to term_io__quote_atom
  ** except that it always uses quotes, even if not strictly necessary.
Index: runtime/mercury_trace_base.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trace_base.h,v
retrieving revision 1.49
diff -u -r1.49 mercury_trace_base.h
--- runtime/mercury_trace_base.h	1 Aug 2005 02:40:09 -0000	1.49
+++ runtime/mercury_trace_base.h	4 Aug 2005 09:28:43 -0000
@@ -49,6 +49,20 @@
  	MR_PORT_NONE
  } MR_Trace_Port;

+/*
+** The following array says if a label inside a procedure is 
+** uniquely identifiable by its goal path only, its port only or
+** whether both the port and goal path are necessary.
+*/
+
+typedef enum {
+    PATH_ONLY, PORT_ONLY, PORT_AND_PATH
+} MR_PathPort;
+
+extern	MR_PathPort     MR_named_count_port[MR_PORT_NONE + 1];
+
+extern	void		MR_trace_name_count_port_ensure_init(void);
+
  #define	MR_PORT_NUM_PORTS		((int) MR_PORT_NONE + 1)

  extern	const char 			*MR_port_names[];
@@ -459,6 +473,13 @@
  extern	MR_Word	MR_trace_get_exception_value(void);

  /*
+** Return a pointer to the execution count of a particular label.
+*/
+
+extern	MR_Unsigned *MR_trace_lookup_trace_count(
+	const MR_Label_Layout *label_layout);
+
+/*
  ** If MR_TRACE_HISTOGRAM is defined, MR_trace maintains two arrays of integers,
  ** MR_trace_histogram_all and MR_trace_histogram_exp, in which the element
  ** with subscript d is incremented when a trace event occurs at depth d.
Index: tests/debugger/declarative/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/declarative/Mmakefile,v
retrieving revision 1.78
diff -u -r1.78 Mmakefile
--- tests/debugger/declarative/Mmakefile	28 Jul 2005 06:44:10 -0000	1.78
+++ tests/debugger/declarative/Mmakefile	4 Aug 2005 16:56:31 -0000
@@ -21,6 +21,7 @@
  	deep_warning		\
  	dependency		\
  	dependency2		\
+	dice			\
  	divide_and_query1	\
  	empty_command		\
  	exceptions		\
@@ -248,6 +249,19 @@
  	$(MDB) ./dependency2 < dependency2.inp > dependency2.out 2>&1 \
  	|| { grep . $@ /dev/null; exit 1; }

+dice.pass: dice
+	/bin/rm -f .mercury_trace_counts.*dice.*
+	MERCURY_OPTIONS=--trace-count ./dice 1 2 3 4 && \
+	mv .mercury_trace_counts.*dice.* dice.pass
+
+dice.fail: dice
+	/bin/rm -f .mercury_trace_counts.*dice.*
+	MERCURY_OPTIONS=--trace-count ./dice 4 1 2 3 && \
+	mv .mercury_trace_counts.*dice.* dice.fail
+
+dice.out: dice dice.inp dice.pass dice.fail
+	$(MDB_STD) ./dice 4 1 2 3 < dice.inp > dice.out 2>&1
+
  divide_and_query1.out: divide_and_query1 divide_and_query1.inp
  	$(MDB_STD) ./divide_and_query1 < divide_and_query1.inp \
  		> divide_and_query1.out 2>&1 \
Index: tests/debugger/declarative/dice.exp
===================================================================
RCS file: tests/debugger/declarative/dice.exp
diff -N tests/debugger/declarative/dice.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/declarative/dice.exp	4 Aug 2005 17:05:21 -0000
@@ -0,0 +1,27 @@
+      E1:     C1 CALL pred dice.main/2-0 (det) dice.m:13
+mdb> mdb> Contexts will not be printed.
+mdb> echo on
+Command echo enabled.
+mdb> break merge_sort
+ 0: + stop  interface pred dice.merge_sort/2-0 (det)
+mdb> continue
+      E2:     C2 CALL pred dice.merge_sort/2-0 (det)
+mdb> delete *
+ 0: E stop  interface pred dice.merge_sort/2-0 (det)
+mdb> finish
+      E3:     C2 EXIT pred dice.merge_sort/2-0 (det)
+mdb> set format pretty
+mdb> set depth 10
+mdb> dd -s sdq -f dice.fail -p dice.pass
+merge_sort([4, 1, 2, 3], [1, 1, 2, 3])
+Valid? n
+merge([], [1], [1])
+Valid? y
+merge([4], [1], [1, 1])
+Valid? n
+Found incorrect contour:
+merge([], [1], [1])
+merge([4], [1], [1, 1])
+Is this a bug? y
+      E4:     C3 EXIT pred dice.merge/3-0 (det)
+mdb> quit -y
Index: tests/debugger/declarative/dice.inp
===================================================================
RCS file: tests/debugger/declarative/dice.inp
diff -N tests/debugger/declarative/dice.inp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/declarative/dice.inp	4 Aug 2005 17:04:04 -0000
@@ -0,0 +1,15 @@
+register --quiet
+context none
+echo on
+break merge_sort
+continue
+delete *
+finish
+set format pretty
+set depth 10
+dd -s sdq -f dice.fail -p dice.pass
+n
+y
+n
+y
+quit -y
Index: tests/debugger/declarative/dice.m
===================================================================
RCS file: tests/debugger/declarative/dice.m
diff -N tests/debugger/declarative/dice.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/declarative/dice.m	4 Aug 2005 16:52:58 -0000
@@ -0,0 +1,72 @@
+:- module dice.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- import_module int, string, list, exception.
+
+main(!IO) :-
+	io.command_line_arguments(Args, !IO),
+	(
+		list.map(string.to_int, Args, Ints)
+	->
+		merge_sort(Ints, Sorted),
+		io.write(Sorted, !IO),
+		io.nl(!IO)
+	;
+		io.write_string("usage error\n", !IO)
+	).
+
+:- pred merge_sort(list(int)::in, list(int)::out) is det.
+
+merge_sort(Us, Ss) :-
+	N = list.length(Us),
+	msort_n(N, Us, Ss, _).
+
+:- pred msort_n(int::in, list(int)::in, list(int)::out, list(int)::out) is det.
+
+msort_n(N, Unsorted, SortedPart, Rest) :-
+	(
+		N =< 0
+	->
+		SortedPart = [],
+		Rest = Unsorted
+	;
+		N = 1
+	->
+		(
+			Unsorted = [U | Us],
+			SortedPart = [U],
+			Rest = Us
+		;
+			Unsorted = [],
+			throw("Unsorted = [] and N = 0")
+		)
+	;
+		N1 = N // 2,
+		dice.msort_n(N1, Unsorted, Ss1, Us2),
+		N2 = N - N1,
+		msort_n(N2, Us2, Ss2, Rest),
+		dice.merge(Ss1, Ss2, SortedPart)
+	).
+
+:- pred merge(list(int)::in, list(int)::in, list(int)::out) is det.
+
+merge([], [], []).
+merge([S | Ss], [], [S | Ss]).
+merge([], [S | Ss], [S | Ss]).
+merge([A | As], [B | Bs], [C | Cs]) :-
+	(
+		A =< B
+	->
+		dice.merge(As, [B | Bs], Cs),
+		C = A
+	;
+		dice.merge(As, [B | Bs], Cs), % BUG
+		C = B
+	).
Index: tests/debugger/declarative/info.exp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/declarative/info.exp,v
retrieving revision 1.4
diff -u -r1.4 info.exp
--- tests/debugger/declarative/info.exp	20 May 2005 05:40:26 -0000	1.4
+++ tests/debugger/declarative/info.exp	4 Aug 2005 13:23:50 -0000
@@ -13,28 +13,28 @@
  mdb> dd -d 3 -n 7 -s divide_and_query
  last([1, 2, 3, 4, 5, 6, 7, 8, ...], t/1)
  Valid? info
-Context of current question   : info.m:43 (info.m:15)
-Search mode                   : divide and query 
-Estimated questions remaining : 5 
-Number of suspect events      : 30 
+Context of current question   : info.m:43 (info.m:15) 
+Search mode                   : divide and query using number of events
+Estimated questions remaining : 5 
+Number of suspect events      : 30
  The current question was chosen because this is the node where the `dd'
  command was issued.
  dd> n
  last([6, 7, 8, 9, 10], t(10))
  Valid? info
-Context of current question   : info.m:43 (info.m:45)
-Search mode                   : divide and query 
-Estimated questions remaining : 5 
-Number of suspect events      : 30 
+Context of current question   : info.m:43 (info.m:45) 
+Search mode                   : divide and query using number of events
+Estimated questions remaining : 5 
+Number of suspect events      : 30
  The current question was chosen because this node divides the suspect
  area into two regions of 15 and 15 events each.
  dd> n
  last([9, 10], t(10))
  Valid? info
-Context of current question   : info.m:43 (info.m:45)
-Search mode                   : divide and query 
-Estimated questions remaining : 4 
-Number of suspect events      : 15 
+Context of current question   : info.m:43 (info.m:45) 
+Search mode                   : divide and query using number of events
+Estimated questions remaining : 4 
+Number of suspect events      : 15
  The current question was chosen because this node divides the suspect
  area into two regions of 9 and 6 events each.
  dd> q
@@ -51,7 +51,6 @@
  Valid? info
  Context of current question : info.m:43 (info.m:45)
  Search mode                 : top down 
-Number of suspect events    : 24
  The current question was chosen because this is the next node in the
  top-down search.
  dd> b 2
@@ -60,7 +59,6 @@
  Valid? info
  Context of current question : info.m:43 (info.m:45)
  Search mode                 : binary search on path
-Number of suspect events    : 21
  The current question was chosen because the marked subterm was bound by
  the unification inside the predicate info.last/2 (info.m:43). The path
  to the subterm in the atom is 2.
@@ -69,7 +67,6 @@
  Valid? info
  Context of current question : info.m:43 (info.m:45)
  Search mode                 : binary search on path
-Number of suspect events    : 18
  The current question was chosen because this node divides a path of
  length 6 into two paths of length 3 and 3.
  dd> n
@@ -77,7 +74,6 @@
  Valid? info
  Context of current question : info.m:43 (info.m:45)
  Search mode                 : binary search on path
-Number of suspect events    : 12
  The current question was chosen because this node divides a path of
  length 3 into two paths of length 1 and 2.
  dd> b 1
@@ -87,7 +83,6 @@
  Valid? info
  Context of current question : info.m:43 (info.m:45)
  Search mode                 : binary search on path
-Number of suspect events    : 6
  The current question was chosen because tracking of the marked subterm
  was stopped here, because the binding node lies in a portion of the tree
  which has been eliminated.
@@ -111,7 +106,6 @@
  Valid? info
  Context of current question : info.m:51 (info.m:34)
  Search mode                 : binary search on path
-Number of suspect events    : 6
  The current question was chosen because the marked subterm was bound by
  the unification inside the function info.f/3 (info.m:52). The path to
  the subterm in the atom is 3/1/1.
@@ -130,7 +124,6 @@
  Valid? info
  Context of current question : info.m:57 (info.m:37)
  Search mode                 : binary search on path
-Number of suspect events    : 6
  The current question was chosen because the marked subterm was bound by
  the foreign procedure call inside the function info.fproc/2 (info.m:57).
  The path to the subterm in the atom is 2.
@@ -142,9 +135,8 @@
  Valid? [no] info
  Context of current question : info.m:57 (info.m:37)
  Search mode                 : top down 
-Number of suspect events    : 6 
-The current question was chosen because this node is being revised,
-because of an unsuccessful previous bug search.
+The current question was chosen because this question is being
+revisited, because of an unsuccessful previous bug search.
  dd> q
  Diagnosis aborted.
        E9:     C5 EXIT pred info.q/4-0 (det)
Index: trace/mercury_trace_declarative.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_declarative.c,v
retrieving revision 1.93
diff -u -r1.93 mercury_trace_declarative.c
--- trace/mercury_trace_declarative.c	1 Aug 2005 02:26:25 -0000	1.93
+++ trace/mercury_trace_declarative.c	4 Aug 2005 18:14:28 -0000
@@ -125,6 +125,7 @@

  #include "mdb.declarative_debugger.mh"
  #include "mdb.declarative_execution.mh"
+#include "mdbcomp.slice_and_dice.mh"

  #include "benchmarking.mh"
  #include "gc.mh"
@@ -325,6 +326,17 @@
  static    MR_bool       MR_edt_unsafe_retry_already_asked;

  /*
+** If trace counts are provided for failing and passing test cases, then
+** we add the suspicion (an integer between 0 and MR_TRACE_DECL_MAX_SUSPICION)
+** for each event to the accumulator below.  We then store the value of the
+** accumulator at CALL, EXIT, REDO, FAIL and EXCP events, which allows
+** the frontend to easily calculate the suspicion of any subtree in the EDT.
+*/
+
+static  MR_Integer  MR_edt_suspicion_accumulator;
+static  MR_bool     MR_edt_update_suspicion_accumulator = MR_FALSE;
+
+/*
  ** This is used as the abstract map from node identifiers to nodes
  ** in the data structure passed to the front end.  It should be
  ** incremented each time the data structure is destructively
@@ -463,6 +475,8 @@
  static    void              MR_trace_reset_implicit_subtree_counters(void);
  static    void              MR_trace_free_implicit_subtree_counters(void);
  static    MR_Unsigned       MR_trace_calc_implicit_subtree_ideal_depth(void);
+static    void              MR_trace_maybe_update_suspicion_accumulator(
+                                const MR_Label_Layout *label_layout);

  MR_bool    MR_trace_decl_assume_all_io_is_tabled = MR_FALSE;

@@ -496,6 +510,9 @@

      entry = event_info->MR_event_sll->MR_sll_entry;
      MR_trace_edt_build_sanity_check(event_info, entry);
+
+    MR_trace_maybe_update_suspicion_accumulator(event_info->MR_event_sll);
+
      MR_trace_maybe_show_progress(event_info->MR_event_number);

      if (! MR_trace_include_event(entry, event_info, &jumpaddr)) {
@@ -875,7 +892,6 @@
      const MR_Label_Layout       *return_label_layout;
      MR_Stack_Walk_Step_Result   result;
      MR_ConstString              problem;
-    MR_String                   goal_path;
      MR_Word                     *base_sp;
      MR_Word                     *base_curfr;
      MR_Word                     maybe_return_label;
@@ -896,10 +912,6 @@
          &base_sp, &base_curfr, &problem);

      /*
-    ** We pass goal_path to Mercury code, which expects its type to be
-    ** MR_String, not MR_ConstString, even though it treats the string as
-    ** constant.
-    **
      ** return_label_layout may be NULL even if result is MR_STEP_OK, if
      ** the current event is inside the code of main/2.
      */
@@ -916,7 +928,8 @@
              atom_args, (MR_Word) event_info->MR_call_seqno,
              (MR_Word) event_info->MR_event_number,
              (MR_Word) at_depth_limit, maybe_return_label,
-            event_label_layout, MR_io_tabling_counter);
+            event_label_layout, MR_io_tabling_counter,
+            MR_edt_suspicion_accumulator);
      );

      return node;
@@ -948,7 +961,7 @@
          node = (MR_Trace_Node) MR_DD_construct_exit_node((MR_Word) prev,
              (MR_Word) call, last_interface, atom_args,
              (MR_Word) event_info->MR_event_number, event_info->MR_event_sll,
-            MR_io_tabling_counter);
+            MR_io_tabling_counter, MR_edt_suspicion_accumulator);
          MR_DD_call_node_set_last_interface((MR_Word) call, (MR_Word) node);
      );

@@ -988,7 +1001,7 @@
          last_interface = MR_DD_call_node_get_last_interface((MR_Word) call);
          node = (MR_Trace_Node) MR_DD_construct_redo_node((MR_Word) prev,
              last_interface, (MR_Word) event_info->MR_event_number,
-            event_info->MR_event_sll);
+            event_info->MR_event_sll, MR_edt_suspicion_accumulator);
          MR_DD_call_node_set_last_interface((MR_Word) call, (MR_Word) node);
      );

@@ -1026,7 +1039,8 @@
          redo = MR_DD_call_node_get_last_interface((MR_Word) call);
          node = (MR_Trace_Node) MR_DD_construct_fail_node((MR_Word) prev,
              (MR_Word) call, (MR_Word) redo,
-            (MR_Word) event_info->MR_event_number, event_info->MR_event_sll);
+            (MR_Word) event_info->MR_event_number, event_info->MR_event_sll,
+            MR_edt_suspicion_accumulator);
          MR_DD_call_node_set_last_interface((MR_Word) call, (MR_Word) node);
      );

@@ -1055,7 +1069,7 @@
          MR_DD_construct_excp_node((MR_Word) prev, (MR_Word) call,
              last_interface, MR_trace_get_exception_value(),
              (MR_Word) event_info->MR_event_number,
-            event_info->MR_event_sll, &node);
+            event_info->MR_event_sll, MR_edt_suspicion_accumulator, &node);
          MR_DD_call_node_set_last_interface((MR_Word) call, (MR_Word) node);
      );

@@ -1480,24 +1494,40 @@
  {
      MR_trace_decl_ensure_init();
      MR_TRACE_CALL_MERCURY(
-        MR_DD_decl_set_fallback_search_mode(search_mode,
+        MR_DD_decl_set_fallback_search_mode(MR_trace_node_store, search_mode,
              MR_trace_front_end_state, &MR_trace_front_end_state);
      );
  }

  MR_bool
  MR_trace_is_valid_search_mode_string(const char *search_mode_string,
-    MR_Decl_Search_Mode *search_mode)
+    MR_Decl_Search_Mode *search_mode, 
+    MR_bool *search_mode_requires_trace_counts)
  {
      MR_bool is_valid;

+    *search_mode_requires_trace_counts = MR_FALSE;
+
      MR_TRACE_CALL_MERCURY(
-        if (MR_streq(search_mode_string, "top_down")) {
+        if (MR_streq(search_mode_string, "top_down")
+            || MR_streq(search_mode_string, "top-down")
+            || MR_streq(search_mode_string, "td")) 
+        {
              *search_mode = MR_DD_decl_top_down_search_mode();
              is_valid = MR_TRUE;
-        } else if (MR_streq(search_mode_string, "divide_and_query")) {
+        } else if (MR_streq(search_mode_string, "divide_and_query")
+            || MR_streq(search_mode_string, "divide-and-query")
+            || MR_streq(search_mode_string, "dq")) 
+        {
              *search_mode = MR_DD_decl_divide_and_query_search_mode();
              is_valid = MR_TRUE;
+        } else if (MR_streq(search_mode_string, "suspicion_divide_and_query")
+            || MR_streq(search_mode_string, "suspicion-divide-and-query")
+            || MR_streq(search_mode_string, "sdq"))
+        {
+            *search_mode = MR_DD_decl_suspicion_divide_and_query_search_mode();
+            is_valid = MR_TRUE;
+            *search_mode_requires_trace_counts = MR_TRUE;
          } else {
              is_valid = MR_FALSE;
          }
@@ -1800,6 +1830,7 @@
      MR_edt_max_depth = maxdepth;
      MR_edt_inside = MR_FALSE;
      MR_edt_building_supertree = create_supertree;
+    MR_edt_suspicion_accumulator = 0;
      MR_edt_start_time = MR_get_user_cpu_miliseconds();
      MR_edt_first_event = event_details->MR_event_number;

@@ -2257,6 +2288,108 @@
      }
  }

+static  void
+MR_trace_maybe_update_suspicion_accumulator(
+    const MR_Label_Layout *label_layout)
+{
+    if (MR_edt_update_suspicion_accumulator) {
+        MR_Unsigned *label_suspicion;
+
+        label_suspicion = MR_trace_lookup_trace_count(label_layout);
+        MR_edt_suspicion_accumulator += *label_suspicion;
+    }
+}
+
+MR_bool 
+MR_trace_decl_init_suspicion_table(char *pass_trace_counts_file, 
+    char *fail_trace_counts_file, MR_String *problem)
+{
+    MR_String                   aligned_pass_trace_counts_file;
+    MR_String                   aligned_fail_trace_counts_file;
+    MR_Word                     maybe_dice;
+    MR_Word                     dice;
+    int                         num_modules;
+    int                         module_num;
+    int                         num_files;
+    int                         file_num;
+    int                         num_labels;
+    int                         label_num;
+    int                         label_index;
+    const MR_Module_Layout      *module;
+    const MR_Module_File_Layout *file;
+    const MR_Label_Layout       *label;
+    MR_Unsigned                 *table_cell;
+    MR_Float                    f_suspicion;
+
+    MR_TRACE_USE_HP(
+        MR_make_aligned_string(aligned_pass_trace_counts_file,
+            (MR_String) pass_trace_counts_file);
+        MR_make_aligned_string(aligned_fail_trace_counts_file,
+            (MR_String) fail_trace_counts_file);
+    );
+
+    MR_TRACE_CALL_MERCURY(
+        MR_MDB_read_dice_try_single_first(
+            aligned_pass_trace_counts_file,
+            aligned_fail_trace_counts_file,
+            &maybe_dice);
+        MR_DD_maybe_dice_error_to_problem_string(maybe_dice, 
+            problem);
+    );
+    if (! MR_streq(*problem, "")) {
+        return MR_FALSE;
+    } else {
+        MR_TRACE_CALL_MERCURY(
+            MR_DD_det_maybe_dice_error_to_dice(maybe_dice, &dice);
+        );
+    }
+
+    /*
+    ** We have read in a valid dice, so we can go ahead and set up the
+    ** suspicion table.  We use the execution count table to store the
+    ** suspicions of each label.  This is a good idea because 
+    ** (a) it is quick to look up a value in this table given a label, and
+    ** (b) it is not used for counting events during an interactive mdb
+    ** session.
+    */
+
+    num_modules = MR_module_info_next;
+    for (module_num = 0; module_num < num_modules; module_num++) {
+        module = MR_module_infos[module_num];
+        num_files = module->MR_ml_filename_count;
+
+        for (file_num = 0; file_num < num_files; file_num++) {
+            file = module->MR_ml_module_file_layout[file_num];
+            num_labels = file->MR_mfl_label_count;
+ 
+            for (label_num = 0; label_num < num_labels; 
+                label_num++) 
+            {
+                label = file->MR_mfl_label_layout[label_num];
+                label_index = 
+                    label->MR_sll_label_num_in_module;
+                table_cell = &(module->MR_ml_label_exec_count[
+                    label_index]);
+                MR_TRACE_CALL_MERCURY(
+                    f_suspicion = 
+                        MR_DD_get_suspicion_for_label_layout(dice, label);
+                );
+                /*
+                ** Instead of using a ratio between 0 and 1
+                ** we store an integer between 0 and 
+                ** MR_TRACE_DECL_MAX_SUSPICION, since this
+                ** is quicker and requires less storage space.
+                */
+                *table_cell = (MR_Unsigned)
+                    ((MR_Float) MR_TRACE_DECL_MAX_SUSPICION * f_suspicion);
+            }
+        }
+    }
+
+    MR_edt_update_suspicion_accumulator = MR_TRUE;
+    return MR_TRUE;
+}
+
  static void
  MR_trace_maybe_show_progress(MR_Unsigned event_number)
  {
Index: trace/mercury_trace_declarative.h
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_declarative.h,v
retrieving revision 1.24
diff -u -r1.24 mercury_trace_declarative.h
--- trace/mercury_trace_declarative.h	20 May 2005 05:40:37 -0000	1.24
+++ trace/mercury_trace_declarative.h	25 May 2005 05:22:35 -0000
@@ -82,7 +82,8 @@

  extern	MR_bool	MR_trace_is_valid_search_mode_string(
  			const char *search_mode_string,
-			MR_Decl_Search_Mode *search_mode);
+			MR_Decl_Search_Mode *search_mode,
+			MR_bool *search_mode_requires_trace_counts);

  /*
  ** Return the default search mode to use when then --search-mode option for the
@@ -99,6 +100,21 @@

  extern	void	MR_decl_print_all_trusted(FILE *fp,
  			MR_bool mdb_command_format);
+
+/*
+** Set up the table of suspicions for each label.  This must be done
+** before generation of the annotated trace is started if
+** MR_edt_update_suspicion_accumulator is true.
+** Returns MR_TRUE if the table was successfully set up and MR_FALSE
+** in there was a problem.  A description of the problem is stored at
+** *problem.
+*/
+
+extern	MR_bool	MR_trace_decl_init_suspicion_table(
+			char *pass_trace_counts_file, 
+                	char *fail_trace_counts_file,
+			MR_String *problem);
+
  /*
  ** The following macros are provided to help C code manipulate the
  ** Mercury data structure.  The values here must match the corresponding
@@ -120,6 +136,13 @@
  #define MR_TRACE_DECL_INITIAL_DEPTH	5

  /*
+** The suspicion of each event is represented as an integer between 0 and
+** MR_TRACE_DECL_MAX_SUSPICION.
+*/
+
+#define	MR_TRACE_DECL_MAX_SUSPICION 	100
+
+/*
  ** The default desired number of nodes to add to the annotated trace when
  ** materializing a new subtree.
  */
Index: trace/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.209
diff -u -r1.209 mercury_trace_internal.c
--- trace/mercury_trace_internal.c	1 Aug 2005 02:40:13 -0000	1.209
+++ trace/mercury_trace_internal.c	4 Aug 2005 18:36:07 -0000
@@ -601,9 +601,13 @@
  static  MR_bool     MR_trace_options_dd(MR_bool *assume_all_io_is_tabled,
                          MR_Integer *default_depth, MR_Integer *num_nodes,
                          MR_Decl_Search_Mode *search_mode, 
-                        MR_bool *search_mode_was_set, MR_bool *new_session,
-                        char ***words, int *word_count, const char *cat,
-                        const char *item);
+                        MR_bool *search_mode_was_set, 
+                        MR_bool *search_mode_requires_trace_counts,
+                        char **pass_trace_counts_file, 
+                        char **fail_trace_counts_file,
+                        MR_bool *new_session, 
+                        char ***words, int *word_count, 
+                        const char *cat, const char *item);
  static  MR_bool     MR_trace_options_stats(char **filename, char ***words,
                          int *word_count, const char *cat, const char *item);
  static  MR_bool     MR_trace_options_type_ctor(MR_bool *print_rep,
@@ -1972,6 +1976,7 @@
      MR_bool             assume_all_io_is_tabled;
      MR_bool             unsafe_retry;

+    ancestor_level = 0;
      across_io = MR_RETRY_IO_INTERACTIVE;
      assume_all_io_is_tabled = MR_FALSE;
      if (! MR_trace_options_retry(&across_io, &assume_all_io_is_tabled,
@@ -2564,10 +2569,15 @@
      MR_Code **jumpaddr)
  {
      MR_bool         verbose = MR_FALSE;
-    MR_Word         browser_term;
+    MR_Word         browser_term = (MR_Word) NULL;
      const char      *problem = NULL;
      MR_bool         xml = MR_FALSE;

+    /* 
+    ** Set this to NULL to avoid uninitialization warnings.
+    */
+    browser_term = (MR_Word) NULL;
+
      if (! MR_trace_options_save_to_file(&xml, &words, &word_count,
          "browsing", "save_to_file"))
      {
@@ -3907,6 +3917,11 @@
      MR_bool     found;
      const char  *set_word;

+    /* 
+    ** Set this to NULL to avoid uninitialization warnings.
+    */
+    flagptr = NULL;
+
      if (word_count == 1) {
          for (i = 0; i < MR_MAXFLAG; i++) {
              /*
@@ -5791,15 +5806,23 @@
      MR_Decl_Search_Mode search_mode;
      MR_bool             search_mode_was_set = MR_FALSE;
      MR_bool             new_session = MR_TRUE;
+    MR_bool             search_mode_requires_trace_counts = MR_FALSE;
+    char                *pass_trace_counts_file;
+    char                *fail_trace_counts_file;
+    MR_String           problem;

      MR_trace_decl_assume_all_io_is_tabled = MR_FALSE;
      MR_edt_default_depth_limit = MR_TRACE_DECL_INITIAL_DEPTH;
      search_mode = MR_trace_get_default_search_mode();
      MR_trace_decl_in_dd_dd_mode = MR_FALSE;
+    pass_trace_counts_file = MR_dice_pass_trace_counts_file;
+    fail_trace_counts_file = MR_dice_fail_trace_counts_file;

      if (! MR_trace_options_dd(&MR_trace_decl_assume_all_io_is_tabled,
          &MR_edt_default_depth_limit, &MR_edt_desired_nodes_in_subtree,
-        &search_mode, &search_mode_was_set, &new_session,
+        &search_mode, &search_mode_was_set,
+        &search_mode_requires_trace_counts,
+        &pass_trace_counts_file, &fail_trace_counts_file, &new_session,
          &words, &word_count, "dd", "dd"))
      {
          ; /* the usage message has already been printed */
@@ -5810,6 +5833,24 @@
                  "mdb: dd doesn't work after `unhide_events on'.\n");
              return KEEP_INTERACTING;
          }
+        if (search_mode_requires_trace_counts && (
+            pass_trace_counts_file == NULL || fail_trace_counts_file == NULL))
+        {
+            fflush(MR_mdb_out);
+            fprintf(MR_mdb_err,
+                "mdb: you need to supply passing and failing trace count "
+                "files\nbefore using the specified search mode.\n");
+            return KEEP_INTERACTING;
+        }
+        if (pass_trace_counts_file != NULL && fail_trace_counts_file != NULL) {
+            if (! MR_trace_decl_init_suspicion_table(pass_trace_counts_file, 
+                fail_trace_counts_file, &problem))
+            {
+                fflush(MR_mdb_out);
+                fprintf(MR_mdb_err, "mdb: %s\n", problem);
+                return KEEP_INTERACTING;
+            }
+        }
          if (search_mode_was_set) {
              MR_trace_decl_set_fallback_search_mode(search_mode);
          } else if (new_session) {
@@ -5837,15 +5878,23 @@
      MR_Decl_Search_Mode search_mode;
      MR_bool             search_mode_was_set = MR_FALSE;
      MR_bool             new_session = MR_TRUE;
+    MR_bool             search_mode_requires_trace_counts = MR_FALSE;
+    char                *pass_trace_counts_file;
+    char                *fail_trace_counts_file;
+    MR_String           problem;

      MR_trace_decl_assume_all_io_is_tabled = MR_FALSE;
      MR_edt_default_depth_limit = MR_TRACE_DECL_INITIAL_DEPTH;
      search_mode = MR_trace_get_default_search_mode();
      MR_trace_decl_in_dd_dd_mode = MR_TRUE;
+    pass_trace_counts_file = MR_dice_pass_trace_counts_file;
+    fail_trace_counts_file = MR_dice_fail_trace_counts_file;

      if (! MR_trace_options_dd(&MR_trace_decl_assume_all_io_is_tabled,
          &MR_edt_default_depth_limit, &MR_edt_desired_nodes_in_subtree, 
-        &search_mode, &search_mode_was_set, &new_session,
+        &search_mode, &search_mode_was_set,
+        &search_mode_requires_trace_counts,
+        &pass_trace_counts_file, &fail_trace_counts_file, &new_session,
          &words, &word_count, "dd", "dd_dd"))
      {
          ; /* the usage message has already been printed */
@@ -5857,6 +5906,24 @@
              trace_mode = MR_TRACE_DECL_DEBUG;
              filename = (const char *) NULL;
          }
+        if (search_mode_requires_trace_counts && (
+            pass_trace_counts_file == NULL || fail_trace_counts_file == NULL))
+        {
+            fflush(MR_mdb_out);
+            fprintf(MR_mdb_err,
+                "mdb: you need to supply passing and failing trace count "
+                "files\nbefore using the specified search mode.\n");
+            return KEEP_INTERACTING;
+        }
+        if (pass_trace_counts_file != NULL && fail_trace_counts_file != NULL) {
+            if (! MR_trace_decl_init_suspicion_table(pass_trace_counts_file, 
+                fail_trace_counts_file, &problem))
+            {
+                fflush(MR_mdb_out);
+                fprintf(MR_mdb_err, "mdb: %s\n", problem);
+                return KEEP_INTERACTING;
+            }
+        }
          if (search_mode_was_set) {
              MR_trace_decl_set_fallback_search_mode(search_mode);
          } else if (new_session) {
@@ -7101,6 +7168,10 @@
      { "depth",                      MR_required_argument,   NULL,   'd' },
      { "nodes",                      MR_required_argument,   NULL,   'n' },
      { "search-mode",                MR_required_argument,   NULL,   's' },
+    { "pass-trace-counts",          MR_required_argument,   NULL,   'p' },
+    { "pass-trace-count",           MR_required_argument,   NULL,   'p' },
+    { "fail-trace-counts",          MR_required_argument,   NULL,   'f' },
+    { "fail-trace-count",           MR_required_argument,   NULL,   'f' },
      { "resume",                     MR_no_argument,         NULL,   'r' },
      { NULL,                         MR_no_argument,         NULL,   0 }
  };
@@ -7109,13 +7180,15 @@
  MR_trace_options_dd(MR_bool *assume_all_io_is_tabled,
      MR_Integer *default_depth, MR_Integer *num_nodes,
      MR_Decl_Search_Mode *search_mode, MR_bool *search_mode_was_set, 
+    MR_bool *search_mode_requires_trace_counts,
+    char **pass_trace_counts_file, char **fail_trace_counts_file,
      MR_bool *new_session, char ***words, int *word_count, const char *cat,
      const char *item)
  {
      int c;

      MR_optind = 0;
-    while ((c = MR_getopt_long(*word_count, *words, "ad:n:s:r",
+    while ((c = MR_getopt_long(*word_count, *words, "ad:n:s:f:p:r",
          MR_trace_dd_opts, NULL)) != EOF)
      {
          switch (c) {
@@ -7140,7 +7213,7 @@

              case 's':
                  if (MR_trace_is_valid_search_mode_string(MR_optarg,
-                    search_mode))
+                    search_mode, search_mode_requires_trace_counts))
                  {
                      *search_mode_was_set = MR_TRUE;
                  } else {
@@ -7153,6 +7226,14 @@
                  *new_session = MR_FALSE;
                  break;

+            case 'p':
+                *pass_trace_counts_file = MR_copy_string(MR_optarg);
+                break;
+
+            case 'f':
+                *fail_trace_counts_file = MR_copy_string(MR_optarg);
+                break;
+
              default:
                  MR_trace_usage(cat, item);
                  return MR_FALSE;
@@ -8227,7 +8308,8 @@
  static const char *const    MR_trace_dd_cmd_args[] =
      { "-s", "-a", "-d", "-n", "--search-mode",
      "--assume-all-io-is-tabled", "--depth", "--nodes",
-    "top_down", "divide_and_query", NULL };
+    "td", "top_down", "dq" "divide_and_query", "sdq", 
+    "suspicion_divide_and_query", NULL };

  /*
  ** "table_io allow" is deliberately not documented as it is developer only
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list