-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfactorization_function.py
184 lines (156 loc) · 7.28 KB
/
factorization_function.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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# -*- coding: utf-8 -*-
import sys
from sage.all import *
import datetime
import os
import os.path
from benchmark import *
###
# This file will usually not need any alteration. Create subclasses of FactorizationFunction.
###
class FactorizationFunctionCharacteristics(object):
def __init__(self):
self.canFactorizePrimes = False
self.canFactorizeNonPrimes = False
def __str__(self):
return "Factorization Function Characteristics <Can factorize primes: %c, Can factorize non-primes: %c>"%(self.canFactorizePrimes, self.canFactorizeNonPrimes)
def __repr__(self):
return "Factorization Function Characteristics <Can factorize primes: %c, Can factorize non-primes: %c>"%(self.canFactorizePrimes, self.canFactorizeNonPrimes)
# FactorizationFunction is inherited to create benchmarkable, testable factorization functions
class FactorizationFunction(object):
@classmethod
# Return characteristics of the specific algorithm
def getCharacteristics(self):
return None
@classmethod
# Run factorization
# n: number to factor
# returnBenchmark: return factors if False, tuple of (factors, benchmark) if True
def factorize(self, n, returnBenchmark=False):
return (None, None)
@classmethod
# Runs benchmark on the factorization function
# iterations: number of times to run the function
# numberOfFactors: number of factors included in factorized number
# factorLowerLimit: lower limit from which primes are generated
# factorUpperLimit: upper limit from which primes are generated
# Returns tuple (times, iterations)
def benchmark(self, numberSuite, iterations=10, optionalArgs={}, start=2, end=None, skipFactors=None, mode="factors"):
benchmarks = []
description, suite = numberSuite
modeLine = "Unknown"
if mode == "factors":
modeLine = "Number of factors"
elif mode == "bits":
modeLine = "Number of bits"
now = datetime.datetime.now()
name = str(self)
name = name[name.rfind(".")+1:-2]
filename = "./benchmarks/%s_%s.txt"%(name, now.strftime('%Y-%m-%d_%H:%M:%S'))
originalFilename = filename[:-4]
serial = 1
while os.path.isfile(filename):
filename = "%s_%d.txt"%(originalFilename, serial)
serial += 1
def writeToFile(line):
mode = "a" if os.path.exists(filename) else "w"
handle = open(filename, mode)
handle.write(line + "\n")
handle.close()
# Write header and description to file
def formatParameter(parameter):
string = str(parameter)
if "<function" in string:
string = string.split(" ")[1]
return string
def formatParameters(parameters):
if isinstance(parameters, list):
return "[%s]"%', '.join(map(formatParameter, parameters))
return str(parameters)
writeToFile("# %s"%name + (" (%s)"%",".join("%s: %s"%(pair[0], formatParameters(pair[1])) for pair in optionalArgs.items()) if len(optionalArgs) > 0 else ""))
writeToFile("# %s"%description)
writeToFile("%s:Number to factorize:Time taken:Iterations taken"%modeLine)
for numberOfFactors, numbers in suite:
if numberOfFactors < start:
continue
if end is not None and numberOfFactors > end:
continue
if skipFactors is not None:
if callable(skipFactors) and skipFactors(numberOfFactors):
continue
bs = []
for i in range(iterations):
for n, factors in numbers:
resultingFactors, b = self.factorize(n, true, **optionalArgs)
# Only take into account correct factorizations
if sorted(resultingFactors) == sorted(factors):
bs.append(b)
formattedTime = ",".join("%s-%f"%pair for pair in b.totalTime.items())
formattedIterations = ",".join("%s-%d"%pair for pair in b.iterations.items())
writeToFile("%d:%d:%s:%s"%(numberOfFactors, n, formattedTime, formattedIterations))
benchmarks.append((numberOfFactors, bs))
# Result, one tuple per number of factors:
# (numberOfFactors, minimum benchmark, maximum benchmark, average benchmark)
res = [(bs[0], Benchmark.min(bs[1]), Benchmark.max(bs[1]), Benchmark.average(bs[1])) for bs in benchmarks]
return res
@classmethod
def testFactorization(self, cases, truths, optionalArgs):
passed = True
for i in range(len(cases)):
n = cases[i]
truth = sorted(truths[i])
result = sorted(self.factorize(n, **optionalArgs))
factorString = "*".join(str(x) for x in truth)
def togglePassed(passed):
if passed:
print u"✘"
passed = False
return passed
if result is None:
passed = togglePassed(passed)
print "Can factorize %d=%s: ✘"%(n, factorString)
print "\t Expected: ", truth
print "\t Got: None. Most likely means that the function does not support the given input"
elif result != truth:
passed = togglePassed(passed)
print u"Can correctly factor %d=%s: ✘"%(n, factorString)
print "\t Expected: ", truth
print "\t Got: ", result
if passed:
print u"✓"
@classmethod
# Runs test on the factorization function
# optionalArgs is expected to be a map and is passed to factorize function
def test(self, optionalArgs={}):
testFunctions = filter(lambda x : x.find("test") == 0 and x != "test" and x != "testFactorization", dir(self))
if len(testFunctions) > 0:
print "=== Common Tests ==="
print "Can run factorization function: ",
try:
self.factorize(15)
print u"✓"
except:
print u"✘"
print "Will abort tests due to error in factorization function"
return
c = self.getCharacteristics()
if c.canFactorizePrimeComposites:
print "Can factorize one or more primes: ",
cases = [2, 3, 5, 7, 11, 15, 21, 25, 45, 77, 121, 169, 21853]
truths = [[1, 2], [1, 3], [1, 5], [1, 7], [1, 11], [1, 3, 5], [1, 3, 7], [1, 5, 5], [1, 3, 3, 5], [1, 7, 11], [1, 11, 11], [1, 13, 13], [1, 13, 41, 41]]
self.testFactorization(cases, truths, optionalArgs)
else:
print u"Can factorize one or more primes: ✘ (Not supported)"
if c.canFactorizeEvenComposites:
print "Can factorize one or more non-primes: ",
cases = [2, 4, 12, 20, 30]
truths = [[1, 2], [1, 2, 2], [1, 2, 2, 3], [1, 2, 2, 5], [1, 2, 3, 5]]
self.testFactorization(cases, truths, optionalArgs)
else:
print u"Can factorize one or more non-primes: ✘ (Not supported)"
# Run class specific tests
if len(testFunctions) > 0:
print "\n=== Algorithm Specific Tests ==="
for func in testFunctions:
method = getattr(self, func)
method()