Skip to content

Commit

Permalink
Docs: add validators API (#211)
Browse files Browse the repository at this point in the history
  • Loading branch information
fushar authored Dec 14, 2024
1 parent b820bdc commit 4029628
Show file tree
Hide file tree
Showing 8 changed files with 225 additions and 39 deletions.
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

0 comments on commit 4029628

Please sign in to comment.