#include "cubes.h"

/************************************************************************

NAME
	max

SYNOPSIS
	int max(i1,i2)
	int i1,i2;

************************************************************************/

int max(i1,i2)

int i1,i2;
{
  return(i1 > i2 ? i1 : i2);
}

/*************************************************************************

NAME
	select_input

PURPOSE
	The prime implicants are generated using a partioning algorithm
	and this function selects on which input this partition should
	be done, using heuristics.

SYNOPSIS
	int select_input(point_list)
	struct node **point_list;

DESCRIPTION
	for each input not already selected in this subtree count the
	number of 0 1 and x in the cubes. Then the heuristic for the
	selection will use this information. We want to minimize the 
	number of cubes duplicated in both subtrees created by the
	partition, so we will select the input with the least number
	of x. When we are left with only one cube in the partition
	we return -1 instead of an input number. If all the remaining
	cubes are intersecting, an error is generated if the user asked
	for disjoint input cubes by having disjoint_required at 1.
	Otherwise, if all the remaining cubes have the same input,
	we simly combine all their output to form only one cube;
	at output the 1 are the strongest and the d are the weakest.
	If an input is selected, its number is returned.

COORDINATES
	McGill University Electrical Engineering VLSI lab MONTREAL CANADA
	12 july 1984

AUTHOR
	Michel DAGENAIS

***************************************************************************/

int select_input(point_list)

struct node **point_list;
{
   struct cube_list
	*or_cube;	/* cube used when many cubes are intersecting */
   
   struct node 
	*list,		/* pointer to the list received */
	*temp_node;	/* temp pointer to nodes in the list */

   int
	i,		/* loop index for inputs */
	node_number,	/* number of nodes in the list */
	best_input,	/* input selected */
        current_balance, /*number of 0 or 1 whichever is bigger for cur. input*/
        best_balance,	/* number of 0 or 1 whichever is bigger for best input*/
	cost,		/* cost of an input */
	best_cost;	/* cost of the input selected */

/* before anything else we will check if the list contains only one cube
   in which case no partitioning is needed.				*/

   list = *point_list;
   if(list->next_node == NULL) 
    { if(detect_dont_care(list->cube)) put_in_dont_care_list(list);
      list->status = BASIC;
      return(-1);
    }

/* we need partioning so the number of x, 0 and 1 for all the remaining inputs
   will be computed							*/

   for(i = 0 ; i < nbinput ; i++)
    { define_current_var(unused_input[i]);
      nb1_at_input[i] = 0;
      nb0_at_input[i] = 0;
      nbx_at_input[i] = 0;

      temp_node = list;
      for(; temp_node != NULL ; temp_node = temp_node->next_node)
       { switch(extract_current_var(temp_node->cube))

	  { case _1_ :
	      (nb1_at_input[i])++;
	      break;

	    case _0_ :
	      (nb0_at_input[i])++;
	      break;

	    case _X_ :
	      (nbx_at_input[i])++;
	      break;
	  }
       }
    }

   /* Now for all the remaining input we have the number of x, 0 and 1
      we can now decide which input to select. The heuristic is to pick the 
      input with the least number of x and, for this number of x, pick the 
      input with the most balanced number of 0 and 1.		*/

   best_cost = INFINITY;
   best_balance = INFINITY;
   node_number = nb0_at_input[0] + nbx_at_input[0] + nb1_at_input[0];

   for(i = 0 ; i < nbinput ; i++)
    { cost = nbx_at_input[i];
      current_balance = max(nb0_at_input[i],nb1_at_input[i]);
      if(cost != node_number && current_balance != node_number)
       { if(cost < best_cost || 
		(cost == best_cost && current_balance < best_balance))
          { best_balance = current_balance;
            best_cost = cost;
	    best_input = i;
	  }
       }
    }  

/* If no input was selected, all the nodes are the same for the input part.
   If the user specified that disjoint cubes are to be accepted only, a
   message will be issued. Otherwise, we will combine the output of all the
   cubes; the 1 at output are the strongest, the 0 second and the 0 last   */

