Skip to content

Commit f57dd61

Browse files
committed
Initial implementation of iospec
1 parent 279ff54 commit f57dd61

File tree

159 files changed

+9434
-11
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

159 files changed

+9434
-11
lines changed

Diff for: Cargo.lock

+277-11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ task-maker-cache = { path = "./task-maker-cache" }
4444
task-maker-exec = { path = "./task-maker-exec" }
4545
task-maker-lang = { path = "./task-maker-lang" } # needed only by typescriptify
4646
task-maker-format = { path = "./task-maker-format" }
47+
task-maker-iospec = { path = "./task-maker-iospec" }
4748

4849
# Logging and setting up the global logger
4950
log = "0.4"

Diff for: src/tools/main.rs

+5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use task_maker_rust::tools::task_info::main_task_info;
1414
use task_maker_rust::tools::typescriptify::main_typescriptify;
1515
use task_maker_rust::tools::worker::main_worker;
1616

17+
use task_maker_iospec::tools::*;
18+
1719
fn main() {
1820
let base_opt = Opt::parse();
1921
base_opt.logger.enable_log();
@@ -30,6 +32,9 @@ fn main() {
3032
Tool::Booklet(opt) => main_booklet(opt, base_opt.logger),
3133
Tool::FuzzChecker(opt) => main_fuzz_checker(opt),
3234
Tool::AddSolutionChecks(opt) => main_add_solution_checks(opt, base_opt.logger),
35+
Tool::IospecCheck(opt) => iospec_check::do_main(opt, &mut std::io::stderr()),
36+
Tool::IospecGen(opt) => iospec_gen::do_main(opt, &mut std::io::stderr()),
37+
Tool::IospecGenAll(opt) => iospec_gen_all::do_main(opt, &mut std::io::stderr()),
3338
Tool::InternalSandbox => return task_maker_rust::main_sandbox(),
3439
}
3540
.nice_unwrap()

Diff for: src/tools/opt.rs

+8
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use crate::tools::task_info::TaskInfoOpt;
1212
use crate::tools::worker::WorkerOpt;
1313
use crate::LoggerOpt;
1414

15+
use task_maker_iospec::tools::*;
16+
1517
#[derive(Parser, Debug)]
1618
#[clap(name = "task-maker-tools")]
1719
pub struct Opt {
@@ -49,6 +51,12 @@ pub enum Tool {
4951
FuzzChecker(FuzzCheckerOpt),
5052
/// Add the @check comments to the solutions.
5153
AddSolutionChecks(AddSolutionChecksOpt),
54+
/// Check input/output files against a specification in the `iospec` language.
55+
IospecCheck(iospec_check::Opt),
56+
/// Generate graders or other I/O-related files given a specification in the `iospec` language.
57+
IospecGen(iospec_gen::Opt),
58+
/// Generate standard set of files given an I/O format specification in the `iospec` language.
59+
IospecGenAll(iospec_gen_all::Opt),
5260
/// Run the sandbox instead of the normal task-maker.
5361
///
5462
/// This option is left as undocumented as it's not part of the public API.

Diff for: task-maker-exec/tmbox

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit c282fbae959d34597439f0cba5067c9728620ea9

Diff for: task-maker-iospec/Cargo.toml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "task-maker-iospec"
3+
version = "0.5.4"
4+
authors = ["Massimo Cairo <[email protected]>"]
5+
edition = "2021"
6+
7+
[dependencies]
8+
syn = { version = "1.0.92", features = ["extra-traits"] }
9+
proc-macro2 = { version = "1.0.19", features = ["span-locations"] }
10+
annotate-snippets = { version = "0.9.0", features = ["color"] }
11+
codemap = "0.1.3"
12+
num-traits = "0.2.12"
13+
by_address = "1.0.4"
14+
anyhow = "1.0.57"
15+
clap = "3.1.18"
16+
structopt = "0.3.26"
17+
18+
[dev-dependencies]
19+
assert_cmd = "2.0.4"
20+
goldenfile = "1.1.0"
21+
tempdir = "0.3.7"
22+
tempfile = "3.3.0"
23+
walkdir = "2.3.2"

Diff for: task-maker-iospec/rustfmt.toml

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
unstable_features = true
2+
imports_granularity = "Item"

Diff for: task-maker-iospec/src/assets/IOSPEC.sample

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//! Sample I/O specification.
2+
//! The input is a graph, with weights on the nodes.
3+
//! The output is a single value, followed by a value for each node.
4+
5+
inputln {
6+
/// Number of nodes
7+
item N: i32;
8+
assume 2 <= N < 100_000;
9+
10+
/// Number of edges
11+
item M: i32;
12+
assume 0 <= M < 500_000;
13+
}
14+
15+
#[cfg(subtask_name = "quadratic")]
16+
assume N <= 1_000;
17+
18+
inputln {
19+
for u upto N {
20+
/// Weight of `u`
21+
item W[u]: i32;
22+
assume 0 <= W[u] < 1_000_000_000;
23+
}
24+
}
25+
26+
for i upto M {
27+
inputln {
28+
/// Tail of `i`-th edge
29+
item A[i]: i32;
30+
/// Head of `i`-th edge
31+
item B[i]: i32;
32+
33+
assume 0 <= A[i] < N;
34+
assume 0 <= B[i] < N;
35+
36+
/// No self-loops
37+
assume A[i] != B[i];
38+
}
39+
}
40+
41+
#[cfg(grader)]
42+
/// Compute `S` and `X[u]` for every node `u`
43+
@call solve(N = N, M = M, W = W, A = A, B = B, X = &X) -> S;
44+
45+
outputln {
46+
item S: i32;
47+
}
48+
49+
outputln {
50+
for u upto N {
51+
item X[u]: i32;
52+
}
53+
}

Diff for: task-maker-iospec/src/assets/iolib.hpp

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/// Template library to read/write I/O files.
2+
/// Do not modify.
3+
4+
#ifndef GENERATOR_HPP
5+
#define GENERATOR_HPP
6+
7+
#include <iostream>
8+
#include <cassert>
9+
10+
const bool INPUT = 0;
11+
const bool OUTPUT = 1;
12+
13+
template<typename IoData>
14+
void resize_all(IoData const& data) {
15+
bool needs_space = false;
16+
process_io(
17+
const_cast<IoData&>(data),
18+
{},
19+
[](auto stream, auto& value) {},
20+
[](auto stream) {},
21+
[](auto stream, auto value) {},
22+
[](auto stream, auto& value, auto size) {
23+
value.resize(size);
24+
}
25+
);
26+
}
27+
28+
template<typename IoData, typename File = std::ostream>
29+
void write_input(IoData const& data, File& file = std::cout) {
30+
bool needs_space = false;
31+
process_io(
32+
const_cast<IoData&>(data),
33+
{},
34+
[&](auto stream, auto& value) {
35+
if(stream == INPUT) {
36+
if(needs_space) file << " ";
37+
file << value;
38+
needs_space = true;
39+
}
40+
},
41+
[&](auto stream) {
42+
if(stream == INPUT) {
43+
file << std::endl;
44+
needs_space = false;
45+
}
46+
},
47+
[](auto stream, auto value) {},
48+
[](auto stream, auto& value, auto size) {
49+
if (stream == INPUT) {
50+
assert(value.size() == size);
51+
}
52+
value.resize(size);
53+
}
54+
);
55+
}
56+
57+
template<typename IoData, typename File = std::istream>
58+
IoData read_input(File& file = std::cin) {
59+
IoData data;
60+
61+
process_io(
62+
data,
63+
{},
64+
[&](auto stream, auto& value) {
65+
if(stream == INPUT) {
66+
file >> value;
67+
}
68+
},
69+
[](auto stream) {},
70+
[](auto stream, auto value) {},
71+
[](auto stream, auto& value, auto size) {
72+
value.resize(size);
73+
}
74+
);
75+
76+
return data;
77+
}
78+
79+
template<typename IoData, typename File = std::istream>
80+
IoData run_solution(File& file = std::cin) {
81+
IoData data;
82+
83+
process_io(
84+
data,
85+
IoData::global_funs(),
86+
[&](auto stream, auto& value) {
87+
if(stream == INPUT) {
88+
file >> value;
89+
}
90+
},
91+
[](auto stream) {},
92+
[](auto stream, auto value) {},
93+
[](auto stream, auto& value, auto size) {
94+
value.resize(size);
95+
}
96+
);
97+
98+
return data;
99+
}
100+
101+
template<typename IoData, typename IFile = std::istream, typename OFile = std::istream>
102+
IoData read_input_output(IFile& input_file, OFile& output_file) {
103+
IoData data;
104+
105+
process_io(
106+
data,
107+
{},
108+
[&](auto stream, auto& value) {
109+
if(stream == INPUT) {
110+
input_file >> value;
111+
}
112+
if(stream == OUTPUT) {
113+
output_file >> value;
114+
}
115+
},
116+
[](auto stream) {},
117+
[](auto stream, auto value) {
118+
/* */
119+
}
120+
);
121+
122+
return data;
123+
}
124+
125+
#endif

Diff for: task-maker-iospec/src/assets/sample.checker.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include "iolib.hpp"
2+
#include "iospec.hpp"
3+
4+
#include <cassert>
5+
#include <fstream>
6+
7+
int main(int argc, char** argv) {
8+
std::ifstream input(argv[1]);
9+
std::ifstream correct_output(argv[2]);
10+
std::ifstream submission_output(argv[3]);
11+
12+
IoData correct_data = read_input_output<IoData>(input, correct_output);
13+
IoData submission_data = read_input_output<IoData>(input, submission_output);
14+
15+
// Check `submission_data` against `correct_data`, e.g.:
16+
// assert(submission_data.S == correct_data.S);
17+
18+
// TODO: verify output format and assertions in task-maker, before calling the custom checker
19+
20+
return 0;
21+
}

Diff for: task-maker-iospec/src/assets/sample.generator.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include "iolib.hpp"
2+
#include "iospec.hpp"
3+
4+
int main(int argc, char** argv) {
5+
IoData data;
6+
7+
// Fill-in `data` with generated values, e.g.:
8+
// data.N = atol(argv[1]);
9+
10+
write_input(data);
11+
12+
return 0;
13+
}

Diff for: task-maker-iospec/src/assets/sample.validator.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include "iolib.hpp"
2+
#include "iospec.hpp"
3+
4+
#include <cassert>
5+
#include <fstream>
6+
7+
int main(int argc, char** argv) {
8+
std::ifstream input(argv[1]);
9+
auto data = read_input<IoData>(input);
10+
11+
// Check any non-trivial assumptions here, e.g.:
12+
// assert(is_prime_number(data.N));
13+
// assert(is_graph_connected(data));
14+
15+
// TODO: verify input format and assumptions in task-maker, before calling the custom validator
16+
17+
return 0;
18+
}

Diff for: task-maker-iospec/src/bin/iospec-check.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
use task_maker_iospec::tools::iospec_check::*;
2+
3+
fn main() -> Result<(), anyhow::Error> {
4+
return do_main(clap::Parser::parse(), &mut std::io::stderr());
5+
}

Diff for: task-maker-iospec/src/bin/iospec-gen.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
use task_maker_iospec::tools::iospec_gen::*;
2+
3+
fn main() -> Result<(), anyhow::Error> {
4+
return do_main(clap::Parser::parse(), &mut std::io::stderr());
5+
}

0 commit comments

Comments
 (0)