utils.py 4.58 KB
Newer Older
MischaD's avatar
MischaD committed
1
from .mylog import logger
MischaD's avatar
MischaD committed
2
3
import itertools
import numpy as np
MischaD's avatar
MischaD committed
4
import time
MischaD's avatar
MischaD committed
5
import math
MischaD's avatar
MischaD committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from fractions import Fraction

times = dict()


def timer(func, *args, **kwargs):
    """
    Three different methods to time a function.

    Best is used by default, because it's arguably the most important metric of time measurement.
    """

    def cur_time(func_name, time):
        return time

    def avg_time(func_name, time):
        global times
        if not times.get(func_name):
            times[func_name] = [1, time]
        else:
            avg = times[func_name][1]
            times[func_name][0] += 1
            x = times[func_name][0]
            times[func_name][1] = (x - 1) / x * avg + 1 / x * time
        return times[func_name][1]

    def best_time(func_name, time):
        if not times.get(func_name):
            times[func_name] = time
        else:
            if time < times[func_name]:
                times[func_name] = time
        return times[func_name]

    def wrapper(*args, **kwargs):
        start_time = time.time()
        ret = func(*args, **kwargs)
        elapsed_time = time.time() - start_time

        logger.info(
            " - Execution time of {0}: {1}".format(
                func.__name__, best_time(func.__name__, elapsed_time)
            )
        )
        return ret

    return wrapper
MischaD's avatar
MischaD committed
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110


def analyse_tensor_dimension(tensor_rank):
    """

    :param tensor_rank:
    :return:
    """

    first_entry = tensor_rank
    first_entries = [tensor_rank]

    possible_tensors = [first_entries]
    while first_entry > 2:
        first_entry = first_entry - 2
        first_entries = [first_entry]
        rest = tensor_rank - first_entry
        reduced_possible_tensors = analyse_tensor_dimension(rest)
        reduced_tensor_dimension = len(reduced_possible_tensors)
        for i in range(reduced_tensor_dimension):
            if reduced_possible_tensors[i][0] <= first_entry:
                possible_tensors.append(first_entries + reduced_possible_tensors[i])

    return possible_tensors


def get_group(dimension):
    def to_matrix(arr):
        """Convert an array of unit vectors to proper matrix."""

        dim = len(arr)
        M = np.zeros((dim, dim), dtype=np.int8)

        for col in range(dim):
            Row = arr[col] - 1
            M[Row][col] = 1

        return M

    unit_vectors = np.arange(1, dimension + 1)
    permutations = itertools.permutations(unit_vectors, dimension)

    sign_combinations = np.zeros((2**dimension, dimension))
    format_ = "0{}b".format(dimension)
    for i in range(2**dimension):
        binary = format(i, format_)
        sign_combinations[i] = np.array([2*int(binary[j]) - 1 for j in range(dimension)])

    group = []
    for permutation in permutations:
        M = to_matrix(permutation)
        for sign_combination in sign_combinations:
            group.append(np.multiply(sign_combination, M))
    transformation_amount = np.math.factorial(dimension) * 2 ** dimension
    assert len(group) == transformation_amount # Todo Exception
    return group


MischaD's avatar
MischaD committed
111
112
113
def contains(arr, list_of_arr):
    return any((arr == x).all() for x in list_of_arr)

MischaD's avatar
MischaD committed
114

MischaD's avatar
MischaD committed
115
116
117
def contains_in_sublist(arr, list_of_lists):
    return any(contains(arr, list_of_arr) for list_of_arr in list_of_lists)

MischaD's avatar
MischaD committed
118

MischaD's avatar
MischaD committed
119
120
121
122
123
124
125
126
127
128
129
130
131
def get_subshells(shell, group):
    subshells = []
    for velocity in shell:
        subshell = []
        for i in range(len(group)):
            new = np.dot(group[i], velocity)
            if contains(new, subshell):
                continue
            subshell.append(new)
        if not contains_in_sublist(velocity, subshells):
            subshells.append(subshell)

    return subshells
MischaD's avatar
MischaD committed
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163


def double_factorial(n):
    assert n >= 0
    if n == 0 or n == 1:
        return 1
    return n * double_factorial(n-2)


def lattice_sum(vector, velocities, rank):
    ret = 0
    for velocity in velocities:
        scalar_product = 0
        for dim in range(len(vector)):
            scalar_product += vector[dim] * velocity[dim]
        ret += scalar_product ** rank
    return ret / double_factorial(rank - 1)


def fill_rhs(max_rank, shells):
    rhs = []
    cols = max_rank // 2
    for k, rank in enumerate(np.arange(2, max_rank + 2, 2)):
        for j in range(shells[k]):
            rows = []
            for i in range(cols):
                c_s_power = 2 * i + 2
                rows.append(1 if c_s_power == rank else 0)
            rhs.append(rows)
    return np.array(rhs)


MischaD's avatar
MischaD committed
164
165
166
167
168
169
def approximate_ratio(x):
    if abs(x) < 1e-12:
        return 0
    denominator_limit = 1000000 if abs(x) >= 0.1 else int(1. / abs(x)) * 1000000
    return Fraction(x).limit_denominator(denominator_limit)

MischaD's avatar
MischaD committed
170
171
172