@mtf/

Dimensional Analysis Challenge-1

Python

This program reduces physics expressions and returns the resulting SI Unit when applicable.

fork
loading
Files
  • main.py
main.py
1
2
3
4
5
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
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
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
from functools import reduce

units = {
    'kg * m * s ** -2': 'N', #newton
    's ** -1': 'Hz', #hertz also becquerel (Bq)
    'kg * m ** -1 * s ** -2': 'Pa', #pascal
    'kg * m ** 2 * s ** -2': 'J', #joule
    'kg * m ** 2 * s ** -3': 'W', #watt
    's * A': 'C', #coulomb
    'kg * m ** 2 * s ** -3 * A ** -1': 'V', #volt
    'kg ** -1 * m ** -2 * s ** 4 * A ** 2': 'F', #farad
    'kg * m ** 2 * s ** -3 * A ** -2': 'Ω', #ohm
    'kg ** -1 * m ** -2 * s ** 3 * A ** 2': 'S', #siemens
    'kg * m ** 2 * s ** -2 * A ** -1': 'Wb', #weber
    'kg * s ** -2 * A ** -1': 'T', #tesla
    'kg * m ** 2 * s ** -2 * A ** -2': 'H', #henry
    'K':'°C', #degree Celcius
    'cd * sr': 'lm', #lumen
    'cd * sr * m ** -2': 'lx', #lux
    'm ** 2 * s ** -2': 'Gy', #gray also sievert (Sv)
    'mol * s ** -1': 'kat' #katal
}

base_units = {
    'mol': [], #mole
    'cd': [], #candela
    'sr': [], #steradian* (m ** 2 * m ** -2) = 1
    'kg': [], #kilogram
    'm': [], #meter
    's': [], #second
    'A': [], #ampere
    'K': [], #kelvin
    'rad': [] #radian* (m ** 1 * m ** -1) = 1
}

### *While radians and steradians are not technicall base units
### in physics, their formal definitions in base units of
### m * m ** -1 and m ** 2 * m ** -2 respectively prohibit them
### being referred to in base units as they would resolve to 1
### in each case.

multiplier = {
    'multiplier': 1
}

def execute_test_procedure():
    for i in range (len(test_values)):
        exp_to_reduce = test_values[i][1]
        exp_to_reduce = exp_to_reduce.replace('Bq', 'Hz')
        exp_to_reduce = exp_to_reduce.replace('Sv', 'Gy')
        reduced_value = find_unit(exp_to_reduce)
        if 'Bq' in test_values[i][1] and 'Hz' in reduced_value: reduced_value = reduced_value.replace('Hz', 'Bq')
        if 'Sv' in test_values[i][1] and 'Gy' in reduced_value: reduced_value = reduced_value.replace('Gy', 'Sv')    
        print('{}({}) reduces to: {} {}'.format(test_values[i][0], test_values[i][1], test_values[i][0], reduced_value))

def check_for_multiples(expression):
    max_val = max(base_units.values())[0]
    for i in range(2, max_val + 1):
        for si_unit in units.values():
            clear_base_unit_lists()
            test_unit_pos = parse_expression('{} ** {}'.format(si_unit, i))
            clear_base_unit_lists()
            test_unit_neg = parse_expression('{} ** {}'.format(si_unit, -i))
            if test_unit_pos == expression:
                return '{}^{}'.format(si_unit, i)
            if test_unit_neg == expression:
                return '{}^{}'.format(si_unit, -i)
    return ' Houston, we have a problem indeed. No such SI Unit as ({})'.format(expression)

def reduce_units(which_list, operator, next_val):
    if which_list in units.values():
        formal_def = list(units.keys())[list(units.values()).index(which_list)].split(' ')
        if operator == '**':
            multiplier['multiplier'] = int(next_val)
        build_exponent_lists(formal_def)
        multiplier['multiplier'] = 1
        return 4 if operator == '**' else 2
    if operator == '**':
        base_units[which_list].append(int(next_val) * multiplier['multiplier'])
        return 4
    else:
        base_units[which_list].append(multiplier['multiplier'])
        return 2

def build_unit(num, unit):
    if num == 0: return ''
    if num == 1: return unit + ' * '
    return '{} ** {} * '.format(unit, num)

