Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs: add validators API #211

Merged
merged 1 commit into from
Dec 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 33 additions & 33 deletions include/tcframe/validator/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,23 @@ inline ScalarValidator<T> valueOf(T val) {
template<typename T, typename = ScalarType<T>>
struct VectorElementValidator {
private:
const vector<T>& val;
const vector<T>& vec;

public:
explicit VectorElementValidator(const vector<T>& _val) : val(_val) {}
explicit VectorElementValidator(const vector<T>& _vec) : vec(_vec) {}

bool isBetween(T minVal, T maxVal) {
for (T v : val) {
if (!valueOf(v).isBetween(minVal, maxVal)) {
for (T e : vec) {
if (!valueOf(e).isBetween(minVal, maxVal)) {
return false;
}
}
return true;
}

bool satisfies(function<bool(T)> predicate) {
for (T v : val) {
if (!predicate(v)) {
for (T e : vec) {
if (!predicate(e)) {
return false;
}
}
Expand All @@ -63,98 +63,98 @@ struct VectorElementValidator {
};

template<typename T, typename = ScalarType<T>>
inline VectorElementValidator<T> eachElementOf(const vector<T>& val) {
return VectorElementValidator(val);
inline VectorElementValidator<T> eachElementOf(const vector<T>& vec) {
return VectorElementValidator(vec);
}

template<typename T, typename = ScalarType<T>>
struct VectorElementsValidator {
private:
const vector<T>& val;
const vector<T>& vec;

public:
explicit VectorElementsValidator(const vector<T>& _val) : val(_val) {}
explicit VectorElementsValidator(const vector<T>& _vec) : vec(_vec) {}

bool areAscending() {
for (size_t i = 1; i < val.size(); ++i) {
if (val[i - 1] >= val[i]) {
for (size_t i = 1; i < vec.size(); ++i) {
if (vec[i - 1] >= vec[i]) {
return false;
}
}
return true;
}

bool areDescending() {
for (size_t i = 1; i < val.size(); ++i) {
if (val[i - 1] <= val[i]) {
for (size_t i = 1; i < vec.size(); ++i) {
if (vec[i - 1] <= vec[i]) {
return false;
}
}
return true;
}

bool areNonAscending() {
for (size_t i = 1; i < val.size(); ++i) {
if (val[i - 1] < val[i]) {
for (size_t i = 1; i < vec.size(); ++i) {
if (vec[i - 1] < vec[i]) {
return false;
}
}
return true;
}

bool areNonDescending() {
for (size_t i = 1; i < val.size(); ++i) {
if (val[i - 1] > val[i]) {
for (size_t i = 1; i < vec.size(); ++i) {
if (vec[i - 1] > vec[i]) {
return false;
}
}
return true;
}

bool areUnique() {
vector<T> v = val;
vector<T> v = vec;
sort(v.begin(), v.end());
size_t ns = unique(v.begin(), v.end()) - v.begin();
return ns == v.size();
}
};

template<typename T, typename = ScalarType<T>>
inline VectorElementsValidator<T> elementsOf(const vector<T>& val) {
return VectorElementsValidator(val);
inline VectorElementsValidator<T> elementsOf(const vector<T>& vec) {
return VectorElementsValidator(vec);
}

struct StringElementValidator {
private:
const string& val;
const string& str;

public:
explicit StringElementValidator(const string& _val) : val(_val) {}
explicit StringElementValidator(const string& _str) : str(_str) {}

bool isBetween(char minVal, char maxVal) {
for (char v : val) {
if (!valueOf(v).isBetween(minVal, maxVal)) {
for (char c : str) {
if (!valueOf(c).isBetween(minVal, maxVal)) {
return false;
}
}
return true;
}
};

inline StringElementValidator eachCharacterOf(const string& val) {
return StringElementValidator(val);
inline StringElementValidator eachCharacterOf(const string& str) {
return StringElementValidator(str);
}

template<typename T, typename = ScalarType<T>>
struct MatrixElementValidator {
private:
const vector<vector<T>>& val;
const vector<vector<T>>& mat;

public:
explicit MatrixElementValidator(const vector<vector<T>>& _val) : val(_val) {}
explicit MatrixElementValidator(const vector<vector<T>>& _mat) : mat(_mat) {}

bool isBetween(T minVal, T maxVal) {
for (const vector<T>& v : val) {
for (const vector<T>& v : mat) {
if (!eachElementOf(v).isBetween(minVal, maxVal)) {
return false;
}
Expand All @@ -163,7 +163,7 @@ struct MatrixElementValidator {
}

bool satisfies(function<bool(T)> predicate) {
for (const vector<T>& v : val) {
for (const vector<T>& v : mat) {
if (!eachElementOf(v).satisfies(predicate)) {
return false;
}
Expand All @@ -173,8 +173,8 @@ struct MatrixElementValidator {
};

template<typename T, typename = ScalarType<T>>
inline MatrixElementValidator<T> eachElementOf(const vector<vector<T>>& val) {
return MatrixElementValidator(val);
inline MatrixElementValidator<T> eachElementOf(const vector<vector<T>>& mat) {
return MatrixElementValidator(mat);
}

}
174 changes: 174 additions & 0 deletions web/docs/api/04-validators/01-core.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
---
toc_max_heading_level: 4
---

# Core validators

## Validating a scalar value

A scalar type is defined as:

```cpp
template<typename T>
using ScalarType = std::enable_if_t<std::is_arithmetic_v<T>>;
```

Or in simple words, it includes `int`, `long long`, `double`, and `char`.

To instantiate the validator for a value, say `val`, call the following function:

### `valueOf(val)`

```cpp
template<typename T, typename = ScalarType<T>>
ScalarValidator<T> valueOf(T val);
```

This validator contains the following function:

#### `.isBetween()`

```cpp
bool ScalarValidator<T>::isBetween(T minVal, T maxVal);
```

Returns whether `val` is between `minVal` and `maxVal`, inclusive.

---

## Validating each element of a vector

To instantiate the validator for a each element of a vector, say `vec`, call the following function:

### `eachElementOf(vec)`

```cpp
template<typename T, typename = ScalarType<T>>
VectorElementValidator<T> eachElementOf(const std::vector<T>& vec);
```

This validator contains the following functions:

#### `.isBetween()`

```cpp
bool VectorElementValidator<T>::isBetween(T minVal, T maxVal);
```

Returns whether each element of `vec` is between `minVal` and `maxVal`, inclusive.

#### `.satisfies()`

```cpp
bool VectorElementValidator<T>::satisfies(std::function<bool(T)> predicate);
```

Returns whether `predicate(e)` returns true for each `e` element of `vec`.

---

## Validating each element of a matrix

To instantiate the validator for a each element of a matrix, say `mat`, call the following function:

### `eachElementOf(mat)`

```cpp
template<typename T, typename = ScalarType<T>>
MatrixElementValidator<T> eachElementOf(const std::vector<std::vector<T>>& mat);
```

This validator contains the following functions:

#### `.isBetween()`

```cpp
bool MatrixElementValidator<T>::isBetween(T minVal, T maxVal);
```

Returns whether each element of `mat` is between `minVal` and `maxVal`, inclusive.

#### `.satisfies()`

```cpp
bool MatrixElementValidator<T>::satisfies(std::function<bool(T)> predicate);
```

Returns whether `predicate(e)` returns true for each `e` element of `mat`.

---

## Validating each character of a string

To instantiate the validator for a each character of a string, say `str`, call the following function:

### `eachCharacterOf(str)`

```cpp
StringElementValidator eachCharacterOf(const std::string& str);
```

This validator contains the following functions:

#### `.isBetween()`

```cpp
bool StringElementValidator::isBetween(char minVal, char maxVal);
```

Returns whether each character of `str` is between `minVal` and `maxVal`, inclusive.

---

## Validating all elements of a vector

To instantiate the validator for all elements of a vector, say `vec`, call the following function:

### `elementsOf(vec)`

```cpp
template<typename T, typename = ScalarType<T>>
VectorElementsValidator<T> elementsOf(const std::vector<T>& vec);
```

This validator contains the following functions:

#### `.areAscending()`

```cpp
bool VectorElementsValidator<T>::areAscending();
```

Returns whether the elements of `vec` are in a strictly ascending order.

#### `.areDescending()`

```cpp
bool VectorElementsValidator<T>::areDescending();
```

Returns whether the elements of `vec` are in a strictly descending order.

#### `.areNonAscending()`

```cpp
bool VectorElementsValidator<T>::areNonAscending();
```

Returns whether the elements of `vec` are in a non-ascending order.

#### `.areNonDescending()`

```cpp
bool VectorElementsValidator<T>::areNonDescending();
```

Returns whether the elements of `vec` are in a non-descending order.

#### `.areUnique()`

```cpp
bool VectorElementsValidator<T>::areUnique();
```

Returns whether the elements of `vec` are unique (all different).
5 changes: 5 additions & 0 deletions web/docs/api/04-validators/_category_.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
label: Validators
link:
type: generated-index
slug: /api/validators
description: TCFrame provides several validators, which can be used to validate the I/O variables in problem spec.
File renamed without changes.
File renamed without changes.
13 changes: 10 additions & 3 deletions web/docs/topic-guides/05-constraints.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ void Constraints() {
}
```

The constraint definition can be pulled directly from the constraints section in the actual problem description. For example: "1 ≤ **A** ≤ 1,000" can be specified by `CONS(1 <= A && A <= 1000)`. "1 ≤ **A**, **B** ≤ 1,000" translates into two specifications: `CONS(1 <= A && A <= 1000)` and `CONS(1 <= B && B <= 1000)`. "1 ≤ **A** ≤ **B** ≤ 1,000" translates into `CONS(1 <= A && A <= B && B <= 1000)`.
The constraint definition can be pulled directly from the constraints section in the actual problem description. For example:

- "1 ≤ **A** ≤ 1,000" can be specified by `CONS(1 <= A && A <= 1000)`.
- "1 ≤ **A**, **B** ≤ 1,000" translates into two specifications: `CONS(1 <= A && A <= 1000)` and `CONS(1 <= B && B <= 1000)`.
- "1 ≤ **A** ≤ **B** ≤ 1,000" translates into `CONS(1 <= A && A <= B && B <= 1000)`.

How about more complex predicates, such as "1 ≤ **A**[i] ≤ 1,000"? You can write a private method for this purpose. For example, it can be translated into `CONS(eachElementBetween(A, 1, 1000))` and a private method as follows:

Expand All @@ -41,6 +45,9 @@ bool eachElementBetween(const vector<int>& X, int lo, int hi) {

This also applies to even more complex predicates, such as "It is guaranteed that the given graph is a tree". This can be translated to `CONS(graphIsTree())` and define the appropriate private boolean method.

## Notes
## Using built-in validators

To simplify constraint specifications, TCFrame provides built-in [validators](../api/validators). For example:

It is tedious to write `eachElementBetween()` predicate over and over again as it is very common in problems. We are working on providing such helper methods as core part of TCFrame in the next versions.
- `CONS(1 <= A && A <= 1000)` can be rewritten as `CONS(valueOf(A).isBetween(1, 1000))`
- `CONS(eachElementBetween(A, 1, 1000))` and the `eachElementBetween()` function can be rewritten as `CONS(eachElementOf(A).isBetween(1, 1000))`.
2 changes: 1 addition & 1 deletion web/docs/topic-guides/11-grading.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ This will override what is set in `GradingConfig()`.

## Helper programs

If [helper programs](../api/helper) are present, they must be compiled prior to the local grading.
If [helper programs](../api/helpers) are present, they must be compiled prior to the local grading.

### Scorer

Expand Down
4 changes: 2 additions & 2 deletions web/src/components/HomepageFeatures/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ void OutputFormat() {

const constraints =
`void Constraints() {
CONS(1 <= N && N <= 1000);
CONS(eachElementBetween(A, 1, 1000000));
CONS(valueOf(N).isBetween(1, 1000);
CONS(eachElementOf(A).isBetween(1, 10));
}`

const testCases =
Expand Down
Loading