1 /*-------------------------------------------------------------------------
4 * Routines for preprocessing qualification expressions
6 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.38 2003/08/08 21:41:52 momjian Exp $
13 *-------------------------------------------------------------------------
18 #include "nodes/makefuncs.h"
19 #include "optimizer/clauses.h"
20 #include "optimizer/prep.h"
21 #include "utils/lsyscache.h"
23 static Expr *flatten_andors(Expr *qual);
24 static void flatten_andors_and_walker(FastList *out_list, List *andlist);
25 static void flatten_andors_or_walker(FastList *out_list, List *orlist);
26 static List *pull_ands(List *andlist);
27 static void pull_ands_walker(FastList *out_list, List *andlist);
28 static List *pull_ors(List *orlist);
29 static void pull_ors_walker(FastList *out_list, List *orlist);
30 static Expr *find_nots(Expr *qual);
31 static Expr *push_nots(Expr *qual);
32 static Expr *find_ors(Expr *qual);
33 static Expr *or_normalize(List *orlist);
34 static Expr *find_ands(Expr *qual);
35 static Expr *and_normalize(List *andlist);
36 static Expr *qual_cleanup(Expr *qual);
37 static List *remove_duplicates(List *list);
38 static void count_bool_nodes(Expr *qual, double *nodes,
39 double *cnfnodes, double *dnfnodes);
41 /*****************************************************************************
43 * CNF/DNF CONVERSION ROUTINES
45 * These routines convert an arbitrary boolean expression into
46 * conjunctive normal form or disjunctive normal form.
48 * Normalization is only carried out in the top AND/OR/NOT portion
49 * of the given tree; we do not attempt to normalize boolean expressions
50 * that may appear as arguments of operators or functions in the tree.
52 * Query qualifications (WHERE clauses) are ordinarily transformed into
53 * CNF, ie, AND-of-ORs form, because then the optimizer can use any one
54 * of the independent AND clauses as a filtering qualification. However,
55 * quals that are naturally expressed as OR-of-ANDs can suffer an
56 * exponential growth in size in this transformation, so we also consider
57 * converting to DNF (OR-of-ANDs), and we may also leave well enough alone
58 * if both transforms cause unreasonable growth. The OR-of-ANDs format
59 * is useful for indexscan implementation, so we prefer that format when
60 * there is just one relation involved.
62 * canonicalize_qual() does "smart" conversion to either CNF or DNF, per
63 * the above considerations, while cnfify() and dnfify() simply perform
64 * the demanded transformation. The latter two may become dead code
66 *****************************************************************************/
71 * Convert a qualification to the most useful normalized form.
73 * Returns the modified qualification.
75 * If 'removeAndFlag' is true then it removes explicit AND at the top level,
76 * producing a list of implicitly-ANDed conditions. Otherwise, a regular
77 * boolean expression is returned. Since most callers pass 'true', we
78 * prefer to declare the result as List *, not Expr *.
80 * XXX This code could be much smarter, at the cost of also being slower,
81 * if we tried to compute selectivities and/or see whether there are
82 * actually indexes to support an indexscan implementation of a DNF qual.
83 * We could even try converting the CNF clauses that mention a single
84 * relation into a single DNF clause to see if that looks cheaper to
85 * implement. For now, though, we just try to avoid doing anything
86 * quite as stupid as unconditionally converting to CNF was...
89 canonicalize_qual(Expr *qual, bool removeAndFlag)
102 * Flatten AND and OR groups throughout the tree. This improvement is
103 * always worthwhile, so do it unconditionally.
105 qual = flatten_andors(qual);
108 * Push down NOTs. We do this only in the top-level boolean
109 * expression, without examining arguments of operators/functions.
110 * Even so, it might not be a win if we are unable to find negators
111 * for all the operators involved; perhaps we should compare before-
112 * and-after tree sizes?
114 newqual = find_nots(qual);
117 * Choose whether to convert to CNF, or DNF, or leave well enough
120 * We make an approximate estimate of the number of bottom-level nodes
121 * that will appear in the CNF and DNF forms of the query.
123 count_bool_nodes(newqual, &nodes, &cnfnodes, &dnfnodes);
126 * First heuristic is to forget about *both* normal forms if there are
127 * a huge number of terms in the qual clause. This would only happen
128 * with machine-generated queries, presumably; and most likely such a
129 * query is already in either CNF or DNF.
131 cnfok = dnfok = true;
133 cnfok = dnfok = false;
136 * Second heuristic is to forget about either CNF or DNF if it shows
137 * unreasonable growth compared to the original form of the qual,
138 * where we define "unreasonable" a tad arbitrarily as 4x more
141 if (cnfnodes >= 4.0 * nodes)
143 if (dnfnodes >= 4.0 * nodes)
147 * Third heuristic is to prefer DNF if top level is already an OR, and
148 * only one relation is mentioned, and DNF is no larger than the CNF
149 * representation. (Pretty shaky; can we improve on this?)
151 if (cnfok && dnfok && dnfnodes <= cnfnodes &&
152 or_clause((Node *) newqual) &&
153 NumRelids((Node *) newqual) == 1)
157 * Otherwise, we prefer CNF.
159 * XXX obviously, these rules could be improved upon.
164 * Normalize into conjunctive normal form, and clean up the
167 newqual = qual_cleanup(find_ors(newqual));
172 * Normalize into disjunctive normal form, and clean up the
175 newqual = qual_cleanup(find_ands(newqual));
178 /* Convert to implicit-AND list if requested */
180 newqual = (Expr *) make_ands_implicit(newqual);
182 return (List *) newqual;
187 * Convert a qualification to conjunctive normal form by applying
188 * successive normalizations.
190 * Returns the modified qualification.
192 * If 'removeAndFlag' is true then it removes explicit AND at the top level,
193 * producing a list of implicitly-ANDed conditions. Otherwise, a regular
194 * boolean expression is returned. Since most callers pass 'true', we
195 * prefer to declare the result as List *, not Expr *.
198 cnfify(Expr *qual, bool removeAndFlag)
206 * Flatten AND and OR groups throughout the tree. This improvement is
209 newqual = flatten_andors(qual);
212 * Push down NOTs. We do this only in the top-level boolean
213 * expression, without examining arguments of operators/functions.
215 newqual = find_nots(newqual);
216 /* Normalize into conjunctive normal form. */
217 newqual = find_ors(newqual);
218 /* Clean up the result. */
219 newqual = qual_cleanup(newqual);
222 newqual = (Expr *) make_ands_implicit(newqual);
224 return (List *) newqual;
230 * Convert a qualification to disjunctive normal form by applying
231 * successive normalizations.
233 * Returns the modified qualification.
235 * We do not offer a 'removeOrFlag' in this case; the usages are
247 * Flatten AND and OR groups throughout the tree. This improvement is
250 newqual = flatten_andors(qual);
253 * Push down NOTs. We do this only in the top-level boolean
254 * expression, without examining arguments of operators/functions.
256 newqual = find_nots(newqual);
257 /* Normalize into disjunctive normal form. */
258 newqual = find_ands(newqual);
259 /* Clean up the result. */
260 newqual = qual_cleanup(newqual);
266 /*--------------------
267 * The parser regards AND and OR as purely binary operators, so a qual like
268 * (A = 1) OR (A = 2) OR (A = 3) ...
269 * will produce a nested parsetree
270 * (OR (A = 1) (OR (A = 2) (OR (A = 3) ...)))
271 * In reality, the optimizer and executor regard AND and OR as n-argument
272 * operators, so this tree can be flattened to
273 * (OR (A = 1) (A = 2) (A = 3) ...)
274 * which is the responsibility of the routines below.
276 * flatten_andors() does the basic transformation with no initial assumptions.
277 * pull_ands() and pull_ors() are used to maintain flatness of the AND/OR
278 * tree after local transformations that might introduce nested AND/ORs.
279 *--------------------
282 /*--------------------
284 * Given a qualification, simplify nested AND/OR clauses into flat
285 * AND/OR clauses with more arguments.
287 * Returns the rebuilt expr (note original list structure is not touched).
288 *--------------------
291 flatten_andors(Expr *qual)
296 if (and_clause((Node *) qual))
300 FastListInit(&out_list);
301 flatten_andors_and_walker(&out_list, ((BoolExpr *) qual)->args);
302 return make_andclause(FastListValue(&out_list));
304 else if (or_clause((Node *) qual))
308 FastListInit(&out_list);
309 flatten_andors_or_walker(&out_list, ((BoolExpr *) qual)->args);
310 return make_orclause(FastListValue(&out_list));
312 else if (not_clause((Node *) qual))
313 return make_notclause(flatten_andors(get_notclausearg(qual)));
314 else if (is_opclause(qual))
316 OpExpr *opexpr = (OpExpr *) qual;
317 Expr *left = (Expr *) get_leftop(qual);
318 Expr *right = (Expr *) get_rightop(qual);
320 return make_opclause(opexpr->opno,
321 opexpr->opresulttype,
323 flatten_andors(left),
324 flatten_andors(right));
331 flatten_andors_and_walker(FastList *out_list, List *andlist)
335 foreach(arg, andlist)
337 Expr *subexpr = (Expr *) lfirst(arg);
339 if (and_clause((Node *) subexpr))
340 flatten_andors_and_walker(out_list, ((BoolExpr *) subexpr)->args);
342 FastAppend(out_list, flatten_andors(subexpr));
347 flatten_andors_or_walker(FastList *out_list, List *orlist)
353 Expr *subexpr = (Expr *) lfirst(arg);
355 if (or_clause((Node *) subexpr))
356 flatten_andors_or_walker(out_list, ((BoolExpr *) subexpr)->args);
358 FastAppend(out_list, flatten_andors(subexpr));
364 * Recursively flatten nested AND clauses into a single and-clause list.
366 * Input is the arglist of an AND clause.
367 * Returns the rebuilt arglist (note original list structure is not touched).
370 pull_ands(List *andlist)
374 FastListInit(&out_list);
375 pull_ands_walker(&out_list, andlist);
376 return FastListValue(&out_list);
380 pull_ands_walker(FastList *out_list, List *andlist)
384 foreach(arg, andlist)
386 Expr *subexpr = (Expr *) lfirst(arg);
388 if (and_clause((Node *) subexpr))
389 pull_ands_walker(out_list, ((BoolExpr *) subexpr)->args);
391 FastAppend(out_list, subexpr);
397 * Recursively flatten nested OR clauses into a single or-clause list.
399 * Input is the arglist of an OR clause.
400 * Returns the rebuilt arglist (note original list structure is not touched).
403 pull_ors(List *orlist)
407 FastListInit(&out_list);
408 pull_ors_walker(&out_list, orlist);
409 return FastListValue(&out_list);
413 pull_ors_walker(FastList *out_list, List *orlist)
419 Expr *subexpr = (Expr *) lfirst(arg);
421 if (or_clause((Node *) subexpr))
422 pull_ors_walker(out_list, ((BoolExpr *) subexpr)->args);
424 FastAppend(out_list, subexpr);
430 * Traverse the qualification, looking for 'NOT's to take care of.
431 * For 'NOT' clauses, apply push_not() to try to push down the 'NOT'.
432 * For all other clause types, simply recurse.
434 * Returns the modified qualification. AND/OR flatness is preserved.
437 find_nots(Expr *qual)
443 /* recursing into operator expressions is probably not worth it. */
444 if (is_opclause(qual))
446 OpExpr *opexpr = (OpExpr *) qual;
447 Expr *left = (Expr *) get_leftop(qual);
448 Expr *right = (Expr *) get_rightop(qual);
450 return make_opclause(opexpr->opno,
451 opexpr->opresulttype,
457 if (and_clause((Node *) qual))
462 FastListInit(&t_list);
463 foreach(temp, ((BoolExpr *) qual)->args)
464 FastAppend(&t_list, find_nots(lfirst(temp)));
465 return make_andclause(pull_ands(FastListValue(&t_list)));
467 else if (or_clause((Node *) qual))
472 FastListInit(&t_list);
473 foreach(temp, ((BoolExpr *) qual)->args)
474 FastAppend(&t_list, find_nots(lfirst(temp)));
475 return make_orclause(pull_ors(FastListValue(&t_list)));
477 else if (not_clause((Node *) qual))
478 return push_nots(get_notclausearg(qual));
485 * Push down a 'NOT' as far as possible.
487 * Input is an expression to be negated (e.g., the argument of a NOT clause).
488 * Returns a new qual equivalent to the negation of the given qual.
491 push_nots(Expr *qual)
494 return make_notclause(qual); /* XXX is this right? Or
498 * Negate an operator clause if possible: ("NOT" (< A B)) => (> A B)
499 * Otherwise, retain the clause as it is (the 'not' can't be pushed
502 if (is_opclause(qual))
504 OpExpr *opexpr = (OpExpr *) qual;
505 Oid negator = get_negator(opexpr->opno);
508 return make_opclause(negator,
509 opexpr->opresulttype,
511 (Expr *) get_leftop(qual),
512 (Expr *) get_rightop(qual));
514 return make_notclause(qual);
516 else if (and_clause((Node *) qual))
518 /*--------------------
519 * Apply DeMorgan's Laws:
520 * ("NOT" ("AND" A B)) => ("OR" ("NOT" A) ("NOT" B))
521 * ("NOT" ("OR" A B)) => ("AND" ("NOT" A) ("NOT" B))
522 * i.e., swap AND for OR and negate all the subclauses.
523 *--------------------
528 FastListInit(&t_list);
529 foreach(temp, ((BoolExpr *) qual)->args)
530 FastAppend(&t_list, push_nots(lfirst(temp)));
531 return make_orclause(pull_ors(FastListValue(&t_list)));
533 else if (or_clause((Node *) qual))
538 FastListInit(&t_list);
539 foreach(temp, ((BoolExpr *) qual)->args)
540 FastAppend(&t_list, push_nots(lfirst(temp)));
541 return make_andclause(pull_ands(FastListValue(&t_list)));
543 else if (not_clause((Node *) qual))
546 * Another 'not' cancels this 'not', so eliminate the 'not' and
547 * stop negating this branch. But search the subexpression for
548 * more 'not's to simplify.
550 return find_nots(get_notclausearg(qual));
555 * We don't know how to negate anything else, place a 'not' at
558 return make_notclause(qual);
564 * Given a qualification tree with the 'not's pushed down, convert it
565 * to a tree in CNF by repeatedly applying the rule:
566 * ("OR" A ("AND" B C)) => ("AND" ("OR" A B) ("OR" A C))
568 * Note that 'or' clauses will always be turned into 'and' clauses
569 * if they contain any 'and' subclauses.
571 * Returns the modified qualification. AND/OR flatness is preserved.
579 /* We used to recurse into opclauses here, but I see no reason to... */
580 if (and_clause((Node *) qual))
585 foreach(temp, ((BoolExpr *) qual)->args)
586 andlist = lappend(andlist, find_ors(lfirst(temp)));
587 return make_andclause(pull_ands(andlist));
589 else if (or_clause((Node *) qual))
594 foreach(temp, ((BoolExpr *) qual)->args)
595 orlist = lappend(orlist, find_ors(lfirst(temp)));
596 return or_normalize(pull_ors(orlist));
598 else if (not_clause((Node *) qual))
599 return make_notclause(find_ors(get_notclausearg(qual)));
606 * Given a list of exprs which are 'or'ed together, try to apply
607 * the distributive law
608 * ("OR" A ("AND" B C)) => ("AND" ("OR" A B) ("OR" A C))
609 * to convert the top-level OR clause to a top-level AND clause.
611 * Returns the resulting expression (could be an AND clause, an OR
612 * clause, or maybe even a single subexpression).
615 or_normalize(List *orlist)
617 Expr *distributable = NULL;
618 int num_subclauses = 1;
619 List *andclauses = NIL;
623 return NULL; /* probably can't happen */
624 if (lnext(orlist) == NIL)
625 return lfirst(orlist); /* single-expression OR (can this happen?) */
628 * If we have a choice of AND clauses, pick the one with the most
629 * subclauses. Because we initialized num_subclauses = 1, any AND
630 * clauses with only one arg will be ignored as useless.
632 foreach(temp, orlist)
634 Expr *clause = lfirst(temp);
636 if (and_clause((Node *) clause))
638 int nclauses = length(((BoolExpr *) clause)->args);
640 if (nclauses > num_subclauses)
642 distributable = clause;
643 num_subclauses = nclauses;
648 /* if there's no suitable AND clause, we can't transform the OR */
650 return make_orclause(orlist);
653 * Caution: lremove destructively modifies the input orlist. This
654 * should be OK, since or_normalize is only called with freshly
655 * constructed lists that are not referenced elsewhere.
657 orlist = lremove(distributable, orlist);
659 foreach(temp, ((BoolExpr *) distributable)->args)
661 Expr *andclause = lfirst(temp);
665 * We are going to insert the orlist into multiple places in the
666 * result expression. For most expression types, it'd be OK to
667 * just have multiple links to the same subtree, but this fails
668 * badly for SubLinks (and perhaps other cases?). For safety, we
669 * make a distinct copy for each place the orlist is inserted.
671 if (lnext(temp) == NIL)
672 neworlist = orlist; /* can use original tree at the end */
674 neworlist = copyObject(orlist);
677 * pull_ors is needed here in case andclause has a top-level OR.
678 * Then we recursively apply or_normalize, since there might be an
679 * AND subclause in the resulting OR-list.
681 andclause = or_normalize(pull_ors(lcons(andclause, neworlist)));
682 andclauses = lappend(andclauses, andclause);
685 /* pull_ands is needed in case any sub-or_normalize succeeded */
686 return make_andclause(pull_ands(andclauses));
691 * Given a qualification tree with the 'not's pushed down, convert it
692 * to a tree in DNF by repeatedly applying the rule:
693 * ("AND" A ("OR" B C)) => ("OR" ("AND" A B) ("AND" A C))
695 * Note that 'and' clauses will always be turned into 'or' clauses
696 * if they contain any 'or' subclauses.
698 * Returns the modified qualification. AND/OR flatness is preserved.
701 find_ands(Expr *qual)
706 /* We used to recurse into opclauses here, but I see no reason to... */
707 if (or_clause((Node *) qual))
712 foreach(temp, ((BoolExpr *) qual)->args)
713 orlist = lappend(orlist, find_ands(lfirst(temp)));
714 return make_orclause(pull_ors(orlist));
716 else if (and_clause((Node *) qual))
721 foreach(temp, ((BoolExpr *) qual)->args)
722 andlist = lappend(andlist, find_ands(lfirst(temp)));
723 return and_normalize(pull_ands(andlist));
725 else if (not_clause((Node *) qual))
726 return make_notclause(find_ands(get_notclausearg(qual)));
733 * Given a list of exprs which are 'and'ed together, try to apply
734 * the distributive law
735 * ("AND" A ("OR" B C)) => ("OR" ("AND" A B) ("AND" A C))
736 * to convert the top-level AND clause to a top-level OR clause.
738 * Returns the resulting expression (could be an AND clause, an OR
739 * clause, or maybe even a single subexpression).
742 and_normalize(List *andlist)
744 Expr *distributable = NULL;
745 int num_subclauses = 1;
746 List *orclauses = NIL;
750 return NULL; /* probably can't happen */
751 if (lnext(andlist) == NIL)
752 return lfirst(andlist); /* single-expression AND (can this
756 * If we have a choice of OR clauses, pick the one with the most
757 * subclauses. Because we initialized num_subclauses = 1, any OR
758 * clauses with only one arg will be ignored as useless.
760 foreach(temp, andlist)
762 Expr *clause = lfirst(temp);
764 if (or_clause((Node *) clause))
766 int nclauses = length(((BoolExpr *) clause)->args);
768 if (nclauses > num_subclauses)
770 distributable = clause;
771 num_subclauses = nclauses;
776 /* if there's no suitable OR clause, we can't transform the AND */
778 return make_andclause(andlist);
781 * Caution: lremove destructively modifies the input andlist. This
782 * should be OK, since and_normalize is only called with freshly
783 * constructed lists that are not referenced elsewhere.
785 andlist = lremove(distributable, andlist);
787 foreach(temp, ((BoolExpr *) distributable)->args)
789 Expr *orclause = lfirst(temp);
793 * We are going to insert the andlist into multiple places in the
794 * result expression. For most expression types, it'd be OK to
795 * just have multiple links to the same subtree, but this fails
796 * badly for SubLinks (and perhaps other cases?). For safety, we
797 * make a distinct copy for each place the andlist is inserted.
799 if (lnext(temp) == NIL)
800 newandlist = andlist; /* can use original tree at the
803 newandlist = copyObject(andlist);
806 * pull_ands is needed here in case orclause has a top-level AND.
807 * Then we recursively apply and_normalize, since there might be
808 * an OR subclause in the resulting AND-list.
810 orclause = and_normalize(pull_ands(lcons(orclause, newandlist)));
811 orclauses = lappend(orclauses, orclause);
814 /* pull_ors is needed in case any sub-and_normalize succeeded */
815 return make_orclause(pull_ors(orclauses));
820 * Fix up a qualification by removing duplicate entries (which could be
821 * created during normalization, if identical subexpressions from different
822 * parts of the tree are brought together). Also, check for AND and OR
823 * clauses with only one remaining subexpression, and simplify.
825 * Returns the modified qualification.
828 qual_cleanup(Expr *qual)
833 if (and_clause((Node *) qual))
838 foreach(temp, ((BoolExpr *) qual)->args)
839 andlist = lappend(andlist, qual_cleanup(lfirst(temp)));
841 andlist = remove_duplicates(pull_ands(andlist));
843 if (length(andlist) > 1)
844 return make_andclause(andlist);
846 return lfirst(andlist);
848 else if (or_clause((Node *) qual))
853 foreach(temp, ((BoolExpr *) qual)->args)
854 orlist = lappend(orlist, qual_cleanup(lfirst(temp)));
856 orlist = remove_duplicates(pull_ors(orlist));
858 if (length(orlist) > 1)
859 return make_orclause(orlist);
861 return lfirst(orlist);
863 else if (not_clause((Node *) qual))
864 return make_notclause(qual_cleanup(get_notclausearg(qual)));
873 remove_duplicates(List *list)
878 if (length(list) <= 1)
883 if (!member(lfirst(i), result))
884 result = lappend(result, lfirst(i));
891 * Support for heuristics in canonicalize_qual(): count the
892 * number of nodes that are inputs to the top level AND/OR/NOT
893 * part of a qual tree, and estimate how many nodes will appear
894 * in the CNF'ified or DNF'ified equivalent of the expression.
896 * This is just an approximate calculation; it doesn't deal with NOTs
897 * very well, and of course it cannot detect possible simplifications
898 * from eliminating duplicate subclauses. The idea is just to cheaply
899 * determine whether CNF will be markedly worse than DNF or vice versa.
901 * The counts/estimates are represented as doubles to avoid risk of overflow.
904 count_bool_nodes(Expr *qual,
914 if (and_clause((Node *) qual))
916 *nodes = *cnfnodes = 0.0;
917 *dnfnodes = 1.0; /* DNF nodes will be product of sub-counts */
919 foreach(temp, ((BoolExpr *) qual)->args)
921 count_bool_nodes(lfirst(temp),
922 &subnodes, &subcnfnodes, &subdnfnodes);
924 *cnfnodes += subcnfnodes;
925 *dnfnodes *= subdnfnodes;
929 * we could get dnfnodes < cnfnodes here, if all the sub-nodes are
930 * simple ones with count 1. Make sure dnfnodes isn't too small.
932 if (*dnfnodes < *cnfnodes)
933 *dnfnodes = *cnfnodes;
935 else if (or_clause((Node *) qual))
937 *nodes = *dnfnodes = 0.0;
938 *cnfnodes = 1.0; /* CNF nodes will be product of sub-counts */
940 foreach(temp, ((BoolExpr *) qual)->args)
942 count_bool_nodes(lfirst(temp),
943 &subnodes, &subcnfnodes, &subdnfnodes);
945 *cnfnodes *= subcnfnodes;
946 *dnfnodes += subdnfnodes;
950 * we could get cnfnodes < dnfnodes here, if all the sub-nodes are
951 * simple ones with count 1. Make sure cnfnodes isn't too small.
953 if (*cnfnodes < *dnfnodes)
954 *cnfnodes = *dnfnodes;
956 else if (not_clause((Node *) qual))
958 count_bool_nodes(get_notclausearg(qual),
959 nodes, cnfnodes, dnfnodes);
961 else if (contain_subplans((Node *) qual))
964 * charge extra for subexpressions containing sub-SELECTs, to
965 * discourage us from rearranging them in a way that might
966 * generate N copies of a subselect rather than one. The magic
967 * constant here interacts with the "4x maximum growth" heuristic
968 * in canonicalize_qual().
971 *cnfnodes = *dnfnodes = 25.0;
975 /* anything else counts 1 for my purposes */
976 *nodes = *cnfnodes = *dnfnodes = 1.0;