Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Views: 1833
Image: ubuntu2004
1
# Generator helpers
2
def mi_vars(*latex_names, random_order=True):
3
"""
4
Given one or more `latex_names` of strings, returns a tuple
5
of Sage variables. `random_order` names them so that they appear
6
in expressions in a random order.
7
"""
8
stamp = randrange(100000,999999)
9
indices = list(range(len(latex_names)))
10
if random_order:
11
shuffle(indices)
12
import string
13
random_letter = choice(list(string.ascii_lowercase))
14
return (var(f"{random_letter}_mi_var_{stamp}_{indices[i]}", latex_name=name) for i, name in enumerate(latex_names))
15
16
def shuffled_equation(*terms):
17
"""
18
Represents the equation sum(terms)==0, but with terms shuffled randomly
19
to each side.
20
"""
21
new_equation = (SR(0)==0)
22
for term in terms:
23
if choice([True,False]):
24
new_equation += (SR(term)==0)
25
else:
26
new_equation += (0==-SR(term))
27
return new_equation*choice([-1,1])
28
29
def base64_graphic(obj, file_format="svg"):
30
"""
31
Generates Base64 encoding of the graphic in the requested file_format.
32
"""
33
if not isinstance(obj,Graphics):
34
raise TypeError("Only graphics may be encoded as base64")
35
if file_format not in ["svg", "png"]:
36
raise ValueError("Invalid file format")
37
filename = tmp_filename(ext=f'.{file_format}')
38
obj.save(filename)
39
with open(filename, 'rb') as f:
40
from base64 import b64encode
41
b64 = b64encode(f.read())
42
return b64
43
44
def data_url_graphic(obj, file_format="svg"):
45
"""
46
Generates Data URL representing the graphic in the requested file_format.
47
"""
48
b64 = base64_graphic(obj, file_format=file_format).decode('utf-8')
49
if file_format=="svg":
50
file_format = "svg+xml"
51
return f"data:image/{file_format};base64,{b64}"
52
53
def latex_system_from_matrix(matrix, variables="x", alpha_mode=False, variable_list=[]):
54
# Augment with zero vector if not already augmented
55
if not matrix.subdivisions()[1]:
56
matrix=matrix.augment(zero_vector(QQ, len(matrix.rows())), subdivide=true)
57
num_vars = matrix.subdivisions()[1][0]
58
# Start using requested variables
59
system_vars = variable_list
60
# Conveniently add xyzwv if requested
61
if alpha_mode:
62
system_vars += list(var("x y z w v"))
63
# Finally fall back to x_n as needed
64
system_vars += [var(f"{variables}_{n+1}") for n in range(num_vars)]
65
# Build matrix
66
latex_output = "\\begin{matrix}\n"
67
for row in matrix.rows():
68
if row[0]!= 0:
69
latex_output += latex(row[0]*system_vars[0])
70
previous_terms = True
71
else:
72
previous_terms = False
73
for n,cell in enumerate(row[1:num_vars]):
74
latex_output += " & "
75
if cell < 0:
76
latex_output += " - "
77
elif cell > 0 and previous_terms:
78
latex_output += " + "
79
latex_output += " & "
80
if cell != 0:
81
latex_output += latex(cell.abs()*system_vars[n+1])
82
if not previous_terms:
83
previous_terms = bool(cell!=0)
84
if not previous_terms:
85
latex_output += " 0 "
86
latex_output += " & = & "
87
latex_output += latex(row[num_vars])
88
latex_output += "\\\\\n"
89
latex_output += "\\end{matrix}"
90
return latex_output
91
92
def latex_solution_set_from_matrix(matrix):
93
# Augment with zero vector if not already augmented
94
if not matrix.subdivisions()[1]:
95
matrix=matrix.augment(zero_vector(QQ, len(matrix.rows())), subdivide=true)
96
if (len(matrix.columns())-1) in matrix.pivots():
97
return r" \{\} "
98
solution_dimension = len(matrix.columns())-1
99
free_variables = list(var("a b c d e f g h i j"))
100
kernel_basis=matrix.subdivision(0,0).right_kernel(basis='pivot').basis()
101
span = sum([kernel_basis[i]*free_variables[i] for i in range(len(kernel_basis))])
102
offset = zero_vector(QQ,solution_dimension)
103
for row_index,col_index in enumerate(matrix.pivots()):
104
offset[col_index] = matrix.rref().columns()[-1][row_index]
105
rep = column_matrix(span+offset)
106
predicate = ",".join([latex(a) for a in free_variables[:len(kernel_basis)]])
107
return r" \left\{ " + latex(rep) + r" \,\middle|\, " + predicate + r" \in\mathbb R \right\} "
108
109
def json_ready(obj):
110
if isinstance(obj,str) or isinstance(obj,bool):
111
return obj
112
elif isinstance(obj,list):
113
return [json_ready(item) for item in obj]
114
elif isinstance(obj,dict):
115
return {key:json_ready(obj[key]) for key in obj.keys()}
116
else:
117
return str(latex(obj))
118
119
def simple_random_matrix_of_rank(rank,rows=1,columns=1,augmented=False):
120
# get extra rows and columns, at least zero
121
extra_rows = max(0,rows-rank)
122
extra_columns = max(0,columns-rank)
123
# create matrix with terms between -5 and 5 inclusive, rank in every column, and integer entries RREF
124
A = random_matrix(QQ,rank+extra_rows,rank,algorithm='echelonizable',rank=rank,upper_bound=6)
125
# randomly choose pivot indices where dependent columns are injected afterward
126
inserts = [randrange(rank) for _ in range(extra_columns)]
127
# pedagogically we want final column to be dependent at least half the time
128
if extra_columns>0 and choice([True,False]):
129
inserts[0]=rank-1
130
# we'll insert columns backwards to avoid messing up where to inject columns
131
inserts.sort(reverse=True)
132
# we won't repeat dependent columns
133
inserted_columns = []
134
for pivot in inserts:
135
while True:
136
# get random numbers for pivot rows
137
rref_pivot_entries = [randrange(-3,4) for _ in range(pivot+1)]
138
# ensure at least one is nonzero
139
rref_pivot_entries[randrange(pivot+1)] = randrange(1,4)*choice([-1,1])
140
# create vector
141
dependent_vector = sum([rref_pivot_entries[_]*A.column(_) for _ in range(pivot+1)])
142
if dependent_vector not in inserted_columns:
143
inserted_columns.append(dependent_vector)
144
A = matrix(A.columns()[:pivot+1]+[dependent_vector]+A.columns()[pivot+1:]).transpose()
145
break
146
if augmented:
147
A.subdivide([],[columns-1])
148
return A
149
150
import sys,json,os
151
if sys.argv[4]:
152
generator_directory_path = sys.argv[1]
153
current_dir = os.getcwd()
154
os.chdir(generator_directory_path)
155
generator_filename = sys.argv[2]
156
amount = int(sys.argv[3])
157
public = (sys.argv[4]=="PUBLIC")
158
load(generator_filename) # provides generator() function
159
seeds = []
160
for i in range(amount):
161
if public:
162
seed = i % 1000
163
else:
164
set_random_seed()
165
seed = randrange(1000,10000)
166
set_random_seed(seed)
167
seeds.append({"seed":int(seed),"values":json_ready(generator())})
168
print(json.dumps(seeds))
169
os.chdir(current_dir)
170
171