Module Argument.
Fixpoint term_to_tree (t: mset_term) : tree :=
match t with
| mset_term_zero => node 0 leaf leaf
| mset_term_var x => node 1 (node x leaf leaf) leaf
| mset_term_plus t u => node 2 (term_to_tree t) (term_to_tree u)
| mset_term_h t => node 3 (term_to_tree t) leaf
end.
Fixpoint tree_to_term (t: tree) : mset_term :=
match t with
| node 0 leaf leaf => mset_term_zero
| node 1 (node x leaf leaf) leaf => mset_term_var x
| node 2 t u => mset_term_plus (tree_to_term t) (tree_to_term u)
| node 3 t leaf => mset_term_h (tree_to_term t)
| _ => mset_term_zero
end.
Definition term_to_nat (t: mset_term) : nat :=
tree_to_nat (term_to_tree t).
Definition nat_to_term (n: nat) : mset_term :=
tree_to_term (nat_to_tree n).
(* decompose mset_term into elementary constraints *)
Fixpoint term_to_msetcs (t: mset_term) : list msetc :=
match t with
| mset_term_zero => [msetc_zero (term_to_nat t)]
| mset_term_var x => []
| mset_term_plus u v =>
[msetc_sum (term_to_nat t) (term_to_nat u) (term_to_nat v)] ++
(term_to_msetcs u) ++ (term_to_msetcs v)
| mset_term_h u =>
[msetc_h (term_to_nat t) (term_to_nat u)] ++ (term_to_msetcs u)
end.
Definition encode_eq (t u: mset_term) :=
[(msetc_sum (tree_to_nat leaf) (tree_to_nat leaf) (tree_to_nat leaf));
(msetc_sum (term_to_nat t) (tree_to_nat leaf) (term_to_nat u))].
(* encode FMsetC_PROBLEM as LPolyNC_PROBLEM *)
Definition encode_problem (msetcs : list constraint) : list msetc :=
flat_map (fun '(t, u) => (encode_eq t u) ++ term_to_msetcs t ++ term_to_msetcs u) msetcs.
End Argument.

(* many-one reduction from FMsetTC to FMsetC *)
Theorem reduction : FMsetTC_SAT ⪯ FMsetC_SAT.