def build_exponent_lists(expression_list):
    i = 0
    while i < len(expression_list):
        if expression_list[i] != '*' and expression_list[i] != '**':
            operator = expression_list[i + 1] if i < len(expression_list)  - 1 else ''
            next_val = expression_list[i + 2] if i < len(expression_list) - 2 else ''
            i += reduce_units(expression_list[i], operator, next_val)

def clear_base_unit_lists():
    for base_unit in base_units:
        del base_units[base_unit][:]

def parse_expression(exp):
    expression_list = exp.split(' ')
    build_exponent_lists(expression_list)

    unit = ''
    for base_unit in base_units:
        if base_units[base_unit]:
            base_units[base_unit] = [reduce((lambda x, y : x + y), base_units[base_unit])]
            unit += build_unit(base_units[base_unit][0], base_unit)

    return unit.strip(' * ')    

def find_unit(exp):
    unit = parse_expression(exp)
    if unit in units: 
        final_unit = units[unit]
    else:
        final_unit = check_for_multiples(unit)
        clear_base_unit_lists()
        return final_unit
    clear_base_unit_lists()
    return final_unit

# Test Cases:
test_values = [[2,'kg * m * s ** -2 * kg * m * s ** -2 * s ** 2 * kg ** -1 * m ** -1'], #expect 2N
[5, 's ** -1 * kg ** 2 * N * m ** -1 * Pa * s ** 2 * kg ** -1 * kg ** -2 * m * kg ** -1 * s ** 2'], #expect 5Hz
[11, 's ** -1 * kg ** 2 * N * m ** -1 * Pa * s ** 2 * kg ** -1 * kg ** -2 * m * J * kg ** -1 * s ** 2'], #expect 11W
[42, 'kg * m ** 2 * s ** -2'], #expect 42J
[6, 'kg * m ** -1 * s ** -2 * N * kg ** -1 * m * s ** 2'], #expect 6N
[17, 'Hz * N * J * Pa'], #expect 17 Houston, we have a problem indeed. No such SI Unit as (kg ** 3 * m ** 2 * s ** -7)
[5, 'kg * m ** -1 * s ** -2 * N * kg ** -1 * m ** -1 * s ** 2'], #expect 5Pa
[14, 'kg * m'], #expect 14 Houston, we have a problem indeed. No such SI Unit as (kg * m)
[1, 'N'], #expect 1N
[4, 'N ** -3'], #expect N^-3
[3, 'Pa'], #expect 3Pa
[7, 'W ** 2'], #expect 7W
[22, 'Hz'], #expect 22Hz
[23, 'Bq * Bq * Bq ** -1'], #expect 23 Bq^2
[19, 'J'], #expect 19J
[12, 'K'], #expect 12°C
[1, 'kg'], #expect 1 Houston, we have a problem indeed. No such SI Unit as (kg)
[27, 'W * J'], #expect 27 Houston, we have a problem indeed. No such SI Unit as (kg ** 2 * m ** 4 * s ** -5)
[15, 'J * s ** -1'], #expect 15W
[2, 'kg ** -1 * m ** -2 * s ** 4 * A ** 2'], #expect 2F
[9, 'V * A ** -1'], #expect 9Ω
[4, 'F * J * kat'], #expect 4 Houston, we have a problem indeed. No such SI Unit as (s * A ** 2 * mol)
[35, 'kg * s ** -2 * A ** -1 * F * kg ** 2 * N * A ** -3 * s ** -2 * m * kg ** -2 * A'], #expect 35T
[18, 'lm * kg ** -1 * s ** 2 * N * m ** -3'], #18lx
[13, 'mol * s ** -1 * kg * m ** -3 * m ** 2 * kg ** -2 * N * s ** 2'], #expect 13kat
[21, 's ** 3 * kg ** -1 * A ** 3 * H * m ** -2'], #expect 21C
[2, 'N ** 2 * N ** -1'], #expect 2N
[52, 'N ** 2 * C ** 3 * N ** -1 * kg ** -1 * m ** -1 * s ** 2'], #expect 52C^3
[14, 'Pa ** 2 * N ** -1 * Pa * Pa ** -3 * N * K'], #expect 14°C
[22, 'K * m ** 2 * s * s ** -1 * m ** -2']] #22°C

execute_test_procedure()