import random
Tutorial V.II - Recap with Randomness
Programming: Everyday Decision-Making Algorithms
Introduction
From now on, it is rather difficult to give you tasks that you cannot solve within minutes by yourself with the help of AI. Therefore, today’s tutorial will be more open-ended than usual. All tasks are designed to be solved together with AI, but you are nonetheless the human in the loop. Thus, your responsiblities are to control the AI and to learn how to use it by doing. Instructions and explanations will only be given sparsely, as you are encouraged to use AI to ask for help and explanations to explore the tasks on your own.
Let’s explore how randomness affects our daily decision-making. As always, we will use Python and simulate various scenarios where randomness plays a crucial role.
Section 1 - Optimal Stopping with Random Candidates
Optimal stopping is a classic problem in decision theory where you want to select the best candidate from a list of candidates. As seen in the lecture, the 37% rule is a simple strategy that can be used to solve this problem.
Exercise 1.1 - The 37% Rule
Let’s implement the 37% rule from Optimal Stopping by using random candidates. Your task is to simulate the process of selecting the best candidate out of a list of random candidates. Remember, the 37% rule says that you should reject the first 37% of candidates and then select the next candidate who is better than all previous candidates.
First, let’s import the necessary library:
In total, you have 32 candidates. Screen the candidates one by one and compute the best_candidate_index
to find the best candidate.
- In Cursor, you can select the code or text you want to work with and then press
Ctrl+L
to open the chat. - In the chat, you can ask the AI to help you complete the task or ask it to explain the code, the task, or related concepts
- While writing code, you can press
Ctrl+K
to let the AI help you write the code directly in the editor. - Furthermore, the AI will try to understand your code and might make suggestions on how to improve it or on how to continue. Just press
TAB
to accept a suggestion.
42) # Sets the random seed for reproducibility
random.seed(= [random.random() for _ in range(32)]
candidates
# YOUR CODE BELOW
Code
# Test your solution with the following code
assert best_candidate_index == 24, "The selected candidate is not the best one"
print(r"All tests passed, you have successfully implemented the 37% rule!")
Section 2 - Explore vs Exploit
Remember the explore vs. exploit dilemma? Should you try a new restaurant (explore) or return to your favorite (exploit)? Let’s simulate this decision-making process!
Exercise 2.1 - Visiting Restaurants
Imagine you’re new to a city with 10 restaurants. Each restaurant has a “true” quality rating (unknown to you) between 0 and 5 stars. Each time you visit a restaurant, you get to experience its rating. In total, you will visit restaurants 15 times.
Your goal is to create a simulation that computes the average satisfaction over 15 days based on an explore vs. exploit strategy. First, you should try each restaurant once (pure exploration). Then, you should just exploit your favorite restaurant for the remaining visits. Save the average satisfaction in average_satisfaction
and the index of the best restaurant in best_restaurant_index
.
import random
# Set up the restaurants (true qualities are unknown to the visitor!)
59)
random.seed(= [random.uniform(1, 5) for _ in range(10)]
qualities
# YOUR CODE BELOW
Code
# Test your solution with the following code
assert average_satisfaction > 3.7, "The average satisfaction should be greater than 3.7"
assert best_restaurant_index == 2, "The best restaurant should be number 3"
print(r"All tests passed, you have successfully implemented the explore vs. exploit strategy!")
Section 3 - Caching
Caching is a technique that can be used to speed up computations by storing the results of expensive computations and reusing them when the same inputs occur again. Let’s implement a simple caching mechanism in Python.
Section 4 - Scheduling
Scheduling is a classic problem in operations research and in daily life. Let’s implement a simple scheduling algorithm that tries to find the optimal schedule for a given set of tasks with the earliest due date strategy.
Exercise 4.1 - Scheduling Tasks
Let’s create a task scheduler that handles tasks with different due dates. The scheduler should sort tasks by their due date (Earliest Due Date First - EDD strategy) to minimize potential delays.
Your task is to create a function schedule_tasks(tasks)
that:
- Sorts tasks by due date
- Creates a schedule with start and end times for each task
- Returns the complete schedule as an pandas DataFrame
- Keep the same column names as in the dictionary
# Pre-generated tasks (don't modify this!)
# Times are represented in hours from start (hour 0)
# For example, due_time: 24 means it's due 24 hours from start
import pandas as pd
= [
tasks
{"name": "Project Review",
"duration": 2, # hours
"due_time": 12 # due in 12 hours
},
{"name": "Team Meeting",
"duration": 4,
"due_time": 6
},
{"name": "Client Presentation",
"duration": 3,
"due_time": 7
},
{"name": "Email Updates",
"duration": 4,
"due_time": 11
},
{"name": "Planning Session",
"duration": 2,
"due_time": 9
}
]
# YOUR CODE HERE
Code
# Test your solution with the following code
= schedule_tasks(tasks)
schedule_df assert schedule_df.shape == (5, 4), "The schedule should have 5 rows and 4 columns"
assert schedule_df.iloc[0]['name'] == "Team Meeting", "First task should be 'Team Meeting'"
assert schedule_df.iloc[4]['name'] == "Project Review", "Fifth task should be 'Project Review'"
print(r"All tests passed, you have successfully implemented the task scheduler!")
Section 5 - Randomness
In our daily lives, we often encounter situations where randomness plays a crucial role in decision-making. From choosing a restaurant for dinner to selecting which tasks to tackle first, incorporating some randomness can actually lead to better outcomes than strictly deterministic approaches.
Solving your travel problem by brute force
Imagine you want to travel during the semester break and you want to visit 6 cities and then return to Hamburg. Your aim is to find the route that is the cheapest to travel. Implement a heuristic that randomly tries 10 different routes and picks the cheapest one. Save the costs in min_cost
.
# City names and cost matrix
import pandas as pd
import random
= ["New York", "London", "Tokyo", "Sydney", "Barcelona", "Hamburg"]
cities
= [
cost_matrix 0, 700, 1500, 2000, 800, 900], # New York
[700, 0, 1200, 1800, 300, 700], # London
[1500, 1200, 0, 1000, 1100, 1400], # Tokyo
[2000, 1800, 1000, 0, 1700, 1500], # Sydney
[800, 300, 1100, 1700, 0, 600], # Barcelona
[900, 700, 1400, 1500, 600, 0] # Hamburg
[
]
# Create a DataFrame
= pd.DataFrame(cost_matrix, index=cities, columns=cities)
cost_df
# Display the DataFrame
print(cost_df)
# YOUR CODE HERE
New York London Tokyo Sydney Barcelona Hamburg
New York 0 700 1500 2000 800 900
London 700 0 1200 1800 300 700
Tokyo 1500 1200 0 1000 1100 1400
Sydney 2000 1800 1000 0 1700 1500
Barcelona 800 300 1100 1700 0 600
Hamburg 900 700 1400 1500 600 0
Code
# Test your solution with the following code
assert min_cost < 6000, "The cheapest route should be cheaper than 6000. Try again, if you think your algorithm works correctly."
print(r"All tests passed, you have successfully implemented the route planner!")
Conclusion
We’ve explored how randomness affects decision-making through:
- Explore vs. Exploit trade-offs
- Optimal stopping with random elements
- Caching a random subset of data
- Scheduling tasks with due dates
- Finding the cheapest route for a travel problem
Remember that randomness isn’t always bad - sometimes it’s the best strategy we have!
In the next tutorial, we’ll dive deeper into some free-form tasks!