   if(best_cost == INFINITY)
    { if(DISJOINT_REQUIRED)
       { foutput_cube(stderr,list->cube);
	 fatal_user_error("the part above is present in many cubes");
       }
      or_cube = copy_and_alloc_cube_list(list->cube);
      temp_node = list->next_node;
      for(; temp_node != NULL ; temp_node = temp_node->next_node)
       { or_output(temp_node->cube,or_cube->cube);
       }

/* all the cubes had the same input part so we computed a new cube out of 
   them. The old list is freed and the new cube is placed in the list.
   Since we are left with only one cube, no partitioning is needed and
   we return -1.						*/

      free_list_of_nodes(point_list);
      *point_list = copy_and_alloc_node(or_cube->cube);
      free_cube_list(or_cube);
      list = *point_list;
      if(detect_dont_care(list->cube)) put_in_dont_care_list(list);
      list->status = BASIC;
      return(-1);
    }

/* the best input is selected, we will return it; also we place it at the
   end of the unused_input vector because for the next partition the number
   of unused input will be decreased by one and this input will not be 
   accessible any more as an unused input				*/

   nbinput--;
   i = unused_input[best_input];
   unused_input[best_input] = unused_input[nbinput];
   unused_input[nbinput] = i;
   return(i);
}

/*************************************************************************

NAME
	put_in_dont_care_list

PURPOSE
	When a node has some dont care bits at output, the dont care part
	is put in a special list and a link makes this new node an ancestor
	of the original node with the dont care.

SYNOPSIS
	put_in_dont_care_list(node)
	struct node *node;

DESCRIPTION
	A node with dont care has its dont care part put in the dont care list
	and the dont care bits of the original node are then converted to 1.
	The dont care node is put as an ancestor of the original node.

COORDINATES
	McGill University Electrical Engineering VLSI lab MONTREAL CANADA

AUTHOR
	Michel DAGENAIS

***************************************************************************/

put_in_dont_care_list(node)

struct node *node;
{
  struct parent *parent;
  
  struct node *temp_node;

  temp_node = copy_and_alloc_node(node->cube);
  remove_do_care(temp_node->cube);
  change_dont_to_do_care(node->cube);
  temp_node->next_node = dont_care_list;
  dont_care_list = temp_node;
  temp_node->status = DONT_CARE;
  parent = alloc_parent();
  parent->next_parent = temp_node->descendants;
  temp_node->descendants = parent;
  parent->parent = node;
  parent = alloc_parent();
  parent->next_parent = node->ancestors;
  node->ancestors = parent;
  parent->parent = temp_node;
}

/************************************************************************

NAME
	put_in_common_list

PURPOSE
	The branch received is scanned for the nodes it contains; all the
	nodes in the branch are put in the common list. This function is
	useful to convert a tree structure to store the nodes into a list
	of nodes.

SYNOPSIS
	put_in_common_list(branch)
	struct branch *branch;

DESCRIPTION
	If the branch points to a list of nodes, they are put in the common
	list. If it points to a new binary node, the isx list is put in the
	common list and the 0 and 1 branches are recursively put in the
	common list.

COORDINATES
	McGill University Electrical Engineering VLSI lab MONTREAL CANADA
	8 august 1984

AUTHOR
	Michel DAGENAIS

***************************************************************************/

put_in_common_list(branch)

struct branch *branch;
{
  if(branch->status == 0)return;
  if(branch->status & SUBTREE)
   { put_in_common_list(&(branch->_.subtree->is0));
     put_in_common_list(&(branch->_.subtree->is1));
     common_list = merge_node_lists(branch->_.subtree->isx,common_list);
     free_binary(branch->_.subtree);
     return;
   }
  common_list = merge_node_lists(branch->_.leaf,common_list);
}

 ������������������������������������������������������������