let solve_triangular a b ro vars atms po =
  let rec help po subst row =
    let no_ones_found = ref true in
    for col = row to (Array.length vars)-1 do
      (* if we found a one we test if it
       * is possible to choose this variable according
       * to the partial order *)

      if lookup ro a row col = 1 then
        begin
          (if is_possible po (get_row ro b row) atms vars.(col) then
            begin
              (* extend substitution *)

              let ll = array_to_list (fun i -> Var vars.(i))
                  (get_row ro a row) [] col
              in
              (* add the variables in atms to ll *)
              let ll = array_to_list (fun i -> Var atms.(i))
                  (get_row ro b row) ll (-1)
              in
              (* do a small normalisation *)
              let term = match ll with
                         | []  -> Atm(0)
                         | [x] -> x
                         | _   -> Xor ll
              in
              let subst = (vars.(col), term)::subst
              in
              (* try to solve system with the next row *)
              if row = 0 then
                (* we found a solution and can stop iterating *)
                raise (Substitution_found subst)
              else
                (* try to solve system with the next row *)

                (* update the partial order *)
                let po = it_list
                  (fun po t ->
                    match t with
                    | Var(m) -> add_to_po po m vars.(col)
                    | _      -> failwith "solve_triangular: only Var(_) allowed"
                  ) po ll
                in
                (* apply substitution to the other equations *)
                for row2 = 0 to row-1 do
                  if lookup ro a row2 col = 1 then
                    add_lines ro a b row2 row
                done;
                help po subst (row-1)
            end
          else
            ()
          );
          no_ones_found := false
        end
      else
        ()
    done;
    (* if there are no variables in this row we can find a solution
     * iff there are also no constants in this row, i.e. if it is
     * a 0 = 0 equation *)

    if !no_ones_found then
      begin
        for i = 0 to (Array.length atms)-1 do
          if lookup ro b row i = 1 then
            raise No_Solution
        done;
        if row = 0 then
          raise (Substitution_found subst)
        else
          help po subst (row-1)
      end
  in
  try
    help po [] ((Array.length a)-1);
    raise No_Solution
  with
    Substitution_found subst -> subst