Because of the last-added-tried-first rule for macros, all the special purpose `decreasing_trivial` rules are tried for most recursive definitions out there, and because they use `apply` and `assumption` with default transparency may cause some definitoins to be unfolded over and over again. A quick test with one of the functions in the leansat project shows that elaboration time goes down from 600ms to 375ms when using ``` decreasing_by all_goals decreasing_with with_reducible decreasing_trivial ``` instead of ``` decreasing_by all_goals decreasing_with decreasing_trivial ``` This change uses `with_reducible` in most of these macros. This means that these tactics will no longer work when the relations/definitions they look for is hidden behind a definition. This affected in particular `Array.sizeOf_get`, which now has a companion `sizeOf_getElem`. In addition, there were three tactics using `apply` to apply Nat-related lemmas that we now expect `omega` to solve. We still need them when building `Init` modules that don’t have access to `omega`, but they now live in `decreasing_trivial_pre_omega`, meant to be only used internally.
47 lines
1.7 KiB
Text
47 lines
1.7 KiB
Text
/-
|
||
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Leonardo de Moura
|
||
-/
|
||
prelude
|
||
import Init.Data.Array.Basic
|
||
|
||
namespace Array
|
||
-- TODO: remove the [Inhabited α] parameters as soon as we have the tactic framework for automating proof generation and using Array.fget
|
||
|
||
def qpartition (as : Array α) (lt : α → α → Bool) (lo hi : Nat) : Nat × Array α :=
|
||
if h : as.size = 0 then (0, as) else have : Inhabited α := ⟨as[0]'(by revert h; cases as.size <;> simp)⟩ -- TODO: remove
|
||
let mid := (lo + hi) / 2
|
||
let as := if lt (as.get! mid) (as.get! lo) then as.swap! lo mid else as
|
||
let as := if lt (as.get! hi) (as.get! lo) then as.swap! lo hi else as
|
||
let as := if lt (as.get! mid) (as.get! hi) then as.swap! mid hi else as
|
||
let pivot := as.get! hi
|
||
let rec loop (as : Array α) (i j : Nat) :=
|
||
if h : j < hi then
|
||
if lt (as.get! j) pivot then
|
||
let as := as.swap! i j
|
||
loop as (i+1) (j+1)
|
||
else
|
||
loop as i (j+1)
|
||
else
|
||
let as := as.swap! i hi
|
||
(i, as)
|
||
termination_by hi - j
|
||
decreasing_by all_goals simp_wf; decreasing_trivial_pre_omega
|
||
loop as lo lo
|
||
|
||
@[inline] partial def qsort (as : Array α) (lt : α → α → Bool) (low := 0) (high := as.size - 1) : Array α :=
|
||
let rec @[specialize] sort (as : Array α) (low high : Nat) :=
|
||
if low < high then
|
||
let p := qpartition as lt low high;
|
||
-- TODO: fix `partial` support in the equation compiler, it breaks if we use `let (mid, as) := partition as lt low high`
|
||
let mid := p.1
|
||
let as := p.2
|
||
if mid >= high then as
|
||
else
|
||
let as := sort as low mid
|
||
sort as (mid+1) high
|
||
else as
|
||
sort as low high
|
||
|
||
end Array
|