-
Notifications
You must be signed in to change notification settings - Fork 0
/
Main.lean
136 lines (127 loc) · 5.07 KB
/
Main.lean
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
import ArrowPoly.ArrowPoly
import ArrowPoly.LoadKnot
structure knot_data where
name : String
num : Nat
polys : Array Poly
polys' : Array Poly
jpolys : Array Poly
jpolys' : Array Poly
attribute [local instance] Array.lexicographic
local instance [Inhabited α] [Ord α] : LT (Array α) := ltOfOrd
local instance : LT Poly := ltOfOrd
def calculate_knot (cache : ATLCache)
(num : Nat) (name : String) (pd : PD Nat) (bdry : Nat × Nat) (cables : Nat) :
ATLCache × knot_data :=
Id.run do
let mut cache := cache
--let (pd, bdry) := pd.writhe_normalize bdry
let mut polys : Array Poly := #[]
for n in [1:cables+1] do
let (cache', p) := cache.cabled_arrow_poly n pd bdry
polys := polys.push p
cache := cache'
let mut polys' := polys.map Poly.mirror
if polys' < polys then
(polys, polys') := (polys', polys)
let mut jpolys := polys.map Poly.subst_K_one
let mut jpolys' := polys'.map Poly.subst_K_one
if jpolys' < jpolys then
(jpolys, jpolys') := (jpolys', jpolys)
return (cache, { name := name, num := num, polys := polys, polys' := polys', jpolys := jpolys, jpolys' := jpolys' })
def knot_task (data : Array (String × PD Nat × Nat × Nat))
(max_crossings : Nat) (cables : Nat)
(nthreads : Nat) (thread : Nat) :
IO (Array knot_data) :=
do
let mut res : Array knot_data := #[]
let mut cache := ATLCache.empty
for i in [thread : data.size : nthreads] do
let (name, pd, bdry) := data[i]!
if pd.crossings > max_crossings then break
let (cache', knot) := calculate_knot cache i name pd bdry cables
cache := cache'
res := res.push knot
IO.println s!"calculated for {knot.name}"
return res
structure CalcOptions where
input_file : Option String := none
num_threads : Nat := 12
max_crossings : Nat := 5
only_knots : Option (Array String) := none
cables : Nat := 3
def optParseString (err : String) : List String → IO (String × List String)
| s :: args => return (s, args)
| [] => throw <| IO.userError err
def optParseNat (err : String) : List String → IO (Nat × List String)
| s :: args =>
match s.toNat? with
| some n => return (n, args)
| none => throw <| IO.userError err
| [] => throw <| IO.userError err
partial def CalcOptions.parse (opts : CalcOptions := {}) : List String → IO CalcOptions
| [] => return opts
| "-k" :: args => do
let (k, args) ← optParseString "expecting knot name after -k" args
let knots := opts.only_knots.getD #[]
parse {opts with only_knots := knots.push k} args
| "-j" :: args => do
let (n, args) ← optParseNat "expecting non-negative integer after -j" args
parse {opts with num_threads := n} args
| "-n" :: args => do
let (n, args) ← optParseNat "expecting non-negative integer after -n" args
parse {opts with max_crossings := n} args
| "-c" :: args => do
let (n, args) ← optParseNat "expecting non-negative integer after -c" args
parse {opts with cables := n} args
| "-h" :: _ | "--help" :: _ => do
throw <| IO.userError "Usage: arrow_poly [-j num_threads] [-n max_crossings] [-c max_cables] [-k knot_name ... -k knot_name] data/knots-6.txt"
| fname :: args =>
if fname.get? 0 == some '-' then
throw <| IO.userError s!"Unknown option {fname}"
else if opts.input_file.isNone then
parse {opts with input_file := fname} args
else
throw <| IO.userError "Can only have one knot file."
def main (args : List String) : IO Unit := do
let opts ← CalcOptions.parse {} args
let fname ← match opts.input_file with
| some fname => pure fname
| none => throw <| IO.userError "Need to give knot file"
IO.println "Configuration:"
IO.println s!" input file: {opts.input_file.getD ""}"
match opts.only_knots with
| some knots => IO.println s!" only knots: {String.intercalate ", " knots.toList}"
| none => pure ()
IO.println s!" number of threads: {opts.num_threads}"
IO.println s!" max. crossings: {opts.max_crossings}"
IO.println s!" max. cables: {opts.cables}"
IO.println s!"loading {fname}"
let knots ← parseFile fname
IO.println s!"loaded {knots.size} knots"
let knots :=
match opts.only_knots with
| some only => knots.filter (λ k => only.contains k.1)
| none => knots
IO.println s!"processing {knots.size} knots"
let nthreads := opts.num_threads
let mut tasks := #[]
for thread in [0 : nthreads] do
tasks := tasks.push (← IO.asTask (knot_task knots opts.max_crossings opts.cables nthreads thread))
let mut res := #[]
for t in tasks do
let res' ← IO.ofExcept (← IO.wait t)
res := res.append res'
res := res.insertionSort (λ d d' => d.num < d'.num)
IO.println s!"done."
let filename := "out.txt"
IO.println s!"writing to {filename}"
IO.FS.withFile filename IO.FS.Mode.write λ handle => do
for data in res do
handle.putStrLn data.name
handle.putStrLn "arrow"
handle.putStrLn <| ", ".intercalate (data.polys.map toString).toList
handle.putStrLn <| ", ".intercalate (data.polys'.map toString).toList
handle.putStrLn "jones"
handle.putStrLn <| ", ".intercalate (data.jpolys.map toString).toList
handle.putStrLn <| ", ".intercalate (data.jpolys'.map toString).toList