tueda / formset

A "form.set" generator.
MIT License
2 stars 0 forks source link

License and library usage #2

Closed magv closed 3 years ago

magv commented 3 years ago

Hi, Takahiro. I'd like to start using formset.py in pySecDec to generate form.set automatically. To this end, I'd like to have your permission, so could you choose a license for it?

Also, currently the parts of the code that search for the optimal parameters are in main(); I'd like to factorize them so that formset.py could be used a library. For the moment I'm doing this:

--- formset.py.orig 2021-03-01 17:52:13.399899689 +0100
+++ formset.py  2021-03-01 17:45:58.724173153 +0100
@@ -1,8 +1,6 @@
 #!/bin/sh
-""":" .
-
-exec python "$0" "$@"
-"""
+# formset.py by Takahiro Ueda
+# https://github.com/tueda/formset

 from __future__ import print_function

@@ -510,6 +508,66 @@
             largesize + smallextension + 3 * termsinsmall * self._ptrsize + sortiosize
         )

+def search(setup, memory):
+    sp0 = setup.copy()
+    # Presumably increasing MaxTermSize requires increasing WorkSpace, too.
+    sp0.workspace = max(sp0.workspace, sp0.maxtermsize * 250)
+    if sp0.calc() >= memory:
+        return sp0
+    # Optimize the memory usage by bisection.
+    max_iteration = 50
+    def f(x):
+        # type: (float) -> Tuple[int, Setup]
+        # Hopefully monochrome increasing.
+        sp = sp0.copy()
+        sp.smallsize = int(sp.smallsize * x)
+        sp.largesize = int(sp.largesize * x)
+        sp.termsinsmall = int(sp.termsinsmall * x)
+        sp.scratchsize = int(sp.scratchsize * x)
+        m = sp.calc()
+        #if args.human_readable:
+        #    m = round_human_readable(m, True, False)
+        return (-(memory - m), sp)
+    x1 = 1.0
+    x2 = None  # type: Optional[float]
+    y1 = f(x1)[0]
+    y2 = None  # type: Optional[int]
+    for _i in range(max_iteration):
+        if x2 is None:
+            if y1 < 0:
+                x = x1 * 2.0
+                y = f(x)[0]
+                if y > 0:
+                    x2 = x
+                    y2 = y
+                else:
+                    x1 = x
+                    y1 = y
+            else:
+                x = x1 * 0.5
+                y = f(x)[0]
+                if y < 0:
+                    x2 = x1
+                    y2 = y1
+                    x1 = x
+                    y1 = y
+                else:
+                    x1 = x
+                    y1 = y
+        else:
+            x = (x1 + x2) * 0.5
+            y = f(x)[0]
+            if y < 0:
+                x1 = x
+                y1 = y
+            else:
+                x2 = x
+                y2 = y
+        if x2 is not None:
+            assert y2 is not None
+            assert x1 < x2 and y1 < y2
+    return f(x1)[1]
+

 def main():
     # type: () -> None

If you're interested, I can rewrite main() to use search() and submit a pull request or something. I'd prefer not to diverge from your code.

tueda commented 3 years ago

Thanks for your suggestion!

How about the MIT license? If this is fine, then I will add the license declaration to the beginning of formset.py such that you can pick this file up for your project.

I'm happy with rewriting main function and split search from it. It will be nice if you can make a pull request for it. Perhaps it would be more favourable to define search as

def search(setup, total_memory):
    # type: (Setup, float) -> Tuple[Setup, float]
    """Search for the optimized setup parameters for the given memory amount."""
    ...

in such a way that this function returns a set of optimized setup parameters and also its actual memory usage. (I guess they are needed for the main function, though I don't remember the details.)

As you can see in .pre-commit-config.yaml, this repository uses pre-commit for lining: black, flake8, mypy and gitlint. To set up this, you need to install pre-commit and

pre-commit install
pre-commit install --hook-type commit-msg

To run the linters:

pre-commit run --all-files

The git commit message should use the Conventional Commits, for example,

refactor: split a search function from the main routine
magv commented 3 years ago

MIT sounds great. I'll prepare a pull request with search() in a while. The search() above is not doing 100% the same thing main() does, but the difference is minor, and I'll try to remove it (once I'll remember what it was :) ).

tueda commented 3 years ago

The license declaration has been added. There were also some changes in formset.py for tweaking the linter settings (the assert statements were removed).