private static void OptimizeAwayTrue(IDictionary<Fact, IComponent> components, IDictionary<Fact, IComponent> negations,
            PropNet pn, IComponent trueComponent, IComponent falseComponent)
        {
            Debug.Assert((components != null && negations != null) || pn != null);
            foreach (IComponent output in trueComponent.Outputs.ToList())
            {
                if (IsEssentialProposition(output) || output is ITransition)
                    continue;
                var prop = output as IProposition;
                if (prop != null)
                {
                    //Move its outputs to be outputs of true
                    foreach (IComponent child in prop.Outputs)
                    {
                        //Disconnect
                        child.RemoveInput(prop);
                        //output.removeOutput(child); //do at end
                        //Reconnect; will get children before returning, if nonessential
                        trueComponent.AddOutput(child);
                        child.AddInput(trueComponent);
                    }
                    prop.RemoveAllOutputs();

                    if (!IsEssentialProposition(prop))
                    {
                        //Remove the proposition entirely
                        trueComponent.RemoveOutput(prop);
                        output.RemoveInput(trueComponent);
                        //Update its location to the trueComponent in our map
                        if (components != null)
                        {
                            components[prop.Name] = trueComponent;
                            Debug.Assert(negations != null, "negations != null");
                            negations[prop.Name] = falseComponent;
                        }
                        else
                            pn.RemoveComponent(prop);
                    }
                }
                else
                {
                    var or = output as IOr;
                    if (or != null)
                    {
                        //Attach children of or to trueComponent
                        foreach (IComponent child in or.Outputs)
                        {
                            child.AddInput(trueComponent);
                            trueComponent.AddOutput(child);
                            child.RemoveInput(or);
                        }
                        //Disconnect or completely
                        or.RemoveAllOutputs();
                        foreach (IComponent parent in or.Inputs)
                            parent.RemoveOutput(or);
                        or.RemoveAllInputs();
                        if (pn != null)
                            pn.RemoveComponent(or);
                    }
                    else
                    {
                        var and = output as IAnd;
                        if (and != null)
                        {
                            //Remove as input from and
                            and.RemoveInput(trueComponent);
                            trueComponent.RemoveOutput(and);
                            //If and has only one input, remove it
                            if (and.Inputs.Count == 1)
                            {
                                IComponent input = and.GetSingleInput();
                                and.RemoveInput(input);
                                input.RemoveOutput(and);
                                foreach (IComponent output1 in and.Outputs)
                                {
                                    //Disconnect from and
                                    output1.RemoveInput(and);
                                    //and.removeOutput(out); //do at end
                                    //Connect directly to the new input
                                    output1.AddInput(input);
                                    input.AddOutput(output1);
                                }
                                and.RemoveAllOutputs();
                                if (pn != null)
                                    pn.RemoveComponent(and);
                            }
                            else if (and.Inputs.Any())
                                if (pn != null)
                                    pn.RemoveComponent(and);
                        }
                        else
                        {
                            var not = output as INot;
                            if (not != null)
                            {
                                //Disconnect from trueComponent
                                not.RemoveInput(trueComponent);
                                trueComponent.RemoveOutput(not);
                                //Connect all children of the not to falseComponent
                                foreach (IComponent child in not.Outputs)
                                {
                                    //Disconnect
                                    child.RemoveInput(not);
                                    //not.removeOutput(child); //Do at end
                                    //Connect to falseComponent
                                    child.AddInput(falseComponent);
                                    falseComponent.AddOutput(child);
                                }
                                not.RemoveAllOutputs();
                                if (pn != null)
                                    pn.RemoveComponent(not);
                            }
                        }
                    }
                }
            }
        }
        //TODO: Create a version with just a set of components that we can share with post-optimizations
        private static void OptimizeAwayFalse(IDictionary<Fact, IComponent> components, Dictionary<Fact, IComponent> negations,
            PropNet pn, IComponent trueComponent, IComponent falseComponent)
        {
            Debug.Assert((components != null && negations != null) || pn != null);
            Debug.Assert((components == null && negations == null) || pn == null);
            foreach (IComponent output in falseComponent.Outputs.ToList())
            {
                if (IsEssentialProposition(output) || output is ITransition)
                {
                    //Since this is the false constant, there are a few "essential" types we don't actually want to keep around.
                    if (!IsLegalOrGoalProposition(output))
                        continue;
                }
                var prop = output as IProposition;
                if (prop != null)
                {
                    //Move its outputs to be outputs of false
                    foreach (IComponent child in prop.Outputs)
                    {
                        //Disconnect
                        child.RemoveInput(prop);
                        //output.removeOutput(child); //do at end
                        //Reconnect; will get children before returning, if nonessential
                        falseComponent.AddOutput(child);
                        child.AddInput(falseComponent);
                    }
                    prop.RemoveAllOutputs();

                    if (!IsEssentialProposition(prop))
                    {
                        //Remove the proposition entirely
                        falseComponent.RemoveOutput(prop);
                        output.RemoveInput(falseComponent);
                        //Update its location to the trueComponent in our map
                        if (components != null)
                        {
                            components[prop.Name] = falseComponent;
                            negations[prop.Name] = trueComponent;
                        }
                        else
                            pn.RemoveComponent(prop);
                    }
                }
                else
                {
                    var and = output as IAnd;
                    if (and != null)
                    {
                        //Attach children of and to falseComponent
                        foreach (IComponent child in and.Outputs)
                        {
                            child.AddInput(falseComponent);
                            falseComponent.AddOutput(child);
                            child.RemoveInput(and);
                        }
                        //Disconnect and completely
                        and.RemoveAllOutputs();
                        foreach (IComponent parent in and.Inputs)
                            parent.RemoveOutput(and);
                        and.RemoveAllInputs();
                        if (pn != null)
                            pn.RemoveComponent(and);
                    }
                    else
                    {
                        var or = output as IOr;
                        if (or != null)
                        {
                            //Remove as input from or
                            or.RemoveInput(falseComponent);
                            falseComponent.RemoveOutput(or);
                            //If or has only one input, remove it
                            if (or.Inputs.Count == 1)
                            {
                                IComponent input = or.GetSingleInput();
                                or.RemoveInput(input);
                                input.RemoveOutput(or);
                                foreach (IComponent output1 in or.Outputs)
                                {
                                    //Disconnect from and
                                    output1.RemoveInput(or);
                                    //or.removeOutput(out); //do at end
                                    //Connect directly to the new input
                                    output1.AddInput(input);
                                    input.AddOutput(output1);
                                }
                                or.RemoveAllOutputs();
                                if (pn != null)
                                {
                                    pn.RemoveComponent(or);
                                }
                            }
                            else if (!or.Inputs.Any())
                            {
                                if (pn != null)
                                {
                                    pn.RemoveComponent(or);
                                }
                            }
                        }
                        else
                        {
                            var not = output as INot;
                            if (not != null)
                            {
                                //Disconnect from falseComponent
                                not.RemoveInput(falseComponent);
                                falseComponent.RemoveOutput(not);
                                //Connect all children of the not to trueComponent
                                foreach (IComponent child in not.Outputs)
                                {
                                    //Disconnect
                                    child.RemoveInput(not);
                                    //not.removeOutput(child); //Do at end
                                    //Connect to trueComponent
                                    child.AddInput(trueComponent);
                                    trueComponent.AddOutput(child);
                                }
                                not.RemoveAllOutputs();
                                if (pn != null)
                                    pn.RemoveComponent(not);
                            }
                            else if (output is ITransition)
                            {
                                //???
                                throw new Exception("Fix optimizeAwayFalse's case for Transitions");
                            }
                        }
                    }
                }
            }
        }