Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Project: RNApolys
Views: 491
1
from sage.all import *
2
3
# Backend Sage machinery to produce plots of polytopes
4
@cached_method
5
def sliced_cones_2(poly, eqn, vecprojector):
6
"""
7
Return two-dimensional slices of the normal fan of a polytope along a specified plane (helper method)
8
9
INPUT:
10
- ``eqn`` -- Equation defining a plane in R3
11
- ``vecprojector`` -- Anonymous function projecting a vector from R3 to R2
12
"""
13
slices3 = poly.d1_slices()
14
subspace = Polyhedron(eqns = [eqn])
15
16
slices2 = set()
17
for slice3 in slices3:
18
# Find the intersection of this cone with the hyperplanes
19
slice2 = slice3.intersection(subspace)
20
21
# If the result does not have any area, we're done with this slice, so we move on to the next one
22
if slice2.dimension() < 2:
23
continue
24
25
# The resulting coneslice is a two-dimensional polyhedron, but it still lives in Q3, so let's project down to Q2
26
newverts = lambda polyslice: [vecprojector(vert) for vert in polyslice.vertices()] # Projects the defining vertices of a slice into Q2
27
newrays = lambda polyslice: [vecprojector(ray) for ray in polyslice.rays()] # Projects the defining rays of a slice into Q2
28
polyprojector = lambda polyslice: Polyhedron(vertices = newverts(polyslice), rays = newrays(polyslice)) # Projects a polytope from Q3 to Q2 using the helper functions we just defined
29
30
# We can then apply polyprojector to our slice to move it down to Q2
31
projslice = polyprojector(slice2)
32
33
# For future use, we'll store the original cone in Q4 and the slice in Q3 as a member of this object
34
projslice.original_cone = slice3.original_cone
35
projslice.original_slice = slice3
36
37
# As well as the original vertex and structure associated to those cones
38
projslice.original_vertex = poly.vertex_from_cone(slice3.original_cone)
39
projslice.original_structure = poly[projslice.original_vertex]
40
41
# And, finally, we add this slice to our list
42
slices2.add(projslice)
43
44
# Once we've finished the loop, all the slices have been processed, so we return the resulting container
45
return slices2
46
47
@cached_method
48
def sliced_cones_a(poly, a = 0):
49
"""
50
Return the two-dimensional slices of the normal fan of a polytope with fixed a.
51
52
INPUT:
53
- ``poly`` -- A Polytope in Q4
54
- ``a`` -- (default: 0) The fixed value of a at which to slice
55
"""
56
# a needs to be rational
57
a = QQ(a)
58
59
eqn = (-a, 1, 0, 0)
60
vecprojector = lambda vec: [vec[1], vec[2]]
61
62
return sliced_cones_2(poly, eqn, vecprojector)
63
64
@cached_method
65
def sliced_cones_b(poly, b = 0):
66
"""
67
Return the two-dimensional slices of the normal fan of a polytope with fixed b.
68
69
INPUT:
70
- ``poly`` -- A Polytope in Q4
71
- ``b`` -- (default: 0) The fixed value of b at which to slice
72
"""
73
# b needs to be rational
74
b = QQ(b)
75
76
eqn = (-b, 0, 1, 0)
77
vecprojector = lambda vec: [vec[0], vec[2]]
78
return sliced_cones_2(poly, eqn, vecprojector)
79
80
@cached_method
81
def sliced_cones_c(poly, c = 0):
82
"""
83
Return the two-dimensional slices of the normal fan of a polytope with fixed a.
84
85
INPUT:
86
- ``poly`` -- A Polytope in Q4
87
- ``c`` -- (default: 0) The fixed value of c at which to slice
88
"""
89
# a needs to be rational
90
c = QQ(c)
91
92
eqn = (-c, 0, 0, 1)
93
vecprojector = lambda vec: [vec[0], vec[1]]
94
return sliced_cones_2(poly, eqn, vecprojector)
95
96
@cached_method
97
def region_graph(regions):
98
import itertools
99
from collections import defaultdict
100
edge_dict = {region:[] for region in regions}
101
for pair in itertools.combinations(regions, 2):
102
a, b = pair
103
if a != b and not a.intersection(b).is_empty():
104
edge_dict[a].append(b)
105
106
result = Graph(edge_dict)
107
return result
108
109
@cached_method
110
def bounded_regions(regions, points_to_include, xbounds = None, ybounds = None):
111
"""
112
Plot a collection of cone slices in R2
113
"""
114
import itertools
115
116
vertices = [vert for region in regions for vert in region.vertices()] # Find all the vertices to help us construct the bounding box
117
vertices.extend(points_to_include) # Append any marked points to ensure they are visible
118
119
# Identify the maximum values of x and y for the box
120
xvals = [abs(vert[0]) for vert in vertices]
121
xmax = max(xvals)
122
xmin = -xmax
123
124
yvals = [abs(vert[1]) for vert in vertices]
125
ymax = max(yvals)
126
ymin = -ymax
127
128
auto_box_scale = 3/2
129
if xbounds is None:
130
xbounds = [auto_box_scale * xmin, auto_box_scale * xmax]
131
132
if ybounds is None:
133
ybounds = [auto_box_scale * ymin, auto_box_scale * ymax]
134
135
bounding_box = Polyhedron(itertools.product(xbounds, ybounds))
136
137
bounded_regions = set()
138
for region in regions:
139
bounded_region = bounding_box.intersection(region)
140
141
# Discard the region if it's empty
142
if bounded_region.dimension() < 2:
143
continue
144
145
# Otherwise, add some metadata and insert it in the result set
146
bounded_region.original_cone = region.original_cone # add the original cone (fidbc)
147
bounded_region.original_region = region # also add the original region [maybe redundant!] (fidbc)
148
bounded_region.original_vertex = region.original_vertex
149
bounded_region.original_structure = region.original_structure
150
bounded_regions.add(bounded_region)
151
152
return bounded_regions
153
154
# Colorblind-friendly palette from http://bconnelly.net/2013/10/creating-colorblind-friendly-figures/
155
six_nice_colors = (Color(0.9, 0.6, 0), Color(0.35, 0.7, 0.9), Color(0, 0.6, 0.5), Color(0.95, 0.9, 0.25), Color(0, 0.45, 0.7), Color(0.8, 0.4, 0), Color(0.8, 0.6, 0.7))
156
157
@cached_method
158
def colored_regions(regions, points_to_mark, xbounds = None, ybounds = None, plot_colors = six_nice_colors):
159
"""
160
"""
161
from sage.graphs.graph_coloring import first_coloring
162
163
# Get the regions
164
regions = bounded_regions(regions, points_to_mark, xbounds, ybounds)
165
166
# Color the slices using a graph coloring algorithm
167
G = region_graph(regions)
168
169
n_colors = len(plot_colors)
170
region_color_list = first_coloring(G)#, n_colors)
171
region_color_dict = {region: plot_colors[i] for i in range(len(region_color_list)) for region in region_color_list[i]}
172
173
# Store the colors
174
for region in regions:
175
region.color = region_color_dict[region]
176
177
return regions
178
179
#@cached_method
180
def accuracy_colored_regions(regions, accuracy, points_to_mark, xbounds = None, ybounds = None, colormap = colormaps['hot']):
181
"""
182
"""
183
# Get the regions
184
regions = bounded_regions(regions, points_to_mark, xbounds, ybounds)
185
186
# Color the slices using a graph coloring algorithm
187
region_color_dict = {region: colormap(accuracy[tuple(region.original_vertex)])[:3] for region in regions}
188
189
# Store the colors
190
for region in regions:
191
region.color = region_color_dict[region]
192
193
return regions
194
195
@cached_method
196
def region_plots(regions, points_to_mark, plot_title = None, add_slice_count_to_title = True, xbounds = None, xlabel = None, ybounds = None, ylabel = None, figsize = (4, 3), plot_colors = six_nice_colors):
197
"""
198
"""
199
200
plotted_points = [point2d(point, size=30, zorder=10, color=colors['black']) for point in points_to_mark]
201
plotted_regions = [region.projection().render_fill_2d(color = region.color) for region in colored_regions(regions, points_to_mark, xbounds, ybounds, plot_colors = plot_colors)]
202
203
if add_slice_count_to_title:
204
plot_title += ": " + str(len(plotted_regions)) + " slices visible"
205
206
#theplot = plot(plotted_points + plotted_regions, frame = True, axes_labels = [xlabel, ylabel], title = plot_title, figsize = figsize)
207
theplot = sum(plotted_regions)
208
for pp in plotted_points:
209
theplot += pp
210
theplot.SHOW_OPTIONS['frame']=True
211
theplot.SHOW_OPTIONS['axes_labels']=[xlabel, ylabel]
212
theplot.SHOW_OPTIONS['title']=plot_title
213
theplot.SHOW_OPTIONS['figsize']=figsize
214
theplot.axes_labels_size(1)
215
theplot.fontsize(8)
216
return theplot
217
218
#@cached_method
219
def accuracy_region_plots(regions, accuracy, points_to_mark, plot_title = None, add_slice_count_to_title = True, xbounds = None, xlabel = None, ybounds = None, ylabel = None, figsize = (4, 3), colormap=colormaps['hot']):
220
"""
221
"""
222
223
plotted_points = [point2d(point, size=30, zorder=10, color=colors['black']) for point in points_to_mark]
224
plotted_regions = [region.projection().render_fill_2d(color = region.color) for region in accuracy_colored_regions(regions, accuracy, points_to_mark, xbounds, ybounds, colormap)]
225
226
if add_slice_count_to_title:
227
plot_title += ": " + str(len(plotted_regions)) + " slices visible"
228
229
#theplot = plot(plotted_points + plotted_regions, frame = True, axes_labels = [xlabel, ylabel], title = plot_title, figsize = figsize)
230
theplot = sum(plotted_regions)
231
for pp in plotted_points:
232
theplot += pp
233
theplot.SHOW_OPTIONS['frame']=True
234
theplot.SHOW_OPTIONS['axes_labels']=[xlabel, ylabel]
235
theplot.SHOW_OPTIONS['title']=plot_title
236
theplot.SHOW_OPTIONS['figsize']=figsize
237
theplot.axes_labels_size(1)
238
theplot.fontsize(8)
239
return theplot
240
241
alabel = "multibranch loop initiation penalty ($a$)"
242
blabel = "unpaired base penalty ($b$)"
243
clabel = "branching helix penalty ($c$)"
244
245
@cached_method
246
def sliced_cone_plots_a(poly, a = 0, bbounds = None, cbounds = None, plot_title = None, plot_colors = six_nice_colors):
247
"""
248
Plot the two-dimensional slices of the normal fan of a polytope with fixed a.
249
250
INPUT:
251
- ``poly`` -- A Polytope in R4
252
- ``a`` -- (default: 0) The fixed value of a to use
253
- ``bbounds`` -- (default: automatic) The range of b values to plot
254
- ``cbounds`` -- (default: automatic) The range of c values to plot
255
- ``plot_title`` -- (default: None) Title for the plot
256
"""
257
# Get the slices
258
slices = sliced_cones_a(poly, a)
259
260
classical_points = ((0, 0.4),)
261
262
if plot_title is not None:
263
formatted_title = plot_title + "\n"
264
else:
265
formatted_title = ""
266
267
formatted_title += "a = " + str(a)
268
269
plots = region_plots(slices,
270
points_to_mark = classical_points,
271
plot_title = formatted_title,
272
add_slice_count_to_title = True,
273
xbounds = bbounds, xlabel = blabel,
274
ybounds = cbounds, ylabel = clabel,
275
plot_colors = plot_colors)
276
277
return plots
278
279
#@cached_method
280
def sliced_cone_plots_b(poly, b = 0, abounds = None, cbounds = None, plot_title = None, plot_colors = six_nice_colors):
281
"""
282
Plot the two-dimensional slices of the normal fan of a polytope with fixed b.
283
284
INPUT:
285
- ``poly`` -- A Polytope in R4
286
- ``b`` -- (default: 0) The fixed value of b to use
287
- ``abounds`` -- (default: automatic) The range of a values to plot
288
- ``cbounds`` -- (default: automatic) The range of c values to plot
289
- ``plot_title`` -- (default: None) Title for the plot
290
"""
291
# Get the slices
292
slices = sliced_cones_b(poly, b)
293
294
classical_points = ((3.4, 0.4),)
295
296
if plot_title is not None:
297
formatted_title = plot_title + "\n"
298
else:
299
formatted_title = ""
300
301
formatted_title += "b = " + str(b)
302
303
plots = region_plots(slices,
304
points_to_mark = classical_points,
305
plot_title = formatted_title,
306
add_slice_count_to_title = True,
307
xbounds = abounds, xlabel = alabel,
308
ybounds = cbounds, ylabel = clabel,
309
plot_colors = plot_colors)
310
311
return plots
312
313
def paper_sliced_cone_plots_b(poly, b = 0, abounds = None, cbounds = None, plot_title = None, plot_colors = six_nice_colors):
314
"""
315
Plot the two-dimensional slices of the normal fan of a polytope with fixed b.
316
317
INPUT:
318
- ``poly`` -- A Polytope in R4
319
- ``b`` -- (default: 0) The fixed value of b to use
320
- ``abounds`` -- (default: automatic) The range of a values to plot
321
- ``cbounds`` -- (default: automatic) The range of c values to plot
322
- ``plot_title`` -- (default: None) Title for the plot
323
"""
324
# Get the slices
325
slices = sliced_cones_b(poly, b)
326
327
classical_points = ((3.4, 0.4),)
328
329
if plot_title is not None:
330
formatted_title = plot_title + "\n"
331
else:
332
formatted_title = ""
333
334
#formatted_title += "b = " + str(b)
335
336
plots = region_plots(slices,
337
points_to_mark = classical_points,
338
plot_title = formatted_title,
339
add_slice_count_to_title = False,
340
xbounds = abounds, xlabel = alabel,
341
ybounds = cbounds, ylabel = clabel,
342
plot_colors = plot_colors)
343
344
return plots
345
346
def accuracy_cone_plots_b(poly, accuracy, b = 0, abounds = None, cbounds = None, plot_title = None,colormap=colormaps['hot']):
347
"""
348
Plot the two-dimensional slices of the normal fan of a polytope with fixed b.
349
350
INPUT:
351
- ``poly`` -- A Polytope in R4
352
- ``b`` -- (default: 0) The fixed value of b to use
353
- ``abounds`` -- (default: automatic) The range of a values to plot
354
- ``cbounds`` -- (default: automatic) The range of c values to plot
355
- ``plot_title`` -- (default: None) Title for the plot
356
"""
357
# Get the slices
358
slices = sliced_cones_b(poly, b)
359
360
classical_points = ((3.4, 0.4),)
361
362
if plot_title is not None:
363
formatted_title = plot_title + "\n"
364
else:
365
formatted_title = ""
366
367
formatted_title += "b = " + str(b)
368
369
plots = accuracy_region_plots(slices,
370
accuracy,
371
points_to_mark = classical_points,
372
plot_title = formatted_title,
373
add_slice_count_to_title = True,
374
xbounds = abounds, xlabel = alabel,
375
ybounds = cbounds, ylabel = clabel, colormap=colormap)
376
377
return plots
378
379
@cached_method
380
def sliced_cone_plots_c(poly, c = 0, abounds = None, bbounds = None, plot_title = None, plot_colors = six_nice_colors):
381
"""
382
Plot the two-dimensional slices of the normal fan of a polytope with fixed c.
383
384
INPUT:
385
- ``poly`` -- A Polytope in R4
386
- ``c`` -- (default: 0) The fixed value of c to use
387
- ``abounds`` -- (default: automatic) The range of a values to plot
388
- ``bbounds`` -- (default: automatic) The range of b values to plot
389
- ``plot_title`` -- (default: None) Title for the plot
390
"""
391
# Get the slices
392
slices = sliced_cones_c(poly, c)
393
394
classical_points = ((3.4, 0),)
395
396
if plot_title is not None:
397
formatted_title = plot_title + "\n"
398
else:
399
formatted_title = ""
400
401
formatted_title += "c = " + str(c)
402
403
plots = region_plots(slices,
404
points_to_mark = classical_points,
405
plot_title = formatted_title,
406
add_slice_count_to_title = True,
407
xbounds = abounds, xlabel = alabel,
408
ybounds = bbounds, ylabel = blabel,
409
plot_colors = plot_colors)
410
411
return plots
412
413