theory HSV_tasks_2019_solutions_task11 imports Main begin section \Representation of circuits.\ text \A wire is represented as an integer.\ type_synonym wire = int datatype gate = NOT "wire" "wire" | AND "wire" "wire" "wire" | OR "wire" "wire" "wire" | TRUE "wire" | FALSE "wire" text \A circuit is represented as a list gates together with a list of output wires.\ type_synonym circuit = "gate list \ wire list" text \Here are some examples of circuits.\ definition "circuit1 == ([NOT 1 2], [2])" definition "circuit2 == ([NOT 1 3, NOT 2 4, AND 3 4 5, NOT 5 6], [6])" definition "circuit3 == ([NOT 1 3, NOT 2 4, NOT 1 7, AND 3 4 5, NOT 5 6], [6])" definition "circuit4 == ([NOT 1 3, NOT 2 4, NOT 1 7, NOT 7 8, AND 3 4 5, NOT 5 6], [6])" text \Return the input wire(s) of a gate.\ fun inputs_of where "inputs_of (NOT wi _) = {wi}" | "inputs_of (AND wi1 wi2 _) = {wi1, wi2}" | "inputs_of (OR wi1 wi2 _) = {wi1, wi2}" | "inputs_of (TRUE _) = {}" | "inputs_of (FALSE _) = {}" text \Return the output wire of a gate.\ fun output_of where "output_of (NOT _ wo) = wo" | "output_of (AND _ _ wo) = wo" | "output_of (OR _ _ wo) = wo" | "output_of (TRUE wo) = wo" | "output_of (FALSE wo) = wo" section \Evaluating circuits.\ text \A valuation associates every wire with a truth-value.\ type_synonym valuation = "wire \ bool" text \A few examples of valuations.\ definition "\0 == \_. True" definition "\1 == \0(1 := True, 2 := False, 3 := True)" definition "\2 == \0(1 := True, 2 := True, 3 := True)" text \Calculate the output of a single gate, given a valuation.\ fun sim_gate :: "valuation \ gate \ bool" where "sim_gate \ (NOT wi wo) = (\ \ wi)" | "sim_gate \ (AND wi1 wi2 wo) = (\ wi1 \ \ wi2)" | "sim_gate \ (OR wi1 wi2 wo) = (\ wi1 \ \ wi2)" | "sim_gate \ (TRUE wo) = True" | "sim_gate \ (FALSE wo) = False" text \Simulates a list of gates, given an initial valuation. Produces a new valuation.\ fun sim_gates :: "valuation \ gate list \ valuation" where "sim_gates \ [] = \" | "sim_gates \ (g # gs) = sim_gates (\ (output_of g := sim_gate \ g)) gs" text \Simulates a circuit, given an initial valuation. Produces a list of truth-values, one truth-value per output.\ fun sim :: "valuation \ circuit \ bool list" where "sim \ (gs, wos) = map (sim_gates \ gs) wos" text \Testing the simulator.\ value "sim \1 circuit1" value "sim \2 circuit1" value "sim \1 circuit2" value "sim \2 circuit2" value "sim \1 circuit3" value "sim \2 circuit3" section \Optimising circuits by removing dead gates.\ text \Return the set of wires that lead to an output.\ fun live_wires where "live_wires ([], wos) = set wos" | "live_wires (g # gs, wos) = (let ws = live_wires (gs, wos) in (if output_of g \ ws then inputs_of g else {}) \ ws)" value "live_wires ([NOT 1 3, NOT 2 4, NOT 1 7, AND 3 4 5, NOT 5 6], [6])" value "live_wires ([NOT 1 3, NOT 2 4, NOT 1 7, NOT 7 8, AND 3 4 5, NOT 5 6], [6])" value "live_wires ([NOT 1 3, NOT 2 4, NOT 1 7, NOT 7 8, AND 3 4 5, NOT 5 6], [6, 8])" value "live_wires ([NOT 1 3, NOT 2 4, NOT 7 8, AND 3 4 5, NOT 5 6], [6])" text \This is a helper function for the next function .\ fun remove_dead_inner where "remove_dead_inner [] wos = []" | "remove_dead_inner (g # gs) wos = (let gs' = remove_dead_inner gs wos in (if output_of g \ live_wires (gs', wos) then [g] else []) @ gs')" text \This function strips out gates that are not needed.\ fun remove_dead where "remove_dead (gs, wos) = (remove_dead_inner gs wos, wos)" value "remove_dead circuit2" value "remove_dead circuit3" value "remove_dead circuit4" section \Proving that removing dead gates does not change a circuit's behaviour.\ text \This lemma is obviously false -- it wrongly claims that remove_dead has no effect on a circuit.\ lemma "remove_dead c = c" oops text \We shall say that two functions are 'congruent on X' if they coincide on all inputs in X.\ fun cong_on where "cong_on X f g = (\x \ X. f x = g x)" text \Congruency is transitive.\ lemma cong_on_trans: assumes "cong_on X g h" assumes "cong_on X f g" shows "cong_on X f h" using assms by simp text \This is a rather technical lemma. It says that if two valuations \ and \' are congruent on all wires that are live in circuit (g # gs, wos), then the respective valuations obtained after simulating g remain congruent on all wires that are live in circuit (gs, wos). \ lemma cong_on_live_wires: assumes "cong_on (live_wires (g # gs, wos)) \ \'" shows "cong_on (live_wires (gs, wos)) (\(output_of g := sim_gate \ g)) (\'(output_of g := sim_gate \' g))" using assms apply (cases "output_of g \ live_wires (gs, wos)", auto) apply (cases g, auto)+ done text \If valuations \ and \' are congruent on all wires that are live in circuit (gs, wos), then the respective valuations obtained after simulating gs are congruent on all wires in wos.\ lemma cong_sim_gates: assumes "cong_on (live_wires (gs, wos)) \ \'" shows "cong_on (set wos) (sim_gates \ gs) (sim_gates \' gs)" using assms proof (induct gs arbitrary: \ \') case Nil thus ?case by auto next case (Cons g gs) show ?case apply (clarsimp simp del: cong_on.simps) apply (rule Cons.hyps[OF cong_on_live_wires[OF Cons.prems]]) done qed text \This is a slightly unwrapped version of the main theorem below.\ lemma sim_remove_dead: "cong_on (set wos) (sim_gates \ (remove_dead_inner gs wos)) (sim_gates \ gs)" proof (induct gs arbitrary: \) case Nil thus ?case by simp next case (Cons g gs \) show ?case proof (cases "output_of g \ live_wires (remove_dead (gs, wos))") case True thus ?thesis using Cons.hyps by auto next case False thus ?thesis apply (simp del: cong_on.simps) apply (rule cong_on_trans) apply (rule Cons.hyps[of "\(output_of g := sim_gate \ g)"]) apply (rule cong_sim_gates) apply clarsimp done qed qed text \We define a convenient shorthand for expressing that two circuits have the same behaviour.\ fun sim_equiv (infix "\" 50) where "c1 \ c2 = (\\. sim \ c1 = sim \ c2)" text \Main theorem: removing the dead gates from a circuit does not change its behaviour.\ theorem "remove_dead c \ c" using sim_remove_dead by (cases c, auto) end