|
| 1 | +#!/usr/bin/env python |
| 2 | +import os |
| 3 | +from argparse import ArgumentParser |
| 4 | +from math import e |
| 5 | +from typing import List |
| 6 | + |
| 7 | +BIT_COUNT = 64 |
| 8 | +MAX_VALUE = 2**BIT_COUNT |
| 9 | + |
| 10 | +DEFAULT_DIVISOR_BASE = 2 |
| 11 | +DEFAULT_DIVISOR_POWER = 16 |
| 12 | +DEFAULT_EXP_BASE = e |
| 13 | + |
| 14 | + |
| 15 | +def generate_exp_lut(divisor_base: int, divisor_power: int, exp_base: float): |
| 16 | + divisor: int = divisor_base**divisor_power |
| 17 | + |
| 18 | + exp_lut: List[int] = [] |
| 19 | + |
| 20 | + for index in range(BIT_COUNT): |
| 21 | + exponent = (2**index) / divisor |
| 22 | + value = int((exp_base**exponent) * divisor + 0.5) |
| 23 | + if value > MAX_VALUE: |
| 24 | + break |
| 25 | + exp_lut.append(value) |
| 26 | + |
| 27 | + lut_identifier: str = ( |
| 28 | + f"LUT_{divisor_base}_{divisor_power}_EXP_{'e' if exp_base == e else ('%g' % exp_base).replace('.', 'p')}" |
| 29 | + ) |
| 30 | + lut_size: int = len(exp_lut) |
| 31 | + |
| 32 | + generated_options = "" |
| 33 | + if ( |
| 34 | + DEFAULT_DIVISOR_BASE is not divisor_base |
| 35 | + or DEFAULT_DIVISOR_POWER is not divisor_power |
| 36 | + or DEFAULT_EXP_BASE is not exp_base |
| 37 | + ): |
| 38 | + generated_options += " with `" |
| 39 | + |
| 40 | + if DEFAULT_DIVISOR_BASE is not divisor_base: |
| 41 | + generated_options += f"-b {divisor_base}" |
| 42 | + if DEFAULT_DIVISOR_POWER is not divisor_power or DEFAULT_EXP_BASE is not exp_base: |
| 43 | + generated_options += " " |
| 44 | + |
| 45 | + if DEFAULT_DIVISOR_POWER is not divisor_power: |
| 46 | + generated_options += f"-p {divisor_power}" |
| 47 | + if DEFAULT_EXP_BASE is not exp_base: |
| 48 | + generated_options += " " |
| 49 | + |
| 50 | + if DEFAULT_EXP_BASE is not exp_base: |
| 51 | + generated_options += f"-e {exp_base:g}" |
| 52 | + |
| 53 | + generated_options += "`" |
| 54 | + |
| 55 | + source: str = f"""// This file was generated using the `misc/scripts/exp_lut_generator.py` script{generated_options}. |
| 56 | +
|
| 57 | +#pragma once |
| 58 | +
|
| 59 | +#include <array> |
| 60 | +#include <cstddef> |
| 61 | +#include <cstdint> |
| 62 | +
|
| 63 | +static constexpr int64_t {lut_identifier}_DIVISOR = {divisor}; |
| 64 | +static constexpr size_t {lut_identifier}_SIZE = {lut_size}; |
| 65 | +
|
| 66 | +static constexpr std::array<int64_t, {lut_identifier}_SIZE> {lut_identifier} {{ |
| 67 | +""" |
| 68 | + |
| 69 | + for value in exp_lut[:-1]: |
| 70 | + source += f"\t{value},\n" |
| 71 | + |
| 72 | + source += f"\t{exp_lut[-1]}\n" |
| 73 | + source += "};\n" |
| 74 | + |
| 75 | + fixed_point_lut_path: str = os.path.join( |
| 76 | + os.path.dirname(__file__), f"../../src/openvic-simulation/types/fixed_point/FixedPoint{lut_identifier}.hpp" |
| 77 | + ) |
| 78 | + with open(fixed_point_lut_path, "w", newline="\n") as file: |
| 79 | + file.write(source) |
| 80 | + |
| 81 | + print(f"`FixedPoint{lut_identifier}.hpp` generated successfully.") |
| 82 | + |
| 83 | + |
| 84 | +if __name__ == "__main__": |
| 85 | + parser = ArgumentParser( |
| 86 | + prog="Fixed Point Exp LUT Generator", description="Fixed-Point Exponential Look-Up Table generator" |
| 87 | + ) |
| 88 | + parser.add_argument( |
| 89 | + "-b", |
| 90 | + "--base", |
| 91 | + type=int, |
| 92 | + default=DEFAULT_DIVISOR_BASE, |
| 93 | + choices=range(2, 65), |
| 94 | + help="The base of the fixed point divisor", |
| 95 | + ) |
| 96 | + parser.add_argument( |
| 97 | + "-p", |
| 98 | + "--power", |
| 99 | + type=int, |
| 100 | + default=DEFAULT_DIVISOR_POWER, |
| 101 | + choices=range(1, 65), |
| 102 | + help="The power of the fixed point divisor", |
| 103 | + ) |
| 104 | + parser.add_argument( |
| 105 | + "-e", |
| 106 | + "--exp", |
| 107 | + type=float, |
| 108 | + default=DEFAULT_EXP_BASE, |
| 109 | + help="The base of the exponential function the look-up table represents", |
| 110 | + ) |
| 111 | + args = parser.parse_args() |
| 112 | + |
| 113 | + generate_exp_lut(args.base, args.power, args.exp) |
| 114 | + exit(0) |
0 commit comments