lib/utils/bit_utils.ex

defmodule CPSolver.BitUtils do
  import Bitwise

  @all_ones_mask (1 <<< 64) - 1
  ## Find least significant bit for given number
  def lsb(n, method \\ :debruijn)

  def lsb(0, _method) do
    nil
  end

  def lsb(n, :shift) do
    lsb_impl(n, 0)
  end

  def lsb(n, :debruijn) do
    sequence = 0x022FDD63CC95386D
    ## Complement, multiply and normalize to 64-bit
    normalized = (n &&& -n) * sequence &&& @all_ones_mask
    ## Use first 6 bits to locate in index table
    ## || lsb(n, :shift)
    deBruijnTable(sequence, normalized >>> 58)
  end

  defp lsb_impl(1, idx) do
    idx
  end

  defp lsb_impl(n, idx) do
    ((n &&& 1) == 1 && idx) ||
      lsb_impl(n >>> 1, idx + 1)
  end

  ## Find most significant bit for given number
  def msb(n, method \\ :debruijn)

  def msb(0, _method), do: nil

  def msb(n, :debruijn) do
    sequence = 0x03F79D71B4CB0A89

    if n > 0 do
      n = n ||| n >>> 1
      n = n ||| n >>> 2
      n = n ||| n >>> 4
      n = n ||| n >>> 8
      n = n ||| n >>> 16
      n = n ||| n >>> 32

      normalized = (n * sequence) &&& @all_ones_mask

      deBruijnTable(sequence, normalized >>> 58)
    end
  end

  def msb(n, :log2) do
    if n > 0 do
      n = n ||| n >>> 1
      n = n ||| n >>> 2
      n = n ||| n >>> 4
      n = n ||| n >>> 8
      n = n ||| n >>> 16
      n = n ||| n >>> 32

      log2(n - (n >>> 1))
    end
  end

  def bit_count(0) do
    0
  end

  def bit_count(n) do
    n = (n &&& 0x5555555555555555) + (n >>> 1 &&& 0x5555555555555555)
    n = (n &&& 0x3333333333333333) + (n >>> 2 &&& 0x3333333333333333)
    n = (n &&& 0x0F0F0F0F0F0F0F0F) + (n >>> 4 &&& 0x0F0F0F0F0F0F0F0F)
    n = (n &&& 0x00FF00FF00FF00FF) + (n >>> 8 &&& 0x00FF00FF00FF00FF)
    n = (n &&& 0x0000FFFF0000FFFF) + (n >>> 16 &&& 0x0000FFFF0000FFFF)
    (n &&& 0x00000000FFFFFFFF) + (n >>> 32 &&& 0x00000000FFFFFFFF)
  end

  ## Precompiled log2 values for powers of 2
  defp log2(1), do: 0
  defp log2(2), do: 1
  defp log2(4), do: 2
  defp log2(8), do: 3
  defp log2(16), do: 4
  defp log2(32), do: 5
  defp log2(64), do: 6
  defp log2(128), do: 7
  defp log2(256), do: 8
  defp log2(512), do: 9
  defp log2(1024), do: 10
  defp log2(2048), do: 11
  defp log2(4096), do: 12
  defp log2(8192), do: 13
  defp log2(16384), do: 14
  defp log2(32768), do: 15
  defp log2(65536), do: 16
  defp log2(131_072), do: 17
  defp log2(262_144), do: 18
  defp log2(524_288), do: 19
  defp log2(1_048_576), do: 20
  defp log2(2_097_152), do: 21
  defp log2(4_194_304), do: 22
  defp log2(8_388_608), do: 23
  defp log2(16_777_216), do: 24
  defp log2(33_554_432), do: 25
  defp log2(67_108_864), do: 26
  defp log2(134_217_728), do: 27
  defp log2(268_435_456), do: 28
  defp log2(536_870_912), do: 29
  defp log2(1_073_741_824), do: 30
  defp log2(2_147_483_648), do: 31
  defp log2(4_294_967_296), do: 32
  defp log2(8_589_934_592), do: 33
  defp log2(17_179_869_184), do: 34
  defp log2(34_359_738_368), do: 35
  defp log2(68_719_476_736), do: 36
  defp log2(137_438_953_472), do: 37
  defp log2(274_877_906_944), do: 38
  defp log2(549_755_813_888), do: 39
  defp log2(1_099_511_627_776), do: 40
  defp log2(2_199_023_255_552), do: 41
  defp log2(4_398_046_511_104), do: 42
  defp log2(8_796_093_022_208), do: 43
  defp log2(17_592_186_044_416), do: 44
  defp log2(35_184_372_088_832), do: 45
  defp log2(70_368_744_177_664), do: 46
  defp log2(140_737_488_355_328), do: 47
  defp log2(281_474_976_710_656), do: 48
  defp log2(562_949_953_421_312), do: 49
  defp log2(1_125_899_906_842_624), do: 50
  defp log2(2_251_799_813_685_248), do: 51
  defp log2(4_503_599_627_370_496), do: 52
  defp log2(9_007_199_254_740_992), do: 53
  defp log2(18_014_398_509_481_984), do: 54
  defp log2(36_028_797_018_963_968), do: 55
  defp log2(72_057_594_037_927_936), do: 56
  defp log2(144_115_188_075_855_872), do: 57
  defp log2(288_230_376_151_711_744), do: 58
  defp log2(576_460_752_303_423_488), do: 59
  defp log2(1_152_921_504_606_846_976), do: 60
  defp log2(2_305_843_009_213_693_952), do: 61
  defp log2(4_611_686_018_427_387_904), do: 62
  defp log2(9_223_372_036_854_775_808), do: 63

  ## De Bruijn table for sequence 0x022FDD63CC95386D
  ## Used for LSB
  defp deBruijnTable(0x022FDD63CC95386D, 0), do: 0
  defp deBruijnTable(0x022FDD63CC95386D, 1), do: 1
  defp deBruijnTable(0x022FDD63CC95386D, 2), do: 2
  defp deBruijnTable(0x022FDD63CC95386D, 3), do: 53
  defp deBruijnTable(0x022FDD63CC95386D, 4), do: 3
  defp deBruijnTable(0x022FDD63CC95386D, 5), do: 7
  defp deBruijnTable(0x022FDD63CC95386D, 6), do: 54
  defp deBruijnTable(0x022FDD63CC95386D, 7), do: 27
  defp deBruijnTable(0x022FDD63CC95386D, 8), do: 4
  defp deBruijnTable(0x022FDD63CC95386D, 9), do: 38
  defp deBruijnTable(0x022FDD63CC95386D, 10), do: 41
  defp deBruijnTable(0x022FDD63CC95386D, 11), do: 8
  defp deBruijnTable(0x022FDD63CC95386D, 12), do: 34
  defp deBruijnTable(0x022FDD63CC95386D, 13), do: 55
  defp deBruijnTable(0x022FDD63CC95386D, 14), do: 48
  defp deBruijnTable(0x022FDD63CC95386D, 15), do: 28
  defp deBruijnTable(0x022FDD63CC95386D, 16), do: 62
  defp deBruijnTable(0x022FDD63CC95386D, 17), do: 5
  defp deBruijnTable(0x022FDD63CC95386D, 18), do: 39
  defp deBruijnTable(0x022FDD63CC95386D, 19), do: 46
  defp deBruijnTable(0x022FDD63CC95386D, 20), do: 44
  defp deBruijnTable(0x022FDD63CC95386D, 21), do: 42
  defp deBruijnTable(0x022FDD63CC95386D, 22), do: 22
  defp deBruijnTable(0x022FDD63CC95386D, 23), do: 9
  defp deBruijnTable(0x022FDD63CC95386D, 24), do: 24
  defp deBruijnTable(0x022FDD63CC95386D, 25), do: 35
  defp deBruijnTable(0x022FDD63CC95386D, 26), do: 59
  defp deBruijnTable(0x022FDD63CC95386D, 27), do: 56
  defp deBruijnTable(0x022FDD63CC95386D, 28), do: 49
  defp deBruijnTable(0x022FDD63CC95386D, 29), do: 18
  defp deBruijnTable(0x022FDD63CC95386D, 30), do: 29
  defp deBruijnTable(0x022FDD63CC95386D, 31), do: 11
  defp deBruijnTable(0x022FDD63CC95386D, 32), do: 63
  defp deBruijnTable(0x022FDD63CC95386D, 33), do: 52
  defp deBruijnTable(0x022FDD63CC95386D, 34), do: 6
  defp deBruijnTable(0x022FDD63CC95386D, 35), do: 26
  defp deBruijnTable(0x022FDD63CC95386D, 36), do: 37
  defp deBruijnTable(0x022FDD63CC95386D, 37), do: 40
  defp deBruijnTable(0x022FDD63CC95386D, 38), do: 33
  defp deBruijnTable(0x022FDD63CC95386D, 39), do: 47
  defp deBruijnTable(0x022FDD63CC95386D, 40), do: 61
  defp deBruijnTable(0x022FDD63CC95386D, 41), do: 45
  defp deBruijnTable(0x022FDD63CC95386D, 42), do: 43
  defp deBruijnTable(0x022FDD63CC95386D, 43), do: 21
  defp deBruijnTable(0x022FDD63CC95386D, 44), do: 23
  defp deBruijnTable(0x022FDD63CC95386D, 45), do: 58
  defp deBruijnTable(0x022FDD63CC95386D, 46), do: 17
  defp deBruijnTable(0x022FDD63CC95386D, 47), do: 10
  defp deBruijnTable(0x022FDD63CC95386D, 48), do: 51
  defp deBruijnTable(0x022FDD63CC95386D, 49), do: 25
  defp deBruijnTable(0x022FDD63CC95386D, 50), do: 36
  defp deBruijnTable(0x022FDD63CC95386D, 51), do: 32
  defp deBruijnTable(0x022FDD63CC95386D, 52), do: 60
  defp deBruijnTable(0x022FDD63CC95386D, 53), do: 20
  defp deBruijnTable(0x022FDD63CC95386D, 54), do: 57
  defp deBruijnTable(0x022FDD63CC95386D, 55), do: 16
  defp deBruijnTable(0x022FDD63CC95386D, 56), do: 50
  defp deBruijnTable(0x022FDD63CC95386D, 57), do: 31
  defp deBruijnTable(0x022FDD63CC95386D, 58), do: 19
  defp deBruijnTable(0x022FDD63CC95386D, 59), do: 15
  defp deBruijnTable(0x022FDD63CC95386D, 60), do: 30
  defp deBruijnTable(0x022FDD63CC95386D, 61), do: 14
  defp deBruijnTable(0x022FDD63CC95386D, 62), do: 13
  defp deBruijnTable(0x022FDD63CC95386D, 63), do: 12

  ## De Bruijn table for sequence 0x03F79D71B4CB0A89
  ## Used for MSB

  defp deBruijnTable(0x03F79D71B4CB0A89, 0), do: 0
  defp deBruijnTable(0x03F79D71B4CB0A89, 1), do: 47
  defp deBruijnTable(0x03F79D71B4CB0A89, 2), do: 1
  defp deBruijnTable(0x03F79D71B4CB0A89, 3), do: 56
  defp deBruijnTable(0x03F79D71B4CB0A89, 4), do: 48
  defp deBruijnTable(0x03F79D71B4CB0A89, 5), do: 27
  defp deBruijnTable(0x03F79D71B4CB0A89, 6), do: 2
  defp deBruijnTable(0x03F79D71B4CB0A89, 7), do: 60
  defp deBruijnTable(0x03F79D71B4CB0A89, 8), do: 57
  defp deBruijnTable(0x03F79D71B4CB0A89, 9), do: 49
  defp deBruijnTable(0x03F79D71B4CB0A89, 10), do: 41
  defp deBruijnTable(0x03F79D71B4CB0A89, 11), do: 37
  defp deBruijnTable(0x03F79D71B4CB0A89, 12), do: 28
  defp deBruijnTable(0x03F79D71B4CB0A89, 13), do: 16
  defp deBruijnTable(0x03F79D71B4CB0A89, 14), do: 3
  defp deBruijnTable(0x03F79D71B4CB0A89, 15), do: 61
  defp deBruijnTable(0x03F79D71B4CB0A89, 16), do: 54
  defp deBruijnTable(0x03F79D71B4CB0A89, 17), do: 58
  defp deBruijnTable(0x03F79D71B4CB0A89, 18), do: 35
  defp deBruijnTable(0x03F79D71B4CB0A89, 19), do: 52
  defp deBruijnTable(0x03F79D71B4CB0A89, 20), do: 50
  defp deBruijnTable(0x03F79D71B4CB0A89, 21), do: 42
  defp deBruijnTable(0x03F79D71B4CB0A89, 22), do: 21
  defp deBruijnTable(0x03F79D71B4CB0A89, 23), do: 44
  defp deBruijnTable(0x03F79D71B4CB0A89, 24), do: 38
  defp deBruijnTable(0x03F79D71B4CB0A89, 25), do: 32
  defp deBruijnTable(0x03F79D71B4CB0A89, 26), do: 29
  defp deBruijnTable(0x03F79D71B4CB0A89, 27), do: 23
  defp deBruijnTable(0x03F79D71B4CB0A89, 28), do: 17
  defp deBruijnTable(0x03F79D71B4CB0A89, 29), do: 11
  defp deBruijnTable(0x03F79D71B4CB0A89, 30), do: 4
  defp deBruijnTable(0x03F79D71B4CB0A89, 31), do: 62
  defp deBruijnTable(0x03F79D71B4CB0A89, 32), do: 46
  defp deBruijnTable(0x03F79D71B4CB0A89, 33), do: 55
  defp deBruijnTable(0x03F79D71B4CB0A89, 34), do: 26
  defp deBruijnTable(0x03F79D71B4CB0A89, 35), do: 59
  defp deBruijnTable(0x03F79D71B4CB0A89, 36), do: 40
  defp deBruijnTable(0x03F79D71B4CB0A89, 37), do: 36
  defp deBruijnTable(0x03F79D71B4CB0A89, 38), do: 15
  defp deBruijnTable(0x03F79D71B4CB0A89, 39), do: 53
  defp deBruijnTable(0x03F79D71B4CB0A89, 40), do: 34
  defp deBruijnTable(0x03F79D71B4CB0A89, 41), do: 51
  defp deBruijnTable(0x03F79D71B4CB0A89, 42), do: 20
  defp deBruijnTable(0x03F79D71B4CB0A89, 43), do: 43
  defp deBruijnTable(0x03F79D71B4CB0A89, 44), do: 31
  defp deBruijnTable(0x03F79D71B4CB0A89, 45), do: 22
  defp deBruijnTable(0x03F79D71B4CB0A89, 46), do: 10
  defp deBruijnTable(0x03F79D71B4CB0A89, 47), do: 45
  defp deBruijnTable(0x03F79D71B4CB0A89, 48), do: 25
  defp deBruijnTable(0x03F79D71B4CB0A89, 49), do: 39
  defp deBruijnTable(0x03F79D71B4CB0A89, 50), do: 14
  defp deBruijnTable(0x03F79D71B4CB0A89, 51), do: 33
  defp deBruijnTable(0x03F79D71B4CB0A89, 52), do: 19
  defp deBruijnTable(0x03F79D71B4CB0A89, 53), do: 30
  defp deBruijnTable(0x03F79D71B4CB0A89, 54), do: 9
  defp deBruijnTable(0x03F79D71B4CB0A89, 55), do: 24
  defp deBruijnTable(0x03F79D71B4CB0A89, 56), do: 13
  defp deBruijnTable(0x03F79D71B4CB0A89, 57), do: 18
  defp deBruijnTable(0x03F79D71B4CB0A89, 58), do: 8
  defp deBruijnTable(0x03F79D71B4CB0A89, 59), do: 12
  defp deBruijnTable(0x03F79D71B4CB0A89, 60), do: 7
  defp deBruijnTable(0x03F79D71B4CB0A89, 61), do: 6
  defp deBruijnTable(0x03F79D71B4CB0A89, 62), do: 5
  defp deBruijnTable(0x03F79D71B4CB0A89, 63), do: 63
end