// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
fn[T] removes_array(k : Int, n : Int, xs : Array[T]) -> Iter[Array[T]] {
guard k <= n else { [||] }
let xs2 = xs[:k].to_owned()
let xs1 = xs[k:].to_owned()
if xs1.is_empty() {
[|[]|]
} else {
[xs1].iter().add(removes_array(k, n - k, xs1).map(x => xs2 + x))
}
}
///|
fn[T] removes_list(k : Int, n : Int, xs : @list.List[T]) -> Iter[@list.List[T]] {
guard k <= n else { [||] }
let xs_drop = xs.drop(k)
if xs_drop.is_empty() {
[|List([])|]
} else {
let xs_take = xs.take(k)
removes_list(k, n - k, xs_drop).map(x => xs_take.concat(x)).add([|xs_drop|])
}
}
///|
fn shrink_decimal(x : Double) -> Iter[Double] {
guard !x.is_nan() else { [|0.0, 1.0, -1.0, 2.0|] }
guard !x.is_inf() else { [|0.0, 1.0, -1.0, 1000.0, -1000.0|] }
guard x >= 0.0 else {
Iter::singleton(-x).concat(shrink_decimal(-x).map(Double::neg))
}
guard x != 0.0 else { Iter::empty() }
[|1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0|].flat_map(p => {
let m = (x * p + 0.5).floor().to_int64()
if p != 1.0 && m % 10L == 0L {
return Iter::empty()
}
Iter::singleton(m)
.concat(Shrink::shrink(m))
.map(n => n.to_double() / p)
.filter(y => y >= 0.0 && y < x)
})
}