Skip to content

Commit

Permalink
Merge pull request #160 from Benezivas/docs_problem_creation
Browse files Browse the repository at this point in the history
Docs problem creation
  • Loading branch information
ImogenBits authored Jan 8, 2024
2 parents aefbb6b + a0590d1 commit 42d2160
Show file tree
Hide file tree
Showing 23 changed files with 2,430 additions and 33 deletions.
2 changes: 2 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ ignore = D105, D401, E302, W503
exclude =
.git,
__pycache__,
.project,
docs/src
ignore_decorators=inherit_docs
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ docker container that only needs to adhere to an I/O structure of your
choice (by default, in the form of `json`-files.)

If you are interested in how to use the framework for a
lab course of your own, please consult our
[teaching concept](https://www.algobattle.org/docs/teaching_concept/english).
lab course of your own, please consult the teaching concept in
the [documentation](https://www.algobattle.org/docs/).
# Installation and Usage
This project is developed and tested on all major operating systems.

Expand Down
2 changes: 1 addition & 1 deletion docs/advanced/config.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Settings

You can configure Algobattle in a lot of different ways, so it does exactly what you want it to do
You can configure Algobattle in a lot of different ways, so that it does exactly what you want it to do.

!!! question "Unsure about TOML syntax?"
TOML syntax can be a bit confusing if you're unfamiliar with it, a full explanation of it can be found on
Expand Down
143 changes: 143 additions & 0 deletions docs/advanced/problems.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Problems

If you're currently a student in an Algobattle lab course, you've probably wondered how exactly the problems work, found
weird behaviour that you think might be a bug, or wanted to find out the exact file format it will accept. This page
teaches you how to get all that info from just the files you've already got in your Algobattle project folder!

!!! note
This page goes over the anatomy of an Algobattle problem and how you can get what you're looking for from your
project folder. This means it's mainly aimed at students who are trying to get more familiar with the course or a
particular problem they're dealing with and course instructors who want to get an overview over how they work.
If you instead are a course instructor looking to make a problem from scratch the
[instructor tutorial](../instructor/problem_basic.md) has more detailed info on that process.

## Overall Structure

A typical problem file looks something like this

```py title="problem.py"
{!> problem/problem.py !}
```

What exactly the problems we discuss here are about is not important for this guide. If you're still curious you can
find them all in our
[Algobattle problems](https://github.com/Benezivas/algobattle-problems/) repo with
additional explanations. We will now go through this file and explain what each section does.

## The Instance Class

This class defines what each instance of the problem will look like. It both tells you what your generator needs to
create and what input your solver will receive. At the top of the class you will find a block of attribute definitions.
In our case this is only a single line.

```py hl_lines="1 8"
{!> problem/instance.py !}
```

This tells us that each instance's json file contains a single key, `job_lengths`, which maps to a list of Timespans.
As we can see from the type alias above the class definition, a Timespan just is an integer between 0 and
(2^64^ - 1) / 5. What that means is that if you're programming your generator you must ensure to not output any numbers
that do not fall in this range, and when implementing your solver you can safely assume that all inputs you will receive
are in it.

### Instance Size

The instance size is defined by the `size` property.

```py hl_lines="10-12"
{!> problem/instance.py !}
```

!!! note
You should not include a `size` key in your instances. It will be computed from other attributes of the instance.

### Additional Validation

Some problem instances, like this one for the Hikers problem, also include a `validate_instance` method.

```py
class HikersInstance(InstanceModel):
"""The Hikers instance class."""

hikers: list[tuple[u64, u64]]

@property
def size(self) -> int:
"""The instance size is the number of hikers."""
return len(self.hikers)

def validate_instance(self) -> None:
super().validate_instance()
if any(min_size > max_size for min_size, max_size in self.hikers):
raise ValidationError("One hiker's minimum group size is larger than their maximum group size.")
```

This method contains further code that validates which inputs are allowable and which aren't. If you generate an
instance that causes this method to raise an error, your instance will be considered invalid, and you will lose the
fight.

## The Solution Class

This class is very similar to the instance class, except it specifies what solutions look like. In our case we again
have a single attribute and thus the solutions contain only a single key.

```py hl_lines="2 8"
{!> problem/solution.py !}
```

This time we not only use an alias to specify the allowable range of integer values, but also the `SizeLen` marker which
means that the number of `assignments` must be exactly the same as the instance's size.

### Solution Score

Most solutions also have a `score` method. This tells Algobattle what the goal of this problem is and how to weigh
different solutions.

```py hl_lines="10-15"
{!> problem/solution.py !}
```

The decorator at the top can either be `maximize` or `minimize` and tells us if bigger or smaller score values are
considered to be better. The function then computes some non-negative real number based on the instance and solution,
this will be this solutions' score. Each fight in a battle will receive a single score, that will be calculated by
comparing the solution score of the generator's and solver's solutions.

In our example the score just is the longest time a machine takes to complete all jobs. If in the generator's solution
all machines complete their jobs in 10 units, but the solver's solution takes 12, the fight's score will be
approximately 0.83.

### Additional Validation

Just like instances can undergo extra validation, so can solutions. They use the `validate_solution` method for this.

```py hl_lines="6-13"
class Solution(SolutionModel[HikersInstance]):
"""A solution to a Hikers problem."""

assignments: dict[Hiker, u64]

def validate_solution(self, instance: HikersInstance, role: Role) -> None:
super().validate_solution(instance, role)
group_sizes = Counter(self.assignments.values())

for hiker, group in self.assignments.items():
min_size, max_size = instance.hikers[hiker]
if not (min_size <= group_sizes[group] <= max_size):
raise ValidationError("A Hiker is not happy with their assignment!")

@maximize
def score(self, instance: HikersInstance, role: Role) -> float:
return len(self.assignments)
```

## The Problem Constructor

The last part of the problem file actually creates the problem.

```py hl_lines="36-41"
{!> problem/problem.py !}
```

It contains the name of the problem and references to the two classes we discussed. It also specifies what the smallest
reasonable size of this problem is. In our case an instance should contain at least one job for each machine, so the
minimum size of this problem is 5.
18 changes: 16 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,24 @@ The teams then battle against each other, generating instances for other teams,
generated for them. Each team then is evaluated on its performance and is awarded points.


## Usage
## Where to start reading

The best place to start learning more about Algobattle is by reading through [the tutorial](tutorial/index.md).
The Algobattle documentation is aimed at two different groups of people: students participating in lab courses, and
instructors running them. In order to keep everything short and sweet we've structured our documentation so that
everyone can easily focus just on what they need to learn about.

For everyone, the best place to start learning more about Algobattle is by reading through
[the tutorial](tutorial/index.md). It contains everything you need to know to use the framework and start working with
it. Students won't necessarily need anything further to participate in the course, but may later run into things they
can best look up in the [advanced section](advanced/index.md).

After finishing the tutorial we then recommend instructors to go through the topics in the
[instructor's corner](instructor/index.md). This will get you up to speed to run an Algobattle lab course on your own.

!!! tip "Just want a broad overview?"
If you're not yet interested in reading all the nitty-gritty and just want a basic idea of how such a Lab course
works to decide if you want to run one yourself, the [teaching concept](instructor/teaching_english.md) is ideal
for you!

## Requirements

Expand Down
18 changes: 18 additions & 0 deletions docs/instructor/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Instructor's Corner

This section is all about the stuff behind the scenes. It covers how you can structure the course and detailed info on
how to interact with the framework. Individual pages are largely independent of each other and can be read in sequence
or used as a reference as needed.

## Overview

- The [teaching concept](teaching_english.md) provides a high level overview of the project, what a full course looks
like, and what our goals are.

- The problem pages discuss how to create your own problems for students to solve. The [intro](problem/intro.md) and
[basic section](problem/problem_file.md) cover everything you need to know to get started and work with most
types of problems. However, the framework is incredibly versatile and lets you create much more complex and out of
the box problems than you might initially think. The following pages dive into more detail on everything else.

- [Battle types](battles.md) discusses how you can customize the Algobattle match process itself by writing your own
battle types.
Loading

0 comments on commit 42d2160

Please sign in to comment.