Skip to content

Commit

Permalink
Add a few combinatorial functions
Browse files Browse the repository at this point in the history
  • Loading branch information
FWDekker committed Oct 1, 2024
1 parent b7106e8 commit 6ef4d8a
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 9 deletions.
2 changes: 1 addition & 1 deletion euler
Submodule euler updated from c5769d to a17c07
2 changes: 1 addition & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
rootProject.name = "challenges"

include("aoc")
if (File("euler").exists()) include("euler")
include("euler")
include("std")
12 changes: 10 additions & 2 deletions std/src/main/kotlin/com/fwdekker/std/collections/collections.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.fwdekker.std.collections

import com.fwdekker.std.maths.max
import com.fwdekker.std.maths.min
import com.fwdekker.std.maths.wrapMod
import kotlin.experimental.ExperimentalTypeInference

Expand Down Expand Up @@ -43,6 +41,16 @@ fun <K, V> Iterable<Map<K, V>>.sum() = fold(emptyMap<K, V>()) { acc, it -> acc +
*/
fun <A, B> Pair<A, B>.swap(): Pair<B, A> = Pair(second, first)

/**
* Returns the first element of each pair.
*/
fun <A, B> Iterable<Pair<A, B>>.firsts(): List<A> = map { it.first }

/**
* Returns the second element of each pair.
*/
fun <A, B> Iterable<Pair<A, B>>.seconds(): List<B> = map { it.second }

/**
* Maps both entries using [transform].
*/
Expand Down
31 changes: 26 additions & 5 deletions std/src/main/kotlin/com/fwdekker/std/maths/combinatorics.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,34 @@ import java.math.BigInteger


/**
* Returns the factorial of [this] number.
* Returns the (falling) factorial of [this] number (to [that]).
*
* The factorial of `n` (denoted `n!`) is `n * (n - 1) * (n - 2) * ... * 1`.
*
* The falling factorial of `n` to `k` is `n! / (n - k)!`, which is `n * (n - 1) * (n - 2) * ... * (n - (k - 1))`. If we
* have `n = k` (or `n - 1 = k`), then this evaluates to simply `n!`.
*
* If either [this] or [that] is non-positive, the output is one.
*/
fun BigInteger.factorial(): BigInteger = factorial(this)
fun Int.factorial(that: Int = this): BigInteger = toBigInteger().factorial(that.toBigInteger())

private tailrec fun factorial(number: BigInteger, acc: BigInteger = BigInteger.ONE): BigInteger =
if (number <= BigInteger.ONE) acc
else factorial(number - BigInteger.ONE, acc * number)
fun Long.factorial(that: Long = this): BigInteger = toBigInteger().factorial(that.toBigInteger())

fun BigInteger.factorial(that: BigInteger = this): BigInteger = factorial(this, that)

private tailrec fun factorial(number: BigInteger, steps: BigInteger, acc: BigInteger = BigInteger.ONE): BigInteger =
if (number < BigInteger.ZERO) BigInteger.ONE
else if (number == BigInteger.ZERO || steps <= BigInteger.ZERO) acc
else factorial(number - BigInteger.ONE, steps.dec(), acc * number)

/**
* Returns the binomial coefficient of [this] and [k].
*/
fun Int.choose(k: Int): BigInteger = toBigInteger().choose(k.toBigInteger())

fun Long.choose(k: Long): BigInteger = toBigInteger().choose(k.toBigInteger())

fun BigInteger.choose(k: BigInteger): BigInteger = this.factorial(k) / k.factorial()


/**
Expand Down

0 comments on commit 6ef4d8a

Please sign in to comment.