Commit e55e1d35 authored by Raphael Rieu-Helft's avatar Raphael Rieu-Helft

Add schoolbook GMP functions to examples and bench

parent bb165cfe
......@@ -269,8 +269,8 @@ goods examples/avl "-L examples/avl"
goods examples/verifythis_2016_matrix_multiplication "-L examples/verifythis_2016_matrix_multiplication"
goods examples/double_wp "-L examples/double_wp"
goods examples/ring_decision "-L examples/ring_decision"
goods examples/multiprecision "-L examples/multiprecision"
goods examples/in_progress
goods examples/in_progress/multiprecision "-L examples/in_progress/multiprecision"
echo ""
echo "=== Checking replay (no prover) ==="
......@@ -290,6 +290,7 @@ replay examples/avl "-L examples/avl --merging-only"
#replay examples/to_port/verifythis_2016_matrix_multiplication "-L examples/to_port/verifythis_2016_matrix_multiplication --merging-only"
replay examples/double_wp "-L examples/double_wp --merging-only"
replay examples/ring_decision "-L examples/ring_decision --merging-only"
replay examples/multiprecision "-L examples/multiprecision --merging-only"
#replay examples/in_progress --merging-only
#replay examples/in_progress/multiprecision "-L examples/in_progress/multiprecision --merging-only"
echo ""
......
module Add
use import int.Int
use import mach.int.Int32
use import mach.int.UInt64GMP as Limb
use import int.Power
use import ref.Ref
use import mach.c.C
use import array.Array
use import map.Map
use import types.Types
use import lemmas.Lemmas
(** [add_limb r x y sz] adds to [x] the value of the limb [y],
writes the result in [r] and returns the carry. [r] and [x]
have size [sz]. This corresponds to the function [mpn_add_1] *)
(* r and x must be separated. This is enforced by Why3 regions in typing *)
let add_limb (r x:t) (y:limb) (sz:int32) : limb
requires { valid x sz }
requires { valid r sz }
requires { sz > 0 } (* ? GMP does the same for 0 and 1*)
ensures { value r sz + (power radix sz) * result =
value x sz + y }
ensures { 0 <= result <= 1 }
ensures { forall j. (j < offset r \/ offset r + sz <= j)
-> (pelts r)[j] = old (pelts r)[j] }
writes { r.data.elts }
=
let limb_zero = Limb.of_int 0 in
let c = ref y in
let lx = ref limb_zero in
let i = ref (Int32.of_int 0) in
while Int32.(<) !i sz && (not (Limb.(=) !c limb_zero)) do
invariant { 0 <= !i <= sz }
invariant { !i > 0 -> 0 <= !c <= 1 }
invariant { value r !i + (power radix !i) * !c =
value x !i + y }
invariant { forall j. (j < offset r \/ offset r + sz <= j)
-> (pelts r)[j] = old (pelts r)[j] }
variant { sz - !i }
label StartLoop in
lx := get_ofs x !i;
let (res, carry) = add_with_carry !lx !c limb_zero in
set_ofs r !i res;
assert { value r !i + (power radix !i) * !c =
value x !i + y };
c := carry;
value_tail r !i;
value_tail x !i;
assert { value r (!i+1) + (power radix (!i+1)) * !c
= value x (!i+1) + y
(* by
value r !i + (power radix !i) * !c
= value r k + (power radix k) * res
+ (power radix !i) * !c
= value r k + (power radix k) * res
+ (power radix k) * radix * !c
= value r k + (power radix k) * (res + radix * !c)
= value r k +
(power radix k) * (!lx + (!c at StartLoop))
= value r k + (power radix k) * (!c at StartLoop)
+ (power radix k) * !lx
= value x k + y + (power radix k) * !lx
= value x !i + y*) };
i := Int32.(+) !i (Int32.of_int 1);
done;
if Int32.(=) !i sz then !c
else begin
while Int32.(<) !i sz do
invariant { !c = 0 }
invariant { 0 <= !i <= sz }
invariant { value r !i + (power radix !i) * !c =
value x !i + y }
invariant { forall j. (j < offset r \/ offset r + sz <= j)
-> (pelts r)[j] = old (pelts r)[j] }
variant { sz - !i }
lx := get_ofs x !i;
set_ofs r !i !lx;
assert { value r !i + (power radix !i) * !c =
value x !i + y };
let ghost k = p2i !i in
i := Int32.(+) !i (Int32.of_int 1);
value_sub_tail (pelts r) r.offset (r.offset + k);
value_sub_tail (pelts x) x.offset (x.offset + k);
done;
!c
end
(** [add_limbs r x y sz] adds [x[0..sz-1]] and [y[0..sz-1]] and writes the result in [r].
Returns the carry, either [0] or [1]. Corresponds to the function [mpn_add_n]. *)
let add_limbs (r x y:t) (sz:int32) : limb
requires { valid x sz }
requires { valid y sz }
requires { valid r sz }
ensures { 0 <= result <= 1 }
ensures { value r sz + (power radix sz) * result =
value x sz + value y sz }
ensures { forall j. (j < offset r \/ offset r + sz <= j)
-> (pelts r)[j] = old (pelts r)[j] }
writes { r.data.elts }
=
let limb_zero = Limb.of_int 0 in
let lx = ref limb_zero in
let ly = ref limb_zero in
let c = ref limb_zero in
let i = ref (Int32.of_int 0) in
while Int32.(<) !i sz do
variant { sz - !i }
invariant { 0 <= !i <= sz }
invariant { value r !i + (power radix !i) * !c =
value x !i + value y !i }
invariant { 0 <= !c <= 1 }
invariant { forall j. (j < offset r \/ offset r + sz <= j)
-> (pelts r)[j] = old (pelts r)[j] }
label StartLoop in
lx := get_ofs x !i;
ly := get_ofs y !i;
let res, carry = add_with_carry !lx !ly !c in
set_ofs r !i res;
assert { value r !i + (power radix !i) * !c =
value x !i + value y !i
by value r !i = (value r !i at StartLoop) };
c := carry;
value_tail r !i;
value_tail x !i;
value_tail y !i;
assert { value r (!i+1) + (power radix (!i+1)) * !c =
value x (!i+1) + value y (!i+1)
(*by
value r !i + (power radix !i) * !c
= value r k + (power radix k) * res
+ (power radix !i) * !c
= value r k + (power radix k) * res
+ (power radix k) * radix * !c
= value r k + (power radix k) * (res + radix * !c)
= value r k +
(power radix k) * (!lx + !ly + (!c at StartLoop))
= value r k + (power radix k) * (!c at StartLoop)
+ (power radix k) * (!lx + !ly)
= value x k + value y k
+ (power radix k) * (!lx + !ly)
= value x k + (power radix k) * !lx
+ value y k + (power radix k) * !ly
= value x !i
+ value y k + (power radix k) * !ly
= value x !i
+ (value y k + (power radix k) * !ly)
= value x !i + value y !i*) };
i := Int32.(+) !i (Int32.of_int 1);
done;
!c
(** [add r x y sx sy] adds [(x, sx)] to [(y,sy)] and writes the
result in [(r, sx)]. [sx] must be greater than or equal to
[sy]. Returns carry, either 0 or 1. Corresponds to [mpn_add]. *)
let add (r x y:t) (sx sy:int32) : limb
requires { 0 <= sy <= sx }
requires { valid x sx }
requires { valid y sy }
requires { valid r sx }
ensures { value r sx + (power radix sx) * result =
value x sx + value y sy }
ensures { forall j. (j < offset r \/ offset r + sx <= j)
-> (pelts r)[j] = old (pelts r)[j] }
ensures { 0 <= result <= 1 }
writes { r.data.elts }
=
let limb_zero = Limb.of_int 0 in
let lx = ref limb_zero in
let ly = ref limb_zero in
let c = ref limb_zero in
let i = ref (Int32.of_int 0) in
while Int32.(<) !i sy do
variant { sy - !i }
invariant { 0 <= !i <= sy }
invariant { value r !i + (power radix !i) * !c =
value x !i + value y !i }
invariant { 0 <= !c <= 1 }
invariant { forall j. (j < offset r \/ offset r + sx <= j)
-> (pelts r)[j] = old (pelts r)[j] }
label StartLoop in
lx := get_ofs x !i;
ly := get_ofs y !i;
let res, carry = add_with_carry !lx !ly !c in
set_ofs r !i res;
assert { value r !i + (power radix !i) * !c =
value x !i + value y !i };
c := carry;
value_tail r !i;
value_tail x !i;
value_tail y !i;
assert { value r (!i+1) + (power radix (!i+1)) * !c =
value x (!i+1) + value y (!i+1)
(*by
value r !i + (power radix !i) * !c
= value r k + (power radix k) * res
+ (power radix !i) * !c
= value r k + (power radix k) * res
+ (power radix k) * radix * !c
= value r k + (power radix k) * (res + radix * !c)
= value r k +
(power radix k) * (!lx + !ly + (!c at StartLoop))
= value r k + (power radix k) * (!c at StartLoop)
+ (power radix k) * (!lx + !ly)
= value x k + value y k
+ (power radix k) * (!lx + !ly)
= value x k + (power radix k) * !lx
+ value y k + (power radix k) * !ly
= value x !i
+ value y k + (power radix k) * !ly
= value x !i
+ (value y k + (power radix k) * !ly)
= value x !i + value y !i*) };
i := Int32.(+) !i (Int32.of_int 1);
done;
try
begin while Int32.(<) !i sx do
variant { sx - !i }
invariant { sy <= !i <= sx }
invariant { value r !i + (power radix !i) * !c =
value x !i + value y sy }
invariant { 0 <= !c <= 1 }
invariant { forall j. (j < offset r \/ offset r + sx <= j)
-> (pelts r)[j] = old (pelts r)[j] }
(if (Limb.(=) !c (Limb.of_int 0)) then raise Break);
label StartLoop2 in
lx := get_ofs x !i;
let res, carry = add_with_carry !lx limb_zero !c in
set_ofs r !i res;
assert { value r !i + (power radix !i) * !c =
value x !i + value y sy };
c := carry;
value_tail r !i;
value_tail x !i;
assert { value r (!i+1) + (power radix (!i+1)) * !c =
value x (!i+1) + value y sy
(*by
value r !i + (power radix !i) * !c
= value r k + (power radix k) * res
+ (power radix !i) * !c
= value r k + (power radix k) * res
+ (power radix k) * radix * !c
= value r k + (power radix k) * (res + radix * !c)
= value r k +
(power radix k) * (!lx + 0 + (!c at StartLoop2))
= value r k + (power radix k) * (!c at StartLoop2)
+ (power radix k) * !lx
= value x k + value y sy
+ (power radix k) * !lx
= value x !i
+ value y sy*) };
i := Int32.(+) !i (Int32.of_int 1);
done;
assert { !i = sx }
end
with Break -> assert { !c = 0 }
end;
while Int32.(<) !i sx do
variant { sx - !i }
invariant { sy <= !i <= sx }
invariant { !i = sx \/ !c = 0 }
invariant { value r !i + power radix !i * !c =
value x !i + value y sy }
invariant { forall j. (j < offset r \/ offset r + sx <= j)
-> (pelts r)[j] = old (pelts r)[j] }
assert { !c = 0 by !i < sx };
lx := get_ofs x !i;
set_ofs r !i !lx;
value_tail r !i;
value_tail x !i;
assert { value r !i = value x !i + value y sy }; (* true with this, should not be needed *)
assert { value r (!i+1) + power radix (!i+1) * !c
= value x (!i+1) + value y sy
(*
by
value r !i + power radix !i * !c
= value r !i
= value r k + power radix k * !lx
so value x !i
= value x k + power radix k * !lx
so value r k
= value r k + power radix k * !c
= value x k + value y sy*) };
i := Int32.(+) !i (Int32.of_int 1);
done;
!c
let add_in_place (x y:t) (sx sy:int32) : limb
requires { 0 <= sy <= sx }
requires { valid x sx }
requires { valid y sy }
ensures { value x sx + (power radix sx) * result
= value (old x) sx + value y sy }
ensures { 0 <= result <= 1 }
ensures { forall j. j < x.offset \/ x.offset + sx <= j ->
(pelts x)[j] = (pelts (old x))[j] }
writes { x.data.elts }
=
let ghost ox = { x } in
let limb_zero = Limb.of_int 0 in
let lx = ref limb_zero in
let ly = ref limb_zero in
let c = ref limb_zero in
let i = ref (Int32.of_int 0) in
while Int32.(<) !i sy do
variant { sy - !i }
invariant { 0 <= !i <= sy }
invariant { value x !i + (power radix !i) * !c =
value ox !i + value y !i }
invariant { 0 <= !c <= 1 }
invariant { forall j. !i <= j < sx ->
(pelts x)[x.offset + j] = (pelts ox)[x.offset + j] }
invariant { forall j. j < x.offset \/ x.offset + sx <= j ->
(pelts x)[j] = (pelts (old x))[j] }
label StartLoop in
lx := get_ofs x !i;
assert { !lx = (pelts ox)[ox.offset + !i] };
ly := get_ofs y !i;
let res, carry = add_with_carry !lx !ly !c in
set_ofs x !i res;
assert { forall j. !i < j < sx ->
(pelts x)[x.offset + j]
= (pelts ox)[x.offset + j]
by (pelts x)[x.offset + j]
= (pelts (x at StartLoop))[x.offset + j]
= (pelts ox)[x.offset + j]};
assert { value x !i + (power radix !i) * !c = value ox !i + value y !i };
c := carry;
value_tail x !i;
value_tail ox !i;
value_tail y !i;
assert { value x (!i+1) + (power radix (!i+1)) * !c =
value ox (!i+1) + value y (!i+1)
(*by value ox k + (power radix k) * !lx
= value ox !i
so value x !i + (power radix !i) * !c
= value x k + (power radix k) * res
+ (power radix !i) * !c
= value x k + (power radix k) * res
+ (power radix k) * radix * !c
= value x k + (power radix k) * (res + radix * !c)
= value x k +
(power radix k) * (!lx + !ly + (!c at StartLoop))
= value x k + (power radix k) * (!c at StartLoop)
+ (power radix k) * (!lx + !ly)
= value ox k + value y k
+ (power radix k) * (!lx + !ly)
= (value ox k + (power radix k) * !lx)
+ (value y k + (power radix k) * !ly)
= value ox !i
+ (value y k + (power radix k) * !ly)
= value ox !i
+ (value y k + (power radix k) * !ly)
= value ox !i + value y !i*) };
i := Int32.(+) !i (Int32.of_int 1);
done;
try
while Int32.(<) !i sx do
variant { sx - !i }
invariant { sy <= !i <= sx }
invariant { value x !i + (power radix !i) * !c =
value ox !i + value y sy }
invariant { 0 <= !c <= 1 }
invariant { forall j. !i <= j < sx ->
(pelts x)[x.offset + j] = (pelts ox) [x.offset + j] }
invariant { forall j. j < x.offset \/ x.offset + sx <= j ->
(pelts x)[j] = (pelts (old x))[j] }
(if (Limb.(=) !c limb_zero) then raise ReturnLimb limb_zero);
label StartLoop2 in
lx := get_ofs x !i;
assert { !lx = (pelts ox)[ox.offset + !i] };
let res, carry = add_with_carry !lx limb_zero !c in
value_sub_update_no_change (pelts x) (x.offset + p2i !i)
(x.offset + p2i !i + 1)
(x.offset + p2i sx) res;
set_ofs x !i res;
assert { value x !i + (power radix !i) * !c = value ox !i + value y sy };
c := carry;
assert { forall j. !i < j < sx ->
(pelts x)[x.offset + j] = (pelts ox) [x.offset + j] };
value_tail ox !i;
value_tail x !i;
assert { value x (!i+1) + (power radix (!i+1)) * !c =
value ox (!i+1) + value y sy
(*by value ox k + (power radix k) * !lx
= value ox !i
so
value x !i + (power radix !i) * !c
= value x k + (power radix k) * res
+ (power radix !i) * !c
= value x k + (power radix k) * res
+ (power radix k) * radix * !c
= value x k + (power radix k) * (res + radix * !c)
= value x k +
(power radix k) * (!lx + 0 + (!c at StartLoop2))
= value x k + (power radix k) * (!c at StartLoop2)
+ (power radix k) * !lx
= value ox k + value y sy
+ (power radix k) * !lx
= value ox !i
+ value y sy*) };
i := Int32.(+) !i (Int32.of_int 1);
done;
assert { !i = sx };
!c
with ReturnLimb n -> begin
assert { n = 0 = !c };
assert { forall j. x.offset + !i <= j < x.offset + sx
-> (pelts x)[j] = (pelts ox)[j]
by !i <= j - x.offset < sx
so (pelts x)[x.offset + (j - x.offset)]
= (pelts ox)[x.offset + (j - x.offset)] };
value_sub_frame (pelts x) (pelts ox) (x.offset + p2i !i) (x.offset + p2i sx);
value_sub_concat (pelts x) x.offset (x.offset + p2i !i) (x.offset + p2i sx);
value_sub_concat (pelts ox) x.offset (x.offset + p2i !i) (x.offset + p2i sx);
assert { value x sx = value (old x) sx + value y sy };
n
end
end
use import int.EuclideanDivision
(** [incr x y sz] adds to [x] the value of the limb [y] in place.
[x] has size [sz]. The addition must not overflow. This corresponds
to [mpn_incr] *)
let incr (x:t) (y:limb) (ghost sz:int32) : unit
requires { valid x sz }
requires { sz > 0 }
requires { value x sz + y < power radix sz }
ensures { value x sz = value (old x) sz + y }
ensures { forall j. j < x.offset \/ x.offset + sz <= j ->
(pelts x)[j] = (pelts (old x))[j] }
writes { x.data.elts }
=
let ghost ox = { x } in
let c = ref y in
let lx : ref limb = ref 0 in
let i : ref int32 = ref 0 in
while not (Limb.(=) !c 0) do
invariant { 0 <= !i <= sz }
invariant { !i = sz -> !c = 0 }
invariant { !i > 0 -> 0 <= !c <= 1 }
invariant { value x !i + (power radix !i) * !c
= value ox !i + y }
invariant { forall j. !i <= j < sz ->
(pelts x)[x.offset + j] = (pelts ox)[x.offset + j] }
invariant { forall j. j < x.offset \/ x.offset + sz <= j ->
(pelts x)[j] = (pelts ox)[j] }
variant { sz - !i }
label StartLoop in
lx := get_ofs x !i;
assert { !lx = (pelts ox)[ox.offset + !i] };
let (res, carry) = add_with_carry !lx !c 0 in (*TODO*)
assert { res + radix * carry = !lx + !c }; (* TODO remove this *)
value_sub_update_no_change (pelts x) (x.offset + p2i !i)
(x.offset + p2i !i + 1)
(x.offset + p2i sz) res;
set_ofs x !i res;
assert { forall j. !i < j < sz ->
(pelts x)[x.offset + j]
= (pelts ox)[x.offset + j] };
assert { value x !i + (power radix !i) * !c = value ox !i + y };
c := carry;
value_tail x !i;
value_tail ox !i;
assert { value x (!i+1) + power radix (!i+1) * !c =
value ox (!i+1) + y };
i := Int32.(+) !i 1;
assert { !i = sz -> !c = 0
by value x sz + power radix sz * !c = value ox sz + y
so value ox sz + y < power radix sz
so 0 <= !c <= 1};
done;
value_concat x !i sz;
value_concat ox !i sz;
assert { forall j. x.offset + !i <= j < x.offset + sz ->
(pelts x)[j] = (pelts ox)[j]
by let k = j - x.offset in
!i <= k < sz
so (pelts x)[x.offset + k] = (pelts ox)[x.offset + k]};
value_sub_frame (pelts x) (pelts ox) (x.offset + p2i !i) (x.offset + p2i sz)
(** [incr_1 x sz] adds 1 to [x] in place.
[x] has size [sz]. The addition must not overflow.
This corresponds to [mpn_incr] *)
let incr_1 (x:t) (ghost sz:int32) : unit
requires { valid x sz }
requires { sz > 0 }
requires { value x sz + 1 < power radix sz }
ensures { value x sz = value (old x) sz + 1 }
ensures { forall j. j < x.offset \/ x.offset + sz <= j ->
(pelts x)[j] = (pelts (old x))[j] }
writes { x.data.elts }
=
let ghost ox = { x } in
let r : ref limb = ref 0 in
let ghost c : ref limb = ref 1 in
let lx : ref limb = ref 0 in
let i : ref int32 = ref 0 in
while (Limb.(=) !r 0) do
invariant { 0 <= !i <= sz }
invariant { !i = sz -> !r <> 0 }
invariant { !r <> 0 <-> !c = 0 }
invariant { 0 <= !c <= 1 }
invariant { value x !i + (power radix !i) * !c
= value ox !i + 1 }
invariant { forall j. !i <= j < sz ->
(pelts x)[x.offset + j] = (pelts ox)[x.offset + j] }
invariant { forall j. j < x.offset \/ x.offset + sz <= j ->
(pelts x)[j] = (pelts ox)[j] }
variant { sz - !i }
label StartLoop in
lx := get_ofs x !i;
assert { !lx = (pelts ox)[ox.offset + !i] };
let res = add_mod !lx 1 in
r := res;
ghost (if Limb.(=) res 0 then c := 1 else c := 0);
assert { res + radix * !c = !lx + 1 };
value_sub_update_no_change (pelts x) (x.offset + p2i !i)
(x.offset + p2i !i + 1)
(x.offset + p2i sz) res;
set_ofs x !i res;
assert { forall j. !i < j < sz ->
(pelts x)[x.offset + j]
= (pelts ox)[x.offset + j] };
assert { value x !i + (power radix !i) * (!c at StartLoop) = value ox !i + 1 };
value_tail x !i;
value_tail ox !i;
assert { value x (!i+1) + power radix (!i+1) * !c =
value ox (!i+1) + 1 };
i := Int32.(+) !i 1;
assert { !i = sz -> !c = 0
by value x sz + power radix sz * !c = value ox sz + 1
so value ox sz + 1 < power radix sz
so 0 <= !c <= 1};
done;
value_concat x !i sz;
value_concat ox !i sz;
assert { forall j. x.offset + !i <= j < x.offset + sz ->
(pelts x)[j] = (pelts ox)[j]
by let k = j - x.offset in
!i <= k < sz
so (pelts x)[x.offset + k] = (pelts ox)[x.offset + k]};
value_sub_frame (pelts x) (pelts ox) (x.offset + p2i !i) (x.offset + p2i sz)
end
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE why3session PUBLIC "-//Why3//proof session v5//EN"
"http://why3.lri.fr/why3session.dtd">
<why3session shape_version="4">
<prover id="0" name="Eprover" version="1.9.1-001" timelimit="5" steplimit="0" memlimit="2000"/>
<prover id="1" name="CVC3" version="2.4.1" timelimit="5" steplimit="0" memlimit="1000"/>
<prover id="2" name="CVC4" version="1.4" timelimit="1" steplimit="0" memlimit="1000"/>
<prover id="3" name="Z3" version="4.5.0" timelimit="1" steplimit="0" memlimit="1000"/>
<prover id="4" name="Z3" version="4.4.1" timelimit="5" steplimit="0" memlimit="1000"/>
<prover id="5" name="Alt-Ergo" version="2.0.0" timelimit="5" steplimit="0" memlimit="1000"/>
<file name="../add.mlw" proved="true">
<theory name="Add" proved="true">
<goal name="VC add_limb" expl="VC for add_limb" proved="true">
<transf name="split_goal_right" proved="true" >
<goal name="VC add_limb.0" expl="integer overflow" proved="true">
<proof prover="4"><result status="valid" time="0.03"/></proof>
<proof prover="5"><result status="valid" time="0.04" steps="20"/></proof>
</goal>
<goal name="VC add_limb.1" expl="integer overflow" proved="true">
<proof prover="4"><result status="valid" time="0.03"/></proof>
<proof prover="5"><result status="valid" time="0.03" steps="21"/></proof>
</goal>
<goal name="VC add_limb.2" expl="loop invariant init" proved="true">
<proof prover="4"><result status="valid" time="0.03"/></proof>
<proof prover="5"><result status="valid" time="0.04" steps="11"/></proof>
</goal>
<goal name="VC add_limb.3" expl="loop invariant init" proved="true">
<proof prover="5"><result status="valid" time="0.01" steps="13"/></proof>
</goal>
<goal name="VC add_limb.4" expl="loop invariant init" proved="true">
<proof prover="5"><result status="valid" time="0.03" steps="70"/></proof>
</goal>
<goal name="VC add_limb.5" expl="loop invariant init" proved="true">
<proof prover="3"><result status="valid" time="0.02"/></proof>
</goal>
<goal name="VC add_limb.6" expl="precondition" proved="true">
<proof prover="4"><result status="valid" time="1.22"/></proof>
<proof prover="5"><result status="valid" time="0.06" steps="49"/></proof>
</goal>
<goal name="VC add_limb.7" expl="precondition" proved="true">
<proof prover="5"><result status="valid" time="0.05" steps="21"/></proof>
</goal>
<goal name="VC add_limb.8" expl="precondition" proved="true">
<transf name="split_goal_right" proved="true" >
<goal name="VC add_limb.8.0" expl="VC for add_limb" proved="true">
<transf name="introduce_premises" proved="true" >
<goal name="VC add_limb.8.0.0" expl="VC for add_limb" proved="true">
<proof prover="0"><result status="valid" time="0.09"/></proof>
</goal>
</transf>
</goal>
<goal name="VC add_limb.8.1" expl="VC for add_limb" proved="true">
<proof prover="1" memlimit="2000"><result status="valid" time="0.05"/></proof>
</goal>
</transf>
</goal>
<goal name="VC add_limb.9" expl="assertion" proved="true">
<proof prover="0"><result status="valid" time="0.51"/></proof>