/// <summary>
        /// [ REFS: 'result', DEREFS: 'guardDDs, commandDDs' ]
        /// </summary>
        /// <param name="guardDDs"></param>
        /// <param name="commandDDs"></param>
        /// <param name="currentAvailStartBit"></param>
        /// <returns></returns>
        private ComponentDDs CombineNondetCommands(List <CUDDNode> guardDDs, List <CUDDNode> commandDDs, int currentAvailStartBit)
        {
            ComponentDDs compDDs;
            int          i, j, maxChoices, numDDChoiceVarsUsed;
            CUDDNode     covered, transDD, overlaps, guardHasIChoices, tmp;

            // create object to return result
            compDDs = new ComponentDDs();

            // use 'transDD' to build up MTBDD for transitions
            transDD = CUDD.Constant(0);

            // use 'covered' to track states covered by guards
            covered = CUDD.Constant(0);

            // find overlaps in guards by adding them all up
            overlaps = CUDD.Constant(0);
            for (i = 0; i < guardDDs.Count; i++)
            {
                CUDD.Ref(guardDDs[i]);
                overlaps = CUDD.Function.Plus(overlaps, guardDDs[i]);

                // compute bdd of all guards at same time
                CUDD.Ref(guardDDs[i]);
                covered = CUDD.Function.Or(covered, guardDDs[i]);
            }

            // find the max number of overlaps
            // (i.e. max number of nondet. choices)
            maxChoices = (int)Math.Round(CUDD.FindMax(overlaps));

            // if all the guards were false, we're done already
            if (maxChoices == 0)
            {
                compDDs.guards = covered;
                compDDs.trans  = transDD;

                compDDs.min = currentAvailStartBit;
                compDDs.max = currentAvailStartBit;

                CUDD.Deref(overlaps);
                CUDD.Deref(guardDDs, commandDDs);
                return(compDDs);
            }

            // likewise, if there are no overlaps, it's also pretty easy
            if (maxChoices == 1)
            {
                // add up dds for all commands
                for (i = 0; i < guardDDs.Count; i++)
                {
                    // add up transitions
                    CUDD.Ref(commandDDs[i]);
                    transDD = CUDD.Function.Plus(transDD, commandDDs[i]);
                }
                compDDs.guards = covered;
                compDDs.trans  = transDD;

                compDDs.min = currentAvailStartBit;
                compDDs.max = currentAvailStartBit;

                CUDD.Deref(overlaps);
                CUDD.Deref(guardDDs, commandDDs);
                return(compDDs);
            }

            // otherwise, it's a bit more complicated...

            // first, calculate how many dd vars will be needed
            //the indexes of these bits are: (currentLastBitForChoice + 1), (currentLastBitForChoice + 2), ...
            numDDChoiceVarsUsed = (int)Math.Ceiling(Math.Log(maxChoices, 2));

            // select the variables we will use and put them in a JDDVars
            if (currentAvailStartBit + numDDChoiceVarsUsed - 1 >= choiceVars.Count)
            {
                throw new Exception("Insufficient BDD variables allocated for nondeterminism - please report this as a bug. Thank you.");
            }

            CUDDVars varForThisChoice = new CUDDVars();

            for (i = 0; i < numDDChoiceVarsUsed; i++)
            {
                varForThisChoice.AddVar(choiceVars[currentAvailStartBit + i]);
            }

            // for each i (i = 1 ... max number of nondet. choices)
            for (i = 1; i <= maxChoices; i++)
            {
                // find sections of state space
                // which have exactly i nondet. choices in this module
                CUDD.Ref(overlaps);
                guardHasIChoices = CUDD.Convert.Equals(overlaps, i);

                // if there aren't any for this i, skip the iteration
                if (guardHasIChoices.Equals(CUDD.ZERO))
                {
                    CUDD.Deref(guardHasIChoices);
                    continue;
                }

                //store guards satisfying the guardHasIChoices, and classify them
                List <CUDDNode> satisfiedGuards = new List <CUDDNode>();

                //store the current number of commands satisfying the guard of the corresponding guard
                List <int> numberOfChoicesAdded = new List <int>();

                // go thru each command of the module...
                for (j = 0; j < guardDDs.Count; j++)
                {
                    // see if this command's guard overlaps with 'guardHasIChoices'
                    CUDD.Ref(guardDDs[j], guardHasIChoices);
                    tmp = CUDD.Function.And(guardDDs[j], guardHasIChoices);

                    // if it does...
                    if (!tmp.Equals(CUDD.ZERO))
                    {
                        //find guard Index
                        int guardIndex = -1;
                        int choiceIndexForThisCommand = 0;

                        for (int k = 0; k < satisfiedGuards.Count; k++)
                        {
                            if (satisfiedGuards[k].Equals(tmp))
                            {
                                guardIndex = k;
                                break;
                            }
                        }

                        //if guard exists, then use the index from numberOfChoicesAdded, and increase it
                        if (guardIndex >= 0)
                        {
                            choiceIndexForThisCommand = numberOfChoicesAdded[guardIndex];
                            numberOfChoicesAdded[guardIndex]++;
                        }
                        else
                        {
                            //if not exists, satisfiedGuards, numberOfChoicesAdded
                            satisfiedGuards.Add(tmp);
                            numberOfChoicesAdded.Add(1);
                        }


                        CUDD.Ref(commandDDs[j]);
                        tmp = CUDD.Function.Times(tmp, commandDDs[j]);


                        CUDDNode choiceIndexDD = CUDD.Matrix.SetVectorElement(CUDD.Constant(0), varForThisChoice, choiceIndexForThisCommand, 1);

                        CUDD.Ref(tmp);
                        transDD = CUDD.Function.Plus(transDD, CUDD.Function.Times(tmp, choiceIndexDD));
                    }
                    CUDD.Deref(tmp);
                }

                // take the i bits out of 'overlaps'
                overlaps = CUDD.Function.Times(overlaps, CUDD.Function.Not(guardHasIChoices));
            }

            // store result
            compDDs.guards = covered;
            compDDs.trans  = transDD;

            compDDs.min = currentAvailStartBit;
            compDDs.max = currentAvailStartBit + numDDChoiceVarsUsed;

            CUDD.Deref(overlaps);
            CUDD.Deref(guardDDs, commandDDs);
            return(compDDs);
        }