Compare commits

...

5 Commits

Author SHA1 Message Date
Miguel M f420690041 pure python for comparison 2023-02-28 21:20:06 +00:00
Miguel M 39cfb20f13 touchups 2023-02-28 21:19:50 +00:00
Miguel M e85346e916 could have used a map instead of running twice, preparing to make that
change
2023-02-26 18:07:25 +00:00
Miguel M b899ddd63a Final commit, in principle.
Got things running at about ~1ns per iteration, seems good enough.
Adopted a linear strategy to evaluating the bytecode, rather than a
recursive or even imperative evaluation strategy; this also lets me
elide the offsets and store the bytecode in half the size. Looking
forward to finding out that formulas are evaluated wrongly, but couldn't
find a counterexample. Also restructured things a bit to avoid multiple
alocations when evaluating by this strategy.
2023-02-24 19:41:51 +00:00
Miguel M 3a6c511ed5 optimized bottlenecks based on benchmarks. fast now 2023-02-24 18:23:37 +00:00
19 changed files with 3132 additions and 302 deletions

1
Cargo.lock generated
View File

@ -6,6 +6,7 @@ version = 3
name = "adversary"
version = "0.1.0"
dependencies = [
"bitflags",
"criterion",
"pest",
"pest_derive",

View File

@ -9,6 +9,7 @@ name = "adversary"
crate-type = ["cdylib", "rlib"]
[dependencies]
bitflags = "1.3.2"
pest = "2.5.5"
pest_derive = "2.5.5"
pyo3 = { version = "0.18.0", features = ["extension-module"] }
@ -16,6 +17,14 @@ pyo3 = { version = "0.18.0", features = ["extension-module"] }
[dev-dependencies]
criterion = "0.4.0"
[[bench]]
name = "search_big"
harness = false
[[bench]]
name = "search"
harness = false
harness = false
[[bench]]
name = "vm"
harness = false

View File

@ -7,5 +7,16 @@ flamegraph:
flamegraph-debug:
cargo flamegraph --dev -o debug_flamegraph.svg --bench search -- --bench
asm:
cargo clean
cargo rustc --release --lib -- --emit asm=.vscode/asm_mangled
pwsh -Command 'Get-Content .vscode/asm_mangled | c++filt > .\src\lib.S'
pwsh -Command 'Remove-Item .vscode/asm_mangled'
maturin:
pwsh -Command 'venv/Scripts/activate; maturin develop --release'
.PHONY: criterion flamegraph flamegraph-debug
hyperfine:
hyperfine --show-output --parameter-scan n 5 20 -S 'pwsh' -s 'venv/scripts/activate' --export-json hyperfine.json --export-csv hyperfine.csv 'python ./pytest/timing.py {n}'
.PHONY: criterion flamegraph flamegraph-debug asm hyperfine maturin

View File

@ -4,7 +4,7 @@ extern crate adversary;
use criterion::{criterion_group, criterion_main, Criterion};
pub fn criterion_benchmark(c: &mut Criterion) {
fn bench_search(c: &mut Criterion) {
pyo3::prepare_freethreaded_python();
pyo3::Python::with_gil(|_py| {
let obj = adversary::Prover::py_new(
@ -13,11 +13,11 @@ pub fn criterion_benchmark(c: &mut Criterion) {
"<= ham (^ x y) p".to_string(),
)
.unwrap();
c.bench_function("find_bounds", |b| {
c.bench_function("search", |b| {
b.iter(|| criterion::black_box(obj.find_bounds(10, 5, 3)));
});
})
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
criterion_group!(search, bench_search);
criterion_main!(search);

23
benches/search_big.rs Normal file
View File

@ -0,0 +1,23 @@
#[macro_use]
extern crate criterion;
extern crate adversary;
use criterion::{criterion_group, criterion_main, Criterion};
fn bench_search_big(c: &mut Criterion) {
pyo3::prepare_freethreaded_python();
pyo3::Python::with_gil(|_py| {
let obj = adversary::Prover::py_new(
"= (ham x) k".to_string(),
"= (ham y) (+ k 1)".to_string(),
"<= ham (^ x y) p".to_string(),
)
.unwrap();
c.bench_function("search_big", |b| {
b.iter(|| criterion::black_box(obj.find_bounds(12, 5, 8)));
});
})
}
criterion_group!(search_big, bench_search_big);
criterion_main!(search_big);

35
benches/vm.rs Normal file
View File

@ -0,0 +1,35 @@
#[macro_use]
extern crate criterion;
extern crate adversary;
use criterion::{criterion_group, criterion_main, Criterion};
fn bench_vm(c: &mut Criterion) {
let expression =
adversary::vm::parsing::parse_relation("and (= (ham (^ x y)) (ham (+ 3 x))) (> (* x y) 5)");
if let Err(e) = expression {
println!("{}", e);
panic!();
}
let code = adversary::vm::compile_boolean(expression.unwrap());
let mut stack = adversary::vm::VmStack::from_code(&code);
c.bench_function("vm", |b| {
b.iter(|| {
for x in 0..(1 << 6) {
for y in 0..(1 << 6) {
criterion::black_box(
adversary::vm::Vm::load(
&code,
adversary::vm::Registers::load(x, y, 6, 0, 0),
&mut stack,
)
.run(),
);
}
}
})
});
}
criterion_group!(vm, bench_vm);
criterion_main!(vm);

17
hyperfine.csv Normal file
View File

@ -0,0 +1,17 @@
#command,mean,stddev,median,user,system,min,max,parameter_n
"python ./pytest/timing.py 5",0.04581394800000006,0.00816270671734837,0.04668517800000005,0.026718750000000003,0.019218749999999996,0.032075278000000096,0.05514677800000001,5
"python ./pytest/timing.py 6",0.042371348000000066,0.007327761603207661,0.04315997800000004,0.009812500000000002,0.010281249999999997,0.03199467800000011,0.05567727800000011,6
"python ./pytest/timing.py 7",0.04077101800000005,0.008782824810351926,0.040449628000000015,0.029562500000000002,0.016093749999999997,0.028448878000000066,0.05205177800000005,7
"python ./pytest/timing.py 8",0.04834307800000006,0.008276160843853466,0.04665782800000007,0.041781250000000006,0.05874999999999999,0.03589267800000007,0.06276897800000003,8
"python ./pytest/timing.py 9",0.04610321800000006,0.01221144375440967,0.04276542800000005,0.004125000000000001,0.005593749999999997,0.031109278000000073,0.06754577800000006,9
"python ./pytest/timing.py 10",0.656881348,1.816322202089533,0.04675287800000005,0.02075,0.00915625,0.03219597800000007,5.8203265779999995,10
"python ./pytest/timing.py 11",0.04503963800000007,0.005758636203747479,0.04366842800000009,0.018906250000000003,0.029718749999999995,0.03824637800000008,0.056746278000000094,11
"python ./pytest/timing.py 12",0.06112314800000005,0.01715353160780924,0.05904557800000004,0.02146875,0.025031249999999994,0.03643177800000008,0.09102267800000008,12
"python ./pytest/timing.py 13",0.07466937800000005,0.040038996149254304,0.060930978000000025,0.040781250000000005,0.017656249999999995,0.03599187800000003,0.15105747800000002,13
"python ./pytest/timing.py 14",0.12913027800000004,0.16291293196519285,0.05922252800000005,0.10300000000000001,0.004249999999999999,0.035453378000000035,0.5145964780000001,14
"python ./pytest/timing.py 15",0.5586950680000001,0.7332788059539814,0.17217967800000006,0.500875,0.005593749999999997,0.03280447800000008,2.137246578,15
"python ./pytest/timing.py 16",2.576790488,2.687933192209969,1.668545078,2.5227499999999994,0.03284374999999999,0.041527578000000065,6.829759978,16
"python ./pytest/timing.py 17",5.479623618,7.132625194222096,3.4482901779999997,5.43184375,0.015874999999999993,0.05124057800000004,21.924067778,17
"python ./pytest/timing.py 18",34.976559767999994,45.33047970462983,1.2725040280000002,34.897749999999995,0.020562499999999994,0.03764907800000006,95.283775278,18
"python ./pytest/timing.py 19",100.16646647799999,143.37612065560103,1.117140078,100.04775,0.022343749999999996,0.036464678000000084,385.89288487799996,19
"python ./pytest/timing.py 20",253.70613178800005,435.7539383326962,75.73695792800001,253.42871875,0.047562499999999994,0.0477563780000001,1400.148915478,20
1 #command mean stddev median user system min max parameter_n
2 python ./pytest/timing.py 5 0.04581394800000006 0.00816270671734837 0.04668517800000005 0.026718750000000003 0.019218749999999996 0.032075278000000096 0.05514677800000001 5
3 python ./pytest/timing.py 6 0.042371348000000066 0.007327761603207661 0.04315997800000004 0.009812500000000002 0.010281249999999997 0.03199467800000011 0.05567727800000011 6
4 python ./pytest/timing.py 7 0.04077101800000005 0.008782824810351926 0.040449628000000015 0.029562500000000002 0.016093749999999997 0.028448878000000066 0.05205177800000005 7
5 python ./pytest/timing.py 8 0.04834307800000006 0.008276160843853466 0.04665782800000007 0.041781250000000006 0.05874999999999999 0.03589267800000007 0.06276897800000003 8
6 python ./pytest/timing.py 9 0.04610321800000006 0.01221144375440967 0.04276542800000005 0.004125000000000001 0.005593749999999997 0.031109278000000073 0.06754577800000006 9
7 python ./pytest/timing.py 10 0.656881348 1.816322202089533 0.04675287800000005 0.02075 0.00915625 0.03219597800000007 5.8203265779999995 10
8 python ./pytest/timing.py 11 0.04503963800000007 0.005758636203747479 0.04366842800000009 0.018906250000000003 0.029718749999999995 0.03824637800000008 0.056746278000000094 11
9 python ./pytest/timing.py 12 0.06112314800000005 0.01715353160780924 0.05904557800000004 0.02146875 0.025031249999999994 0.03643177800000008 0.09102267800000008 12
10 python ./pytest/timing.py 13 0.07466937800000005 0.040038996149254304 0.060930978000000025 0.040781250000000005 0.017656249999999995 0.03599187800000003 0.15105747800000002 13
11 python ./pytest/timing.py 14 0.12913027800000004 0.16291293196519285 0.05922252800000005 0.10300000000000001 0.004249999999999999 0.035453378000000035 0.5145964780000001 14
12 python ./pytest/timing.py 15 0.5586950680000001 0.7332788059539814 0.17217967800000006 0.500875 0.005593749999999997 0.03280447800000008 2.137246578 15
13 python ./pytest/timing.py 16 2.576790488 2.687933192209969 1.668545078 2.5227499999999994 0.03284374999999999 0.041527578000000065 6.829759978 16
14 python ./pytest/timing.py 17 5.479623618 7.132625194222096 3.4482901779999997 5.43184375 0.015874999999999993 0.05124057800000004 21.924067778 17
15 python ./pytest/timing.py 18 34.976559767999994 45.33047970462983 1.2725040280000002 34.897749999999995 0.020562499999999994 0.03764907800000006 95.283775278 18
16 python ./pytest/timing.py 19 100.16646647799999 143.37612065560103 1.117140078 100.04775 0.022343749999999996 0.036464678000000084 385.89288487799996 19
17 python ./pytest/timing.py 20 253.70613178800005 435.7539383326962 75.73695792800001 253.42871875 0.047562499999999994 0.0477563780000001 1400.148915478 20

596
hyperfine.json Normal file
View File

@ -0,0 +1,596 @@
{
"results": [
{
"command": "python ./pytest/timing.py 5",
"mean": 0.04581394800000006,
"stddev": 0.00816270671734837,
"median": 0.04668517800000005,
"user": 0.026718750000000003,
"system": 0.019218749999999996,
"min": 0.032075278000000096,
"max": 0.05514677800000001,
"times": [
0.05514677800000001,
0.043960078000000014,
0.047457178000000044,
0.054621078000000045,
0.045913178000000054,
0.032075278000000096,
0.05370557800000009,
0.040872578000000104,
0.05016877800000008,
0.034218978000000067
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "5"
}
},
{
"command": "python ./pytest/timing.py 6",
"mean": 0.042371348000000066,
"stddev": 0.007327761603207661,
"median": 0.04315997800000004,
"user": 0.009812500000000002,
"system": 0.010281249999999997,
"min": 0.03199467800000011,
"max": 0.05567727800000011,
"times": [
0.04193087800000006,
0.03199467800000011,
0.033345078000000083,
0.046498178,
0.0482699780000001,
0.04545117800000009,
0.044389078000000026,
0.04078387800000005,
0.05567727800000011,
0.03537327800000001
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "6"
}
},
{
"command": "python ./pytest/timing.py 7",
"mean": 0.04077101800000005,
"stddev": 0.008782824810351926,
"median": 0.040449628000000015,
"user": 0.029562500000000002,
"system": 0.016093749999999997,
"min": 0.028448878000000066,
"max": 0.05205177800000005,
"times": [
0.03829057800000002,
0.03260187800000003,
0.04944087800000008,
0.05205177800000005,
0.052009178000000045,
0.04572607800000006,
0.03360147800000002,
0.028448878000000066,
0.04260867800000001,
0.032930778000000105
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "7"
}
},
{
"command": "python ./pytest/timing.py 8",
"mean": 0.04834307800000006,
"stddev": 0.008276160843853466,
"median": 0.04665782800000007,
"user": 0.041781250000000006,
"system": 0.05874999999999999,
"min": 0.03589267800000007,
"max": 0.06276897800000003,
"times": [
0.06276897800000003,
0.051798178000000084,
0.0451638780000001,
0.04575477800000005,
0.05026417800000005,
0.03589267800000007,
0.047560878000000084,
0.040741878000000065,
0.043394178000000005,
0.06009117800000008
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "8"
}
},
{
"command": "python ./pytest/timing.py 9",
"mean": 0.04610321800000006,
"stddev": 0.01221144375440967,
"median": 0.04276542800000005,
"user": 0.004125000000000001,
"system": 0.005593749999999997,
"min": 0.031109278000000073,
"max": 0.06754577800000006,
"times": [
0.055943378000000044,
0.031109278000000073,
0.03689987800000005,
0.03579857800000008,
0.04079887800000004,
0.03652607800000007,
0.04473197800000006,
0.06754577800000006,
0.050433578000000034,
0.061244778000000055
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "9"
}
},
{
"command": "python ./pytest/timing.py 10",
"mean": 0.656881348,
"stddev": 1.816322202089533,
"median": 0.04675287800000005,
"user": 0.02075,
"system": 0.00915625,
"min": 0.03219597800000007,
"max": 5.8203265779999995,
"times": [
5.8203265779999995,
0.31030617800000004,
0.14147657800000002,
0.066758278,
0.03356697800000008,
0.05600177800000006,
0.03219597800000007,
0.03594707800000008,
0.03473007800000005,
0.03750397800000005
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "10"
}
},
{
"command": "python ./pytest/timing.py 11",
"mean": 0.04503963800000007,
"stddev": 0.005758636203747479,
"median": 0.04366842800000009,
"user": 0.018906250000000003,
"system": 0.029718749999999995,
"min": 0.03824637800000008,
"max": 0.056746278000000094,
"times": [
0.056746278000000094,
0.04288307800000002,
0.04308117800000011,
0.03849437800000011,
0.048631578000000064,
0.042227278000000035,
0.04431167800000002,
0.0515188780000001,
0.03824637800000008,
0.044255678000000076
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "11"
}
},
{
"command": "python ./pytest/timing.py 12",
"mean": 0.06112314800000005,
"stddev": 0.01715353160780924,
"median": 0.05904557800000004,
"user": 0.02146875,
"system": 0.025031249999999994,
"min": 0.03643177800000008,
"max": 0.09102267800000008,
"times": [
0.06700417800000003,
0.09102267800000008,
0.07156757800000002,
0.07994157800000001,
0.06872617800000003,
0.04994327800000009,
0.046060578000000074,
0.03643177800000008,
0.05108697800000006,
0.04944667800000002
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "12"
}
},
{
"command": "python ./pytest/timing.py 13",
"mean": 0.07466937800000005,
"stddev": 0.040038996149254304,
"median": 0.060930978000000025,
"user": 0.040781250000000005,
"system": 0.017656249999999995,
"min": 0.03599187800000003,
"max": 0.15105747800000002,
"times": [
0.07185757800000003,
0.036325978000000037,
0.0923784780000001,
0.057389278000000044,
0.1357676780000001,
0.0541288780000001,
0.03599187800000003,
0.15105747800000002,
0.064472678,
0.04732387800000004
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "13"
}
},
{
"command": "python ./pytest/timing.py 14",
"mean": 0.12913027800000004,
"stddev": 0.16291293196519285,
"median": 0.05922252800000005,
"user": 0.10300000000000001,
"system": 0.004249999999999999,
"min": 0.035453378000000035,
"max": 0.5145964780000001,
"times": [
0.07471897800000005,
0.035453378000000035,
0.048438178000000054,
0.05548507800000002,
0.05164857800000011,
0.04432947800000009,
0.5145964780000001,
0.06295997800000008,
0.06315467800000008,
0.34051797800000005
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "14"
}
},
{
"command": "python ./pytest/timing.py 15",
"mean": 0.5586950680000001,
"stddev": 0.7332788059539814,
"median": 0.17217967800000006,
"user": 0.500875,
"system": 0.005593749999999997,
"min": 0.03280447800000008,
"max": 2.137246578,
"times": [
0.7437489780000002,
0.08189187800000008,
0.0344190780000001,
0.7140736780000001,
0.03280447800000008,
0.040056478000000006,
0.26246747800000003,
2.137246578,
0.040682278000000016,
1.499559778
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "15"
}
},
{
"command": "python ./pytest/timing.py 16",
"mean": 2.576790488,
"stddev": 2.687933192209969,
"median": 1.668545078,
"user": 2.5227499999999994,
"system": 0.03284374999999999,
"min": 0.041527578000000065,
"max": 6.829759978,
"times": [
6.602360178,
0.39307727800000003,
0.041527578000000065,
0.057177678000000065,
4.293663578,
6.829759978,
0.08836797800000007,
1.690802878,
4.124880478,
1.646287278
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "16"
}
},
{
"command": "python ./pytest/timing.py 17",
"mean": 5.479623618,
"stddev": 7.132625194222096,
"median": 3.4482901779999997,
"user": 5.43184375,
"system": 0.015874999999999993,
"min": 0.05124057800000004,
"max": 21.924067778,
"times": [
3.617135778,
11.049047278,
3.4278150779999996,
0.116646778,
0.17526147800000003,
3.468765278,
10.884210377999999,
21.924067778,
0.05124057800000004,
0.08204577800000001
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "17"
}
},
{
"command": "python ./pytest/timing.py 18",
"mean": 34.976559767999994,
"stddev": 45.33047970462983,
"median": 1.2725040280000002,
"user": 34.897749999999995,
"system": 0.020562499999999994,
"min": 0.03764907800000006,
"max": 95.283775278,
"times": [
65.275574278,
93.015606878,
93.44633337799999,
1.253816878,
1.291191178,
0.03791617800000002,
0.04903267800000011,
0.03764907800000006,
95.283775278,
0.07470187800000005
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "18"
}
},
{
"command": "python ./pytest/timing.py 19",
"mean": 100.16646647799999,
"stddev": 143.37612065560103,
"median": 1.117140078,
"user": 100.04775,
"system": 0.022343749999999996,
"min": 0.036464678000000084,
"max": 385.89288487799996,
"times": [
385.89288487799996,
290.359225178,
0.036464678000000084,
0.19590917800000007,
0.046879778000000094,
161.21907277800003,
2.035711278,
0.04454757800000009,
161.635400578,
0.19856887800000012
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "19"
}
},
{
"command": "python ./pytest/timing.py 20",
"mean": 253.70613178800005,
"stddev": 435.7539383326962,
"median": 75.73695792800001,
"user": 253.42871875,
"system": 0.047562499999999994,
"min": 0.0477563780000001,
"max": 1400.148915478,
"times": [
420.37908587799996,
0.07129847800000011,
422.945836478,
25.767745578000003,
125.706170278,
141.83330137800002,
0.06695817800000003,
1400.148915478,
0.094249778,
0.0477563780000001
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"parameters": {
"n": "20"
}
}
]
}

491
linear_vm_flamegraph.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 484 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.6 MiB

15
pytest/bounds.py Normal file
View File

@ -0,0 +1,15 @@
import adversary
from math import sqrt
prover = adversary.Prover(
"= (ham x) k", "= (ham y) (+ k 1)", "= ham (^ x y) p").hint_symmetric()
bounds = prover.find_bounds(16, 5, 8)
lower_bound = sqrt(bounds.min_x_relations *
bounds.min_y_relations / bounds.max_joint_relations)
print("m =", bounds.min_x_relations)
print(f"From x={bounds.single_bounding_x:b}")
print("m' =", bounds.min_y_relations)
print(f"From y={bounds.single_bounding_y:b}")
print("ℓ·ℓ' =", bounds.max_joint_relations)
print(f"From x={bounds.joint_bounding_x:012b} and y={bounds.joint_bounding_y:012b} and window={bounds.bounding_window:012b}")
print(f"Query lower bounds = {lower_bound}")

75
pytest/pure.py Normal file
View File

@ -0,0 +1,75 @@
import itertools
from math import inf
n = 16
k = 6
p = 2
def in_set_a(x):
return x.bit_count() == k
def in_set_b(y):
return y.bit_count() == k + 1
def related(a, b):
return (x ^ y).bit_count() == 1
m = inf
m_prime = inf
window = (1 << p) - 1
l = 0
l_prime = 0
# Look at all the `x`s, find the `x` with least number of relations, and
# what is the `x` with most relations (under the window condition)
for x in range(2**n):
if not in_set_a(x):
continue
relations_count = 0
for y in range(2**n):
if not in_set_b(y):
continue
if not related(x, y):
continue
relations_count += 1
if (x & window) != (y & window):
l += 1
# This `x` has less relations than all `x` we've looked at so far
if relations_count < m:
m = relations_count
for y in range(2**n):
if not in_set_b(y):
continue
relations_count = 0
for x in range(2**n):
if not in_set_a(x):
continue
if not related(x, y):
continue
relations_count += 1
if (x & window) != (y & window):
l_prime += 1
# This `y` has less relations than all `y` we've looked at so far
if relations_count < m_prime:
m_prime = relations_count
# Finally, see if we can get a better `l_max` under this window than
# what we've seen so far
l_max = l * l_prime
print(m, m_prime, l_max)

10
pytest/timing.py Normal file
View File

@ -0,0 +1,10 @@
import adversary
import random
import sys
n = int(sys.argv[1])
prover = adversary.Prover(
"= (ham x) k", "= (ham y) (+ k 1)", "= ham (^ x y) p").hint_symmetric()
k = random.randint(0, n)
p = random.randint(0, n)
bounds = prover.find_bounds(n, k, p)

View File

Before

Width:  |  Height:  |  Size: 399 KiB

After

Width:  |  Height:  |  Size: 399 KiB

View File

@ -1,11 +1,12 @@
extern crate pest;
#[macro_use]
extern crate pest_derive;
#[macro_use]
extern crate bitflags;
mod vm;
pub mod vm;
use pyo3::prelude::*;
use vm::VmCode;
// We cache the A and B set up to a total of ~2Gb of memory,
// meaning ~ 10^7 elements in each set
@ -33,58 +34,64 @@ pub struct BoundsResult {
#[pyclass]
pub struct Prover {
a_description: VmCode,
b_description: VmCode,
relationship: VmCode,
a_description: vm::VmCode,
b_description: vm::VmCode,
relationship: vm::VmCode,
hints: ProofHints,
}
bitflags! {
struct ProofHints: u8 {
const SymmetricFn = 0b00000001;
}
}
struct CachedSetIterator<'code> {
cache: Vec<u64>,
filter: &'code VmCode,
filter: &'code vm::VmCode,
stack: vm::VmStack,
n: u32,
p: u32,
k: u32,
cached: bool,
counter: u64,
cache_counter: usize,
top: u64,
counter: usize,
top: usize,
is_x: bool,
}
impl<'code> CachedSetIterator<'code> {
fn create_x(filter: &'code VmCode, n: u32, p: u32, k: u32) -> Self {
fn create_x(filter: &'code vm::VmCode, n: u32, p: u32, k: u32) -> Self {
CachedSetIterator {
cache: Vec::with_capacity(CACHE_SIZE_LIMIT),
filter,
stack: vm::VmStack::from_code(filter),
n,
p,
k,
cached: false,
counter: 0,
cache_counter: 0,
top: 2_u64.pow(n as u32),
top: 2_usize.pow(n as u32),
is_x: true,
}
}
fn create_y(filter: &'code VmCode, n: u32, p: u32, k: u32) -> Self {
fn create_y(filter: &'code vm::VmCode, n: u32, p: u32, k: u32) -> Self {
CachedSetIterator {
cache: Vec::with_capacity(CACHE_SIZE_LIMIT),
filter,
stack: vm::VmStack::from_code(filter),
n,
p,
k,
cached: false,
counter: 0,
cache_counter: 0,
top: 2_u64.pow(n as u32),
top: 2_usize.pow(n as u32),
is_x: false,
}
}
fn reset(&mut self) {
self.counter = 0;
self.cache_counter = 0;
}
}
@ -93,12 +100,12 @@ impl<'code> Iterator for &mut CachedSetIterator<'code> {
fn next(&mut self) -> Option<Self::Item> {
if self.cached {
if self.cache_counter < self.cache.len() {
let result = self.cache[self.cache_counter];
self.cache_counter += 1;
if self.counter < self.cache.len() {
let result = self.cache[self.counter as usize];
self.counter += 1;
if self.cache_counter == CACHE_SIZE_LIMIT {
self.counter = self.cache.last().unwrap() + 1;
if self.counter == CACHE_SIZE_LIMIT {
self.counter = *self.cache.last().unwrap() as usize + 1;
}
return Some(result);
@ -118,24 +125,28 @@ impl<'code> Iterator for &mut CachedSetIterator<'code> {
let included = if self.is_x {
vm::Vm::load(
self.filter,
vm::Registers::load(self.counter, 0, self.n, self.p, self.k),
vm::Registers::load(self.counter as u64, 0, self.n, self.p, self.k),
&mut self.stack,
)
.run()
.unwrap_bool()
.output_bool()
.unwrap()
} else {
vm::Vm::load(
self.filter,
vm::Registers::load(0, self.counter, self.n, self.p, self.k),
vm::Registers::load(0, self.counter as u64, self.n, self.p, self.k),
&mut self.stack,
)
.run()
.unwrap_bool()
.output_bool()
.unwrap()
};
if !included {
self.counter += 1;
continue;
} else {
let result = self.counter;
let result = self.counter as u64;
if self.cache.len() < CACHE_SIZE_LIMIT {
self.cache.push(result);
}
@ -150,6 +161,7 @@ impl<'code> Iterator for &mut CachedSetIterator<'code> {
// See https://stackoverflow.com/a/27755938
// In turn from http://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation
struct FixedHammingWeight {
ones: u32,
permutation: u64,
top: u64,
exhausted: bool,
@ -158,11 +170,17 @@ struct FixedHammingWeight {
impl FixedHammingWeight {
fn new(bits: u32, ones: u32) -> Self {
FixedHammingWeight {
ones,
permutation: (1 << ones) - 1,
top: ((1 << ones) - 1) << (bits - ones),
exhausted: false,
}
}
fn reset(&mut self) {
self.permutation = (1 << self.ones) - 1;
self.exhausted = false;
}
}
impl Iterator for FixedHammingWeight {
@ -170,6 +188,7 @@ impl Iterator for FixedHammingWeight {
fn next(&mut self) -> Option<Self::Item> {
if self.exhausted {
self.reset();
return None;
}
let to_yield = self.permutation;
@ -263,9 +282,20 @@ impl Prover {
relationship,
a_description,
b_description,
hints: ProofHints::empty(),
})
}
/// Hints to the prover that the function in question is totally symmetric,
/// or, equivalently, that `a_description` only depends on the Hamming weight
/// of x, and `b_description` only depends on the Hamming weight of y.
///
/// If you l your results will lower bound the upper bound.
pub fn hint_symmetric<'s>(mut py_self: PyRefMut<'s, Self>, py: Python) -> PyRefMut<'s, Self> {
(*py_self).hints |= ProofHints::SymmetricFn;
py_self
}
/// Finds a lower bound to the query complexity according to the specified parameters.
///
/// Arguments:
@ -273,7 +303,7 @@ impl Prover {
/// belonging to either of the specified sets [int]
/// p The number of parallel queries [int]
/// k Parameter accepted in set specifications and relations [int]
pub fn find_bounds(&self, n: u32, p: u32, k: u32) -> PyResult<BoundsResult> {
pub fn find_bounds(&self, n: u32, k: u32, p: u32) -> PyResult<BoundsResult> {
if n > 63 {
return Err(pyo3::exceptions::PyValueError::new_err(
"More than 63 bits is not supported. (Because of `n` parameter.)",
@ -290,9 +320,10 @@ impl Prover {
));
}
let mut vm_stack = vm::VmStack::from_code(&self.relationship);
let mut a_set_iterator = CachedSetIterator::create_x(&self.a_description, n, p, k);
let mut b_set_iterator = CachedSetIterator::create_y(&self.b_description, n, p, k);
let window_iterator = FixedHammingWeight::new(n, p);
let mut min_x_relations = u64::MAX;
let mut min_y_relations = u64::MAX;
@ -303,7 +334,15 @@ impl Prover {
let mut joint_bounding_y = 0_u64;
let mut bounding_window = 0_u64;
for window in window_iterator {
let mut window_iterator = FixedHammingWeight::new(n, p).into_iter();
let mut first_entry = [(1_u64 << p) - 1].into_iter();
let effective_window_iterator = if self.hints.contains(ProofHints::SymmetricFn) {
&mut first_entry as &mut dyn Iterator<Item = u64>
} else {
&mut window_iterator as &mut dyn Iterator<Item = u64>
};
for window in effective_window_iterator {
let mut max_x_relations = 0_u64;
let mut max_y_relations = 0_u64;
let mut bounding_x_candidate = 0_u64;
@ -317,9 +356,11 @@ impl Prover {
let related = vm::Vm::load(
&self.relationship,
vm::Registers::load(x, y, n, p, k),
&mut vm_stack,
)
.run()
.unwrap_bool();
.output_bool()
.unwrap();
if related {
min_x_relations_candidate += 1;
@ -344,10 +385,14 @@ impl Prover {
let mut max_y_relations_candidate = 0_u64;
for x in &mut a_set_iterator {
let related =
vm::Vm::load(&self.relationship, vm::Registers::load(x, y, n, p, k))
.run()
.unwrap_bool();
let related = vm::Vm::load(
&self.relationship,
vm::Registers::load(x, y, n, p, k),
&mut vm_stack,
)
.run()
.output_bool()
.unwrap();
if related {
min_y_relations_candidate += 1;
@ -374,9 +419,9 @@ impl Prover {
joint_bounding_x = bounding_x_candidate;
joint_bounding_y = bounding_y_candidate;
bounding_window = window;
Python::with_gil(|py| py.check_signals())?;
}
Python::with_gil(|py| py.check_signals())?;
}
Ok(BoundsResult {
@ -437,4 +482,4 @@ fn test_full_run() {
.unwrap();
std::hint::black_box(obj.find_bounds(10, 5, 3)).expect("Success");
})
}
}

View File

@ -4,7 +4,8 @@ use parsing::ast;
use crate::vm::parsing::ast::ComparisonOperator;
type Bytecode = (OpCode, usize);
// type Bytecode = (OpCode, usize);
type Bytecode = OpCode;
#[derive(Debug)]
pub struct VmCode {
@ -15,6 +16,13 @@ pub struct VmCode {
pub struct Vm<'code> {
code: &'code VmCode,
registers: Registers,
stack: &'code mut VmStack,
}
#[derive(Debug)]
pub struct VmStack {
boolean_stack: Vec<bool>,
arithmetic_stack: Vec<ArithmeticValue>,
}
#[derive(Debug)]
@ -26,11 +34,12 @@ pub struct Registers {
k: i64,
}
/*
#[derive(Debug)]
pub enum VmOutput {
Boolean(bool),
Arithmetic(ArithmeticValue),
}
} */
#[derive(Debug)]
pub enum ArithmeticValue {
@ -54,7 +63,23 @@ enum Expression {
Arithmetic(ast::ArithmeticExpression),
}
impl VmOutput {
impl VmStack {
pub fn from_code(code: &VmCode) -> Self {
// Each op_code can produce at most one value onto the stack
let code = &code.code;
VmStack {
boolean_stack: Vec::with_capacity(code.len()),
arithmetic_stack: Vec::with_capacity(code.len()),
}
}
fn reset(&mut self) {
self.boolean_stack.clear();
self.arithmetic_stack.clear();
}
}
/*impl VmOutput {
pub fn unwrap_bool(self) -> bool {
match self {
VmOutput::Boolean(value) => value,
@ -73,6 +98,7 @@ impl VmOutput {
}
}
}
*/
impl Registers {
pub fn load(x: u64, y: u64, n: u32, p: u32, k: u32) -> Self {
@ -101,7 +127,7 @@ pub fn compile_arithmetic(expression: ast::ArithmeticExpression) -> VmCode {
impl VmCode {
pub fn any<P: Fn(&OpCode) -> bool>(&self, predicate: P) -> bool {
for (opcode, _) in &self.code {
for opcode in &self.code {
if predicate(opcode) {
return true;
}
@ -111,242 +137,219 @@ impl VmCode {
}
impl<'code> Vm<'code> {
pub fn load(code: &'code VmCode, registers: Registers) -> Self {
Vm { code, registers }
pub fn load(code: &'code VmCode, registers: Registers, stack: &'code mut VmStack) -> Self {
Vm {
code,
registers,
stack,
}
}
pub fn run(&self) -> VmOutput {
pub fn run(&mut self) -> &mut Self {
// Arithmetic operations for `ArithmeticValue`s
fn operations_as_integer(
op: &ast::BinaryArithmeticOperator,
left_operand: i64,
right_operand: i64,
) -> ArithmeticValue {
match op {
ast::BinaryArithmeticOperator::Times => {
ArithmeticValue::Integer(left_operand * right_operand)
}
ast::BinaryArithmeticOperator::Divide => {
if left_operand % right_operand == 0 {
ArithmeticValue::Integer(left_operand / right_operand)
} else {
ArithmeticValue::Floating(left_operand as f64 / right_operand as f64)
}
}
ast::BinaryArithmeticOperator::Plus => {
ArithmeticValue::Integer(left_operand + right_operand)
}
ast::BinaryArithmeticOperator::Minus => {
ArithmeticValue::Integer(left_operand - right_operand)
}
ast::BinaryArithmeticOperator::Xor => {
ArithmeticValue::Integer(left_operand ^ right_operand)
}
ast::BinaryArithmeticOperator::Pow => {
if right_operand > 0 {
ArithmeticValue::Integer(left_operand.pow(right_operand as u32))
} else {
ArithmeticValue::Floating((left_operand as f64).powi(right_operand as i32))
}
}
}
}
fn operations_as_floating(
op: &ast::BinaryArithmeticOperator,
left_operand: f64,
right_operand: f64,
) -> ArithmeticValue {
match op {
ast::BinaryArithmeticOperator::Times => {
ArithmeticValue::Floating(left_operand * right_operand)
}
ast::BinaryArithmeticOperator::Divide => {
ArithmeticValue::Floating(left_operand as f64 / right_operand as f64)
}
ast::BinaryArithmeticOperator::Plus => {
ArithmeticValue::Floating(left_operand + right_operand)
}
ast::BinaryArithmeticOperator::Minus => {
ArithmeticValue::Floating(left_operand - right_operand)
}
ast::BinaryArithmeticOperator::Xor => {
ArithmeticValue::Integer(left_operand as i64 ^ right_operand as i64)
}
ast::BinaryArithmeticOperator::Pow => {
ArithmeticValue::Floating(left_operand.powf(right_operand))
}
}
}
fn comparison<T: std::cmp::PartialOrd>(
op: &ComparisonOperator,
left_operand: T,
right_operand: T,
) -> bool {
match op {
ast::ComparisonOperator::GreaterOrEqual => left_operand.ge(&right_operand),
ast::ComparisonOperator::LessOrEqual => left_operand.le(&right_operand),
ast::ComparisonOperator::GreaterThan => left_operand.gt(&right_operand),
ast::ComparisonOperator::LessThan => left_operand.lt(&right_operand),
ast::ComparisonOperator::NotEqual => left_operand.ne(&right_operand),
ast::ComparisonOperator::Equal => left_operand.eq(&right_operand),
}
}
// Alias for convenience
let code = &self.code.code;
let registers = &self.registers;
let stack = &mut self.stack;
struct Resolver<'f> {
f: &'f dyn Fn(&Resolver, usize) -> VmOutput,
}
stack.reset();
let resolver = Resolver {
f: &|resolver: &Resolver, op_index: usize| -> VmOutput {
let (opcode, offset) = &code[op_index];
match opcode {
OpCode::UnaryBooleanOperator(op) => match op {
for opcode in code.iter().rev() {
match opcode {
OpCode::UnaryBooleanOperator(op) => {
let operand = stack.boolean_stack.pop().unwrap();
match op {
ast::UnaryBooleanOperator::Not => {
let value = (resolver.f)(resolver, op_index + 1);
match value {
VmOutput::Arithmetic(_) => panic!("Bad bytecode! Unary operator is followed by arithmetic resolution."),
VmOutput::Boolean(value) => VmOutput::Boolean(!value),
}
}
},
OpCode::ComparisonOperator(op) => {
let left_operand = match (resolver.f)(resolver, op_index + 1) {
VmOutput::Arithmetic(value) => value,
VmOutput::Boolean(_) => panic!(
"Bad bytecode! Left operand of arithmetic operator is boolean."
),
};
let right_operand = match (resolver.f)(resolver, op_index + offset) {
VmOutput::Arithmetic(value) => value,
VmOutput::Boolean(_) => panic!(
"Bad bytecode! Right operand of arithmetic operator is boolean."
),
};
fn comparison<T: std::cmp::PartialOrd>(
op: &ComparisonOperator,
left_operand: T,
right_operand: T,
) -> VmOutput {
VmOutput::Boolean(match op {
ast::ComparisonOperator::GreaterOrEqual => {
left_operand.ge(&right_operand)
}
ast::ComparisonOperator::LessOrEqual => {
left_operand.le(&right_operand)
}
ast::ComparisonOperator::GreaterThan => {
left_operand.gt(&right_operand)
}
ast::ComparisonOperator::LessThan => {
left_operand.lt(&right_operand)
}
ast::ComparisonOperator::NotEqual => {
left_operand.ne(&right_operand)
}
ast::ComparisonOperator::Equal => left_operand.eq(&right_operand),
})
};
match left_operand {
ArithmeticValue::Integer(left_operand) => match right_operand {
ArithmeticValue::Integer(right_operand) => {
comparison(op, left_operand, right_operand)
}
ArithmeticValue::Floating(right_operand) => {
comparison(op, left_operand as f64, right_operand)
}
},
ArithmeticValue::Floating(left_operand) => match right_operand {
ArithmeticValue::Integer(right_operand) => {
comparison(op, left_operand, right_operand as f64)
}
ArithmeticValue::Floating(right_operand) => {
comparison(op, left_operand, right_operand)
}
},
stack.boolean_stack.push(!operand);
}
}
OpCode::BinaryArithmeticOperator(op) => {
let left_operand = match (resolver.f)(resolver, op_index + 1) {
VmOutput::Arithmetic(value) => value,
VmOutput::Boolean(_) => panic!(
"Bad bytecode! Left operand of arithmetic operator is boolean."
),
};
let right_operand = match (resolver.f)(resolver, op_index + offset) {
VmOutput::Arithmetic(value) => value,
VmOutput::Boolean(_) => panic!(
"Bad bytecode! Right operand of arithmetic operator is boolean."
),
};
let operations_as_integer = |left_operand: i64, right_operand: i64| match op
{
ast::BinaryArithmeticOperator::Times => {
ArithmeticValue::Integer(left_operand * right_operand)
}
ast::BinaryArithmeticOperator::Divide => {
if left_operand % right_operand == 0 {
ArithmeticValue::Integer(left_operand / right_operand)
} else {
ArithmeticValue::Floating(
left_operand as f64 / right_operand as f64,
)
}
}
ast::BinaryArithmeticOperator::Plus => {
ArithmeticValue::Integer(left_operand + right_operand)
}
ast::BinaryArithmeticOperator::Minus => {
ArithmeticValue::Integer(left_operand - right_operand)
}
ast::BinaryArithmeticOperator::Xor => {
ArithmeticValue::Integer(left_operand ^ right_operand)
}
ast::BinaryArithmeticOperator::Pow => {
if right_operand > 0 {
ArithmeticValue::Integer(left_operand.pow(right_operand as u32))
} else {
ArithmeticValue::Floating(
(left_operand as f64).powi(right_operand as i32),
)
}
}
};
let operations_as_floating =
|left_operand: f64, right_operand: f64| match op {
ast::BinaryArithmeticOperator::Times => {
ArithmeticValue::Floating(left_operand * right_operand)
}
ast::BinaryArithmeticOperator::Divide => ArithmeticValue::Floating(
left_operand as f64 / right_operand as f64,
),
ast::BinaryArithmeticOperator::Plus => {
ArithmeticValue::Floating(left_operand + right_operand)
}
ast::BinaryArithmeticOperator::Minus => {
ArithmeticValue::Floating(left_operand - right_operand)
}
ast::BinaryArithmeticOperator::Xor => ArithmeticValue::Integer(
left_operand as i64 ^ right_operand as i64,
),
ast::BinaryArithmeticOperator::Pow => {
ArithmeticValue::Floating(left_operand.powf(right_operand))
}
};
VmOutput::Arithmetic(match left_operand {
ArithmeticValue::Integer(left_operand) => match right_operand {
ArithmeticValue::Integer(right_operand) => {
operations_as_integer(left_operand, right_operand)
}
ArithmeticValue::Floating(right_operand) => {
operations_as_floating(left_operand as f64, right_operand)
}
},
ArithmeticValue::Floating(left_operand) => match right_operand {
ArithmeticValue::Integer(right_operand) => {
operations_as_floating(left_operand, right_operand as f64)
}
ArithmeticValue::Floating(right_operand) => {
operations_as_floating(left_operand, right_operand)
}
},
})
}
OpCode::UnaryArithmeticOperator(op) => {
let value = match (resolver.f)(resolver, op_index + 1) {
VmOutput::Arithmetic(value) => value,
VmOutput::Boolean(_) => panic!("Bad bytecode! Arithmetic unary operator followed by boolean resolution."),
};
VmOutput::Arithmetic(match op {
ast::UnaryArithmeticOperator::Negative => match value {
ArithmeticValue::Integer(value) => ArithmeticValue::Integer(-value),
ArithmeticValue::Floating(value) => {
ArithmeticValue::Floating(-value)
}
},
ast::UnaryArithmeticOperator::Ham => {
ArithmeticValue::Integer(match value {
ArithmeticValue::Integer(value) => value.count_ones() as i64,
ArithmeticValue::Floating(value) => {
(value as u64).count_ones() as i64
}
})
}
ast::UnaryArithmeticOperator::Sqrt => {
ArithmeticValue::Floating(match value {
ArithmeticValue::Integer(value) => (value as f64).sqrt(),
ArithmeticValue::Floating(value) => value.sqrt(),
})
}
})
}
OpCode::BinaryBooleanOperator(op) => {
let left_operand = match (resolver.f)(resolver, op_index + 1) {
VmOutput::Boolean(value) => value,
VmOutput::Arithmetic(_) => panic!(
"Bad bytecode! Left operand of boolean operator is arithmetic."
),
};
let right_operand = match (resolver.f)(resolver, op_index + offset) {
VmOutput::Boolean(value) => value,
VmOutput::Arithmetic(_) => panic!(
"Bad bytecode! Right operand of boolean operator is arithmetic."
),
};
VmOutput::Boolean(match op {
ast::BinaryBooleanOperator::And => left_operand & right_operand,
ast::BinaryBooleanOperator::Or => left_operand | right_operand,
ast::BinaryBooleanOperator::Xor => left_operand ^ right_operand,
})
}
OpCode::Variable(var) => {
VmOutput::Arithmetic(ArithmeticValue::Integer(match var {
ast::Variable::X => registers.x,
ast::Variable::Y => registers.y,
ast::Variable::N => registers.n,
ast::Variable::P => registers.p,
ast::Variable::K => registers.k,
}))
}
OpCode::Literal(lit) => VmOutput::Arithmetic(ArithmeticValue::Integer(*lit)),
}
},
};
OpCode::BinaryArithmeticOperator(op) => {
let left_operand = stack.arithmetic_stack.pop().unwrap();
let right_operand = stack.arithmetic_stack.pop().unwrap();
let value = match left_operand {
ArithmeticValue::Integer(left_operand) => match right_operand {
ArithmeticValue::Integer(right_operand) => {
operations_as_integer(op, left_operand, right_operand)
}
ArithmeticValue::Floating(right_operand) => {
operations_as_floating(op, left_operand as f64, right_operand)
}
},
ArithmeticValue::Floating(left_operand) => match right_operand {
ArithmeticValue::Integer(right_operand) => {
operations_as_floating(op, left_operand, right_operand as f64)
}
ArithmeticValue::Floating(right_operand) => {
operations_as_floating(op, left_operand, right_operand)
}
},
};
stack.arithmetic_stack.push(value);
}
OpCode::ComparisonOperator(op) => {
let left_operand = stack.arithmetic_stack.pop().unwrap();
let right_operand = stack.arithmetic_stack.pop().unwrap();
let value = match left_operand {
ArithmeticValue::Integer(left_operand) => match right_operand {
ArithmeticValue::Integer(right_operand) => {
comparison(op, left_operand, right_operand)
}
ArithmeticValue::Floating(right_operand) => {
comparison(op, left_operand as f64, right_operand)
}
},
ArithmeticValue::Floating(left_operand) => match right_operand {
ArithmeticValue::Integer(right_operand) => {
comparison(op, left_operand, right_operand as f64)
}
ArithmeticValue::Floating(right_operand) => {
comparison(op, left_operand, right_operand)
}
},
};
stack.boolean_stack.push(value);
}
OpCode::UnaryArithmeticOperator(op) => {
let operand = stack.arithmetic_stack.pop().unwrap();
let value = match op {
ast::UnaryArithmeticOperator::Negative => match operand {
ArithmeticValue::Integer(operand) => ArithmeticValue::Integer(-operand),
ArithmeticValue::Floating(operand) => {
ArithmeticValue::Floating(-operand)
}
},
ast::UnaryArithmeticOperator::Ham => {
ArithmeticValue::Integer(match operand {
ArithmeticValue::Integer(operand) => operand.count_ones() as i64,
ArithmeticValue::Floating(operand) => {
(operand.round() as i64).count_ones() as i64
}
})
}
ast::UnaryArithmeticOperator::Sqrt => {
ArithmeticValue::Floating(match operand {
ArithmeticValue::Integer(operand) => (operand as f64).sqrt(),
ArithmeticValue::Floating(operand) => operand.sqrt(),
})
}
};
stack.arithmetic_stack.push(value);
}
OpCode::BinaryBooleanOperator(op) => {
let left_operand = stack.boolean_stack.pop().unwrap();
let right_operand = stack.boolean_stack.pop().unwrap();
let value = match op {
ast::BinaryBooleanOperator::And => left_operand & right_operand,
ast::BinaryBooleanOperator::Or => left_operand | right_operand,
ast::BinaryBooleanOperator::Xor => left_operand ^ right_operand,
};
stack.boolean_stack.push(value);
}
OpCode::Variable(variable) => {
let value = ArithmeticValue::Integer(match variable {
ast::Variable::X => registers.x,
ast::Variable::Y => registers.y,
ast::Variable::N => registers.n,
ast::Variable::P => registers.p,
ast::Variable::K => registers.k,
});
stack.arithmetic_stack.push(value);
}
OpCode::Literal(literal) => {
stack
.arithmetic_stack
.push(ArithmeticValue::Integer(*literal));
}
}
}
self
}
(resolver.f)(&resolver, 0)
pub fn output_bool(&mut self) -> Result<bool, ()> {
self.stack.boolean_stack.pop().ok_or(())
}
#[allow(unused)]
pub fn output_arithmetic(&mut self) -> Result<ArithmeticValue, ()> {
self.stack.arithmetic_stack.pop().ok_or(())
}
}
@ -356,28 +359,32 @@ fn compile_expression(expression: Expression, code: &mut Vec<Bytecode>) -> usize
Expression::Boolean(expression) => match expression {
ast::BooleanExpression::BinaryBooleanConjunction(expression) => {
let expression = *expression;
code.push((OpCode::BinaryBooleanOperator(expression.operator), 0));
// code.push((OpCode::BinaryBooleanOperator(expression.operator), 0));
code.push(OpCode::BinaryBooleanOperator(expression.operator));
let index = code.len() - 1;
let left_operand_size =
compile_expression(Expression::Boolean(expression.left_operand), code);
let right_operand_size =
compile_expression(Expression::Boolean(expression.right_operand), code);
code[index].1 = left_operand_size + 1;
// code[index].1 = left_operand_size + 1;
return 1 + left_operand_size + right_operand_size;
}
ast::BooleanExpression::UnaryBooleanConjunction(expression) => {
let expression = *expression;
code.push((OpCode::UnaryBooleanOperator(expression.operator), 0));
// code.push((OpCode::UnaryBooleanOperator(expression.operator), 0));
code.push(OpCode::UnaryBooleanOperator(expression.operator));
let operand_size =
compile_expression(Expression::Boolean(expression.operand), code);
return 1 + operand_size;
}
ast::BooleanExpression::ComparisonConjunction(expression) => {
code.push((OpCode::ComparisonOperator(expression.operator), 0));
// code.push((OpCode::ComparisonOperator(expression.operator), 0));
code.push(OpCode::ComparisonOperator(expression.operator));
let index = code.len() - 1;
let left_operand_size = match expression.left_operand {
ast::ArithmeticOperand::Literal(literal) => {
code.push((OpCode::Literal(literal), 0));
// code.push((OpCode::Literal(literal), 0));
code.push(OpCode::Literal(literal));
1_usize
}
ast::ArithmeticOperand::Expression(expression) => {
@ -386,28 +393,32 @@ fn compile_expression(expression: Expression, code: &mut Vec<Bytecode>) -> usize
};
let right_operand_size = match expression.right_operand {
ast::ArithmeticOperand::Literal(literal) => {
code.push((OpCode::Literal(literal), 0));
// code.push((OpCode::Literal(literal), 0));
code.push(OpCode::Literal(literal));
1_usize
}
ast::ArithmeticOperand::Expression(expression) => {
compile_expression(Expression::Arithmetic(*expression), code)
}
};
code[index].1 = left_operand_size + 1;
// code[index].1 = left_operand_size + 1;
return 1 + left_operand_size + right_operand_size;
}
},
Expression::Arithmetic(expression) => match expression {
ast::ArithmeticExpression::Variable(variable) => {
code.push((OpCode::Variable(variable), 0));
// code.push((OpCode::Variable(variable), 0));
code.push(OpCode::Variable(variable));
return 1;
}
ast::ArithmeticExpression::UnaryArithmeticConjunction(expression) => {
let expression = *expression;
code.push((OpCode::UnaryArithmeticOperator(expression.operator), 0));
// code.push((OpCode::UnaryArithmeticOperator(expression.operator), 0));
code.push(OpCode::UnaryArithmeticOperator(expression.operator));
let operand_size = match expression.operand {
ast::ArithmeticOperand::Literal(literal) => {
code.push((OpCode::Literal(literal), 0));
// code.push((OpCode::Literal(literal), 0));
code.push(OpCode::Literal(literal));
1_usize
}
ast::ArithmeticOperand::Expression(expression) => {
@ -417,11 +428,13 @@ fn compile_expression(expression: Expression, code: &mut Vec<Bytecode>) -> usize
return 1 + operand_size;
}
ast::ArithmeticExpression::BinaryArithmeticConjunction(expression) => {
code.push((OpCode::BinaryArithmeticOperator(expression.operator), 0));
// code.push((OpCode::BinaryArithmeticOperator(expression.operator), 0));
code.push(OpCode::BinaryArithmeticOperator(expression.operator));
let index = code.len() - 1;
let left_operand_size = match expression.left_operand {
ast::ArithmeticOperand::Literal(literal) => {
code.push((OpCode::Literal(literal), 0));
// code.push((OpCode::Literal(literal), 0));
code.push(OpCode::Literal(literal));
1_usize
}
ast::ArithmeticOperand::Expression(expression) => {
@ -430,14 +443,15 @@ fn compile_expression(expression: Expression, code: &mut Vec<Bytecode>) -> usize
};
let right_operand_size = match expression.right_operand {
ast::ArithmeticOperand::Literal(literal) => {
code.push((OpCode::Literal(literal), 0));
// code.push((OpCode::Literal(literal), 0));
code.push(OpCode::Literal(literal));
1_usize
}
ast::ArithmeticOperand::Expression(expression) => {
compile_expression(Expression::Arithmetic(*expression), code)
}
};
code[index].1 = left_operand_size + 1;
// code[index].1 = left_operand_size + 1;
return 1 + left_operand_size + right_operand_size;
}
},
@ -452,13 +466,48 @@ fn boolean_compilation_test() {
}
#[test]
fn run_test() {
fn test_vm_simple() {
let expression = parsing::parse_relation("(= (ham (^ x y)) (ham 1))");
if let Err(e) = expression {
println!("{}", e);
panic!();
}
let code = compile_boolean(expression.unwrap());
let vm = Vm::load(&code, Registers::load(0b_1011, 0b_1111, 10, 2, 3));
println!("{:?}", vm.run());
let mut stack = VmStack::from_code(&code);
let mut vm = Vm::load(
&code,
Registers::load(0b_1011, 0b_1111, 10, 2, 3),
&mut stack,
);
let output = vm.run().output_bool().unwrap();
assert_eq!(output, true);
let mut vm = Vm::load(
&code,
Registers::load(0b_1011, 0b_1110, 10, 2, 3),
&mut stack,
);
let output = vm.run().output_bool().unwrap();
assert_eq!(output, false);
}
#[test]
fn test_vm_contrived() {
let expression = parsing::parse_relation("and (= (ham (^ x y)) (ham (+ 3 x))) (> (* x y) 5)");
if let Err(e) = expression {
println!("{}", e);
panic!();
}
let code = compile_boolean(expression.unwrap());
let mut stack = VmStack::from_code(&code);
let as_rust = |x: u64, y: u64| ((x + 3).count_ones() == (x ^ y).count_ones()) && (x * y > 5);
for x in 0..(1 << 4) {
for y in 0..(1 << 4) {
let mut vm = Vm::load(&code, Registers::load(x, y, 10, 2, 3), &mut stack);
let output = vm.run().output_bool().unwrap();
let expected = as_rust(x, y);
assert_eq!(output, expected);
}
}
}

View File

@ -323,6 +323,19 @@ fn rule_as_text(rule: &Rule) -> &'static str {
}
}
#[test]
fn parse_bad() {
match parse_relation("< ham x cheese") {
Err(e) => {
println!("{}", e);
}
Ok(ast) => {
println!("{:?}", ast);
panic!();
}
}
}
#[test]
fn parse_test() {
match parse_relation("< ham x 3") {
@ -331,7 +344,7 @@ fn parse_test() {
panic!();
}
Ok(ast) => {
println!("{:?}", ast)
println!("{:#?}", ast)
}
}
}

View File

@ -1,13 +0,0 @@
import adversary
from math import sqrt
prover = adversary.Prover("= (ham x) k", "= (ham y) (+ k 1)", "<= ham (^ x y) p")
bounds = prover.find_bounds(16, 5, 3);
lower_bound = sqrt(bounds.min_x_relations * bounds.min_y_relations / bounds.max_joint_relations)
print("m =", bounds.min_x_relations)
print(f"From x={bounds.single_bounding_x:b}")
print("m' =", bounds.min_y_relations)
print(f"From y={bounds.single_bounding_y:b}")
print("ℓ·ℓ' =", bounds.max_joint_relations)
print(f"From x={bounds.joint_bounding_x:b} and y={bounds.joint_bounding_y:b} and window={bounds.bounding_window:b}")
print(f"Query lower bounds = {lower_bound}")

962
timing_scaling.svg Normal file
View File

@ -0,0 +1,962 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="227.189mm" height="170.039mm"
viewBox="0 0 644 482"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.2" baseProfile="tiny">
<title>Qt SVG Document</title>
<desc>Generated with Qt</desc>
<defs>
</defs>
<g fill="none" stroke="black" stroke-width="1" fill-rule="evenodd" stroke-linecap="square" stroke-linejoin="bevel" >
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#a0a0a4" stroke-opacity="1" stroke-dasharray="0.5,1" stroke-dashoffset="0" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,422.5 618.5,422.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,422.5 58.5,422.5 " />
<polyline fill="none" vector-effect="none" points="618.5,422.5 613.5,422.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,36.225,430.675)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,36.225,430.675)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,36.225,430.675)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,36.225,430.675)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,36.225,430.675)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,36.225,430.675)"
font-family="Sans" font-size="9" font-weight="400" font-style="normal"
>
<text fill="#000000" fill-opacity="1" stroke="none" xml:space="preserve" x="0" y="0" font-family="Sans" font-size="9" font-weight="400" font-style="normal"
> 0</text>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,36.225,430.675)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#a0a0a4" stroke-opacity="1" stroke-dasharray="0.5,1" stroke-dashoffset="0" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,368.5 618.5,368.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,368.5 58.5,368.5 " />
<polyline fill="none" vector-effect="none" points="618.5,368.5 613.5,368.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,375.331)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,375.331)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,375.331)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,375.331)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,375.331)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,375.331)"
font-family="Sans" font-size="9" font-weight="400" font-style="normal"
>
<text fill="#000000" fill-opacity="1" stroke="none" xml:space="preserve" x="0" y="0" font-family="Sans" font-size="9" font-weight="400" font-style="normal"
> 200</text>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,375.331)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#a0a0a4" stroke-opacity="1" stroke-dasharray="0.5,1" stroke-dashoffset="0" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,313.5 618.5,313.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,313.5 58.5,313.5 " />
<polyline fill="none" vector-effect="none" points="618.5,313.5 613.5,313.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,320.994)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,320.994)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,320.994)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,320.994)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,320.994)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,320.994)"
font-family="Sans" font-size="9" font-weight="400" font-style="normal"
>
<text fill="#000000" fill-opacity="1" stroke="none" xml:space="preserve" x="0" y="0" font-family="Sans" font-size="9" font-weight="400" font-style="normal"
> 400</text>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,320.994)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#a0a0a4" stroke-opacity="1" stroke-dasharray="0.5,1" stroke-dashoffset="0" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,259.5 618.5,259.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,259.5 58.5,259.5 " />
<polyline fill="none" vector-effect="none" points="618.5,259.5 613.5,259.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,265.65)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,265.65)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,265.65)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,265.65)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,265.65)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,265.65)"
font-family="Sans" font-size="9" font-weight="400" font-style="normal"
>
<text fill="#000000" fill-opacity="1" stroke="none" xml:space="preserve" x="0" y="0" font-family="Sans" font-size="9" font-weight="400" font-style="normal"
> 600</text>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,265.65)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#a0a0a4" stroke-opacity="1" stroke-dasharray="0.5,1" stroke-dashoffset="0" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,204.5 618.5,204.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,204.5 58.5,204.5 " />
<polyline fill="none" vector-effect="none" points="618.5,204.5 613.5,204.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,211.313)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,211.313)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,211.313)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,211.313)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,211.313)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,211.313)"
font-family="Sans" font-size="9" font-weight="400" font-style="normal"
>
<text fill="#000000" fill-opacity="1" stroke="none" xml:space="preserve" x="0" y="0" font-family="Sans" font-size="9" font-weight="400" font-style="normal"
> 800</text>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,22.1375,211.313)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#a0a0a4" stroke-opacity="1" stroke-dasharray="0.5,1" stroke-dashoffset="0" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,150.5 618.5,150.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,150.5 58.5,150.5 " />
<polyline fill="none" vector-effect="none" points="618.5,150.5 613.5,150.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,155.969)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,155.969)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,155.969)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,155.969)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,155.969)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,155.969)"
font-family="Sans" font-size="9" font-weight="400" font-style="normal"
>
<text fill="#000000" fill-opacity="1" stroke="none" xml:space="preserve" x="0" y="0" font-family="Sans" font-size="9" font-weight="400" font-style="normal"
> 1000</text>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,155.969)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#a0a0a4" stroke-opacity="1" stroke-dasharray="0.5,1" stroke-dashoffset="0" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,95.5 618.5,95.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,95.5 58.5,95.5 " />
<polyline fill="none" vector-effect="none" points="618.5,95.5 613.5,95.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,101.631)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,101.631)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,101.631)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,101.631)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,101.631)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,101.631)"
font-family="Sans" font-size="9" font-weight="400" font-style="normal"
>
<text fill="#000000" fill-opacity="1" stroke="none" xml:space="preserve" x="0" y="0" font-family="Sans" font-size="9" font-weight="400" font-style="normal"
> 1200</text>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,101.631)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#a0a0a4" stroke-opacity="1" stroke-dasharray="0.5,1" stroke-dashoffset="0" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,41.5 618.5,41.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,41.5 58.5,41.5 " />
<polyline fill="none" vector-effect="none" points="618.5,41.5 613.5,41.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,46.2875)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,46.2875)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,46.2875)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,46.2875)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,46.2875)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,46.2875)"
font-family="Sans" font-size="9" font-weight="400" font-style="normal"
>
<text fill="#000000" fill-opacity="1" stroke="none" xml:space="preserve" x="0" y="0" font-family="Sans" font-size="9" font-weight="400" font-style="normal"
> 1400</text>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,15.0938,46.2875)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#a0a0a4" stroke-opacity="1" stroke-dasharray="0.5,1" stroke-dashoffset="0" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="110.5,449.5 110.5,14.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="110.5,449.5 110.5,444.5 " />
<polyline fill="none" vector-effect="none" points="110.5,14.5 110.5,19.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,103.141,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,103.141,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,103.141,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,103.141,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,103.141,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,103.141,471.931)"
font-family="Sans" font-size="9" font-weight="400" font-style="normal"
>
<text fill="#000000" fill-opacity="1" stroke="none" xml:space="preserve" x="0" y="0" font-family="Sans" font-size="9" font-weight="400" font-style="normal"
> 15</text>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,103.141,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#a0a0a4" stroke-opacity="1" stroke-dasharray="0.5,1" stroke-dashoffset="0" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="197.5,449.5 197.5,14.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="197.5,449.5 197.5,444.5 " />
<polyline fill="none" vector-effect="none" points="197.5,14.5 197.5,19.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,189.678,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,189.678,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,189.678,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,189.678,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,189.678,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,189.678,471.931)"
font-family="Sans" font-size="9" font-weight="400" font-style="normal"
>
<text fill="#000000" fill-opacity="1" stroke="none" xml:space="preserve" x="0" y="0" font-family="Sans" font-size="9" font-weight="400" font-style="normal"
> 16</text>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,189.678,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#a0a0a4" stroke-opacity="1" stroke-dasharray="0.5,1" stroke-dashoffset="0" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="283.5,449.5 283.5,14.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="283.5,449.5 283.5,444.5 " />
<polyline fill="none" vector-effect="none" points="283.5,14.5 283.5,19.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,277.222,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,277.222,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,277.222,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,277.222,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,277.222,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,277.222,471.931)"
font-family="Sans" font-size="9" font-weight="400" font-style="normal"
>
<text fill="#000000" fill-opacity="1" stroke="none" xml:space="preserve" x="0" y="0" font-family="Sans" font-size="9" font-weight="400" font-style="normal"
> 17</text>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,277.222,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#a0a0a4" stroke-opacity="1" stroke-dasharray="0.5,1" stroke-dashoffset="0" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="370.5,449.5 370.5,14.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="370.5,449.5 370.5,444.5 " />
<polyline fill="none" vector-effect="none" points="370.5,14.5 370.5,19.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,363.759,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,363.759,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,363.759,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,363.759,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,363.759,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,363.759,471.931)"
font-family="Sans" font-size="9" font-weight="400" font-style="normal"
>
<text fill="#000000" fill-opacity="1" stroke="none" xml:space="preserve" x="0" y="0" font-family="Sans" font-size="9" font-weight="400" font-style="normal"
> 18</text>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,363.759,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#a0a0a4" stroke-opacity="1" stroke-dasharray="0.5,1" stroke-dashoffset="0" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="456.5,449.5 456.5,14.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="456.5,449.5 456.5,444.5 " />
<polyline fill="none" vector-effect="none" points="456.5,14.5 456.5,19.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,451.303,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,451.303,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,451.303,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,451.303,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,451.303,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,451.303,471.931)"
font-family="Sans" font-size="9" font-weight="400" font-style="normal"
>
<text fill="#000000" fill-opacity="1" stroke="none" xml:space="preserve" x="0" y="0" font-family="Sans" font-size="9" font-weight="400" font-style="normal"
> 19</text>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,451.303,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#a0a0a4" stroke-opacity="1" stroke-dasharray="0.5,1" stroke-dashoffset="0" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="543.5,449.5 543.5,14.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="543.5,449.5 543.5,444.5 " />
<polyline fill="none" vector-effect="none" points="543.5,14.5 543.5,19.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,537.841,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,537.841,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,537.841,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,537.841,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,537.841,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,537.841,471.931)"
font-family="Sans" font-size="9" font-weight="400" font-style="normal"
>
<text fill="#000000" fill-opacity="1" stroke="none" xml:space="preserve" x="0" y="0" font-family="Sans" font-size="9" font-weight="400" font-style="normal"
> 20</text>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,537.841,471.931)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,14.5 52.5,449.5 618.5,449.5 618.5,14.5 52.5,14.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#9400d3" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="109.5,422.5 112.5,422.5 112.5,422.5 109.5,422.5 109.5,422.5 " />
<polyline fill="none" vector-effect="none" points="110.5,422.5 110.5,422.5 " />
<polyline fill="none" vector-effect="none" points="110.5,422.5 110.5,422.5 " />
<polyline fill="none" vector-effect="none" points="195.5,422.5 198.5,422.5 198.5,421.5 195.5,421.5 195.5,422.5 " />
<polyline fill="none" vector-effect="none" points="197.5,422.5 197.5,422.5 " />
<polyline fill="none" vector-effect="none" points="197.5,421.5 197.5,420.5 " />
<polyline fill="none" vector-effect="none" points="282.5,422.5 285.5,422.5 285.5,419.5 282.5,419.5 282.5,422.5 " />
<polyline fill="none" vector-effect="none" points="283.5,423.5 283.5,422.5 " />
<polyline fill="none" vector-effect="none" points="283.5,419.5 283.5,416.5 " />
<polyline fill="none" vector-effect="none" points="368.5,422.5 371.5,422.5 371.5,400.5 368.5,400.5 368.5,422.5 " />
<polyline fill="none" vector-effect="none" points="370.5,425.5 370.5,422.5 " />
<polyline fill="none" vector-effect="none" points="370.5,400.5 370.5,396.5 " />
<polyline fill="none" vector-effect="none" points="455.5,422.5 457.5,422.5 457.5,356.5 455.5,356.5 455.5,422.5 " />
<polyline fill="none" vector-effect="none" points="456.5,434.5 456.5,422.5 " />
<polyline fill="none" vector-effect="none" points="456.5,356.5 456.5,317.5 " />
<polyline fill="none" vector-effect="none" points="541.5,422.5 544.5,422.5 544.5,234.5 541.5,234.5 541.5,422.5 " />
<polyline fill="none" vector-effect="none" points="543.5,449.5 543.5,422.5 " />
<polyline fill="none" vector-effect="none" points="543.5,234.5 543.5,41.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#009e73" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,422.5 52.5,422.5 58.2,422.5 63.9,422.4 69.7,422.4 75.4,422.4 81.1,422.4 86.8,422.4 92.5,422.3 98.3,422.3 104,422.3 109.7,422.2 115.4,422.2 121.2,422.2 126.9,422.1 132.6,422.1 138.3,422 144,421.9 149.8,421.9 155.5,421.8 161.2,421.7 166.9,421.6 172.6,421.5 178.4,421.4 184.1,421.3 189.8,421.2 195.5,421.1 201.3,420.9 207,420.7 212.7,420.6 218.4,420.4 224.1,420.1 229.9,419.9 235.6,419.6 241.3,419.4 247,419 252.7,418.7 258.5,418.3 264.2,417.9 269.9,417.5 275.6,417 281.3,416.4 287.1,415.8 292.8,415.2 298.5,414.4 304.2,413.7 310,412.8 315.7,411.8 321.4,410.8 327.1,409.7 332.8,408.4 338.6,407.1 344.3,405.6 350,403.9 355.7,402.1 361.4,400.2 367.2,398 372.9,395.6 378.6,393 384.3,390.2 390.1,387.1 395.8,383.7 401.5,379.9 407.2,375.8 412.9,371.3 418.7,366.4 424.4,361 430.1,355.1 435.8,348.6 441.5,341.4 447.3,333.6 453,325.1 458.7,315.7 464.4,305.4 470.1,294.2 475.9,281.8 481.6,268.3 487.3,253.5 493,237.2 498.8,219.4 504.5,199.8 510.2,178.4 515.9,155 521.6,129.2 527.4,101 533.1,70.1 538.8,36.2 538.8,36.2 542.2,14 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<polyline fill="none" vector-effect="none" points="52.5,14.5 52.5,449.5 618.5,449.5 618.5,14.5 52.5,14.5 " />
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1.00625,0,0,1.00625,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 53 KiB