This commit is contained in:
2024-08-10 19:46:55 +08:00
commit 2233526534
798 changed files with 35282 additions and 0 deletions

View File

@@ -0,0 +1,341 @@
# 程序示例
::: tip
阅读程序并运行
完成习题
:::
::: tip 📥
本节附件下载 <Download url="https://cdn.xyxsw.site/code/4-Lecture.zip"/>
:::
## Hospital(局部搜索)
```python
import random
class Space():
def __init__(self, height, width, num_hospitals):
"""创建一个具有给定维度的新状态空间"""
self.height = height # 高度
self.width = width # 宽度
self.num_hospitals = num_hospitals # 医院数量
self.houses = set() # 住房位置集合
self.hospitals = set() # 医院位置集合
def add_house(self, row, col):
"""在状态空间中的特定位置添加住房"""
self.houses.add((row, col))
def available_spaces(self):
"""返回住房或医院当前未使用的所有单元格"""
# 考虑所有可能的单元格
candidates = set(
(row, col)
for row in range(self.height)
for col in range(self.width)
)
# 排除所有住房和医院
for house in self.houses:
candidates.remove(house)
for hospital in self.hospitals:
candidates.remove(hospital)
return candidates
def hill_climb(self, maximum=None, image_prefix=None, log=False):
"""执行爬山算法找到解决方案"""
count = 0
# 从随机初始化的医院位置开始
self.hospitals = set()
for i in range(self.num_hospitals):
self.hospitals.add(random.choice(list(self.available_spaces())))
...
# 执行算法,直到达到最大迭代次数
while maximum is None or count < maximum:
count += 1
best_neighbors = []
best_neighbor_cost = None
# 考虑所有医院移动
for hospital in self.hospitals:
# 考虑一下那家医院的所有邻居
for replacement in self.get_neighbors(*hospital):
# 生成一组相邻的医院
neighbor = self.hospitals.copy()
neighbor.remove(hospital)
neighbor.add(replacement)
# 检查邻居是否是迄今为止最好的
cost = self.get_cost(neighbor)
if best_neighbor_cost is None or cost < best_neighbor_cost:
best_neighbor_cost = cost
best_neighbors = [neighbor]
elif best_neighbor_cost == cost:
best_neighbors.append(neighbor)
# 没有一个邻居比目前的状态更好
if best_neighbor_cost >= self.get_cost(self.hospitals):
return self.hospitals
# 移动到价值最高的邻居
else:
...
self.hospitals = random.choice(best_neighbors)
...
def random_restart(self, maximum, image_prefix=None, log=False):
"""多次重复爬山算法"""
best_hospitals = None
best_cost = None
# 重复爬山算法的固定次数
for i in range(maximum):
hospitals = self.hill_climb()
cost = self.get_cost(hospitals)
if best_cost is None or cost < best_cost:
best_cost = cost
best_hospitals = hospitals
...
else:
...
...
return best_hospitals
def get_cost(self, hospitals):
"""计算从住房到最近医院的距离总和"""
cost = 0
for house in self.houses:
cost += min(
abs(house[0] - hospital[0]) + abs(house[1] - hospital[1])
for hospital in hospitals
)
return cost
def get_neighbors(self, row, col):
"""返回尚未包含住房或医院的邻居"""
candidates = [
(row - 1, col),
(row + 1, col),
(row, col - 1),
(row, col + 1)
]
neighbors = []
for r, c in candidates:
if (r, c) in self.houses or (r, c) in self.hospitals:
continue
if 0 <= r < self.height and 0 <= c < self.width:
neighbors.append((r, c))
return neighbors
def output_image(self, filename):
"""生成所有房屋和医院的图像(不作要求)"""
from PIL import Image, ImageDraw, ImageFont
cell_size = 100
cell_border = 2
cost_size = 40
padding = 10
# Create a blank canvas
img = Image.new(
"RGBA",
(self.width * cell_size,
self.height * cell_size + cost_size + padding * 2),
"white"
)
house = Image.open("assets/images/House.png").resize(
(cell_size, cell_size)
)
hospital = Image.open("assets/images/Hospital.png").resize(
(cell_size, cell_size)
)
font = ImageFont.truetype("assets/fonts/OpenSans-Regular.ttf", 30)
draw = ImageDraw.Draw(img)
for i in range(self.height):
for j in range(self.width):
# Draw cell
rect = [
(j * cell_size + cell_border,
i * cell_size + cell_border),
((j + 1) * cell_size - cell_border,
(i + 1) * cell_size - cell_border)
]
draw.rectangle(rect, fill="black")
if (i, j) in self.houses:
img.paste(house, rect[0], house)
if (i, j) in self.hospitals:
img.paste(hospital, rect[0], hospital)
# Add cost
draw.rectangle(
(0, self.height * cell_size, self.width * cell_size,
self.height * cell_size + cost_size + padding * 2),
"black"
)
draw.text(
(padding, self.height * cell_size + padding),
f"Cost: {self.get_cost(self.hospitals)}",
fill="white",
font=font
)
img.save(filename)
# 创建一个状态空间并随机添加住房
s = Space(height=10, width=20, num_hospitals=3)
for i in range(15):
s.add_house(random.randrange(s.height), random.randrange(s.width))
# 使用局部搜索来确定医院位置
hospitals = s.random_restart(maximum=100, image_prefix="hospitals", log=True)
```
## Production(线性规划)
```python
import scipy.optimize
# Objective Function: 50x_1 + 80x_2
# Constraint 1: 5x_1 + 2x_2 <= 20
# Constraint 2: -10x_1 + -12x_2 <= -90
result = scipy.optimize.linprog(
[50, 80], # Cost function: 50x_1 + 80x_2
A_ub=[[5, 2], [-10, -12]], # Coefficients for inequalities
b_ub=[20, -90], # Constraints for inequalities: 20 and -90
)
if result.success:
print(f"X1: {round(result.x[0], 2)} hours")
print(f"X2: {round(result.x[1], 2)} hours")
else:
print("No solution")
```
## Schedule(约束满足)
```python
"""没有任何启发式或推理的自然回溯搜索"""
VARIABLES = ["A", "B", "C", "D", "E", "F", "G"]
CONSTRAINTS = [
("A", "B"),
("A", "C"),
("B", "C"),
("B", "D"),
("B", "E"),
("C", "E"),
("C", "F"),
("D", "E"),
("E", "F"),
("E", "G"),
("F", "G")
]
def backtrack(assignment):
"""运行回溯搜索以查找赋值"""
# 检查赋值是否完成
if len(assignment) == len(VARIABLES):
return assignment
# 尝试一个新变量
var = select_unassigned_variable(assignment)
for value in ["Monday", "Tuesday", "Wednesday"]:
new_assignment = assignment.copy()
new_assignment[var] = value
if consistent(new_assignment):
result = backtrack(new_assignment)
if result is not None:
return result
return None
def select_unassigned_variable(assignment):
"""按顺序选择尚未赋值的变量"""
for variable in VARIABLES:
if variable not in assignment:
return variable
return None
def consistent(assignment):
"""检查分配是否一致"""
for (x, y) in CONSTRAINTS:
# 仅考虑变量赋值都已指定的弧
if x not in assignment or y not in assignment:
continue
# 如果两者的值相同,则不一致
if assignment[x] == assignment[y]:
return False
# 如果没有不一致的地方,那么赋值是一致的
return True
solution = backtrack(dict())
print(solution)
```
使用命令`pip install python-constraint`安装 constraint 库
```python
from constraint import *
problem = Problem()
# 添加变量
problem.addVariables(
["A", "B", "C", "D", "E", "F", "G"],
["Monday", "Tuesday", "Wednesday"]
)
# 添加约束
CONSTRAINTS = [
("A", "B"),
("A", "C"),
("B", "C"),
("B", "D"),
("B", "E"),
("C", "E"),
("C", "F"),
("D", "E"),
("E", "F"),
("E", "G"),
("F", "G")
]
for x, y in CONSTRAINTS:
problem.addConstraint(lambda x, y: x != y, (x, y))
# Solve problem
for solution in problem.getSolutions():
print(solution)
```
## Quiz
1. 对于以下哪一项,即使多次重新运行算法,也会始终找到相同的解决方案?
假设一个问题的目标是最小化成本函数,并且状态空间中的每个状态都有不同的成本。
1. Steepest-ascent hill-climbing每次从不同的初始状态开始
2. Steepest-ascent hill-climbing每次都从相同的初始状态开始
3. Stochastic hill-climbing每次从不同的初始状态开始
4. Stochastic hill-climbing每次都从相同的初始状态开始
5. 无论是 steepest-ascent 还是 stochastic hill climbing只要你总是从同一个初始状态开始
6. 无论是 steepest-ascent 还是 stochastic hill climbing只要每次都从不同的初始状态开始
7. 没有任何版本的爬山算法能保证每次都能得到相同的解决方案
2. 下面两个问题都会问你关于下面描述的优化问题。
一位农民正在尝试种植两种作物,`作物 1``作物 2`,并希望实现利润最大化。农民将从种植的每英亩`作物 1` 中获得 500 美元的利润,从种植的每英亩`作物 2` 中获得 400 美元的利润。然而,农民今天需要在早上 7 点到晚上 7 点之间的 12 个小时内完成所有的种植。种植一英亩的`作物 1` 需要 3 个小时,种植一英亩`作物 2` 需要 2 个小时。农民在供应方面也很有限:他有足够的供应种植 10 英亩的`作物 1`,有足够的资源种植 4 英亩的`作物 2`。假设变量 C1 表示要种植的`作物 1` 的英亩数,变量 C2 表示要种植`作物 2` 的英亩数。
对于这个问题,什么是有效的目标函数?
1. 10 \* C1 + 4 \* C2
2. -3 \* C1 - 2 \* C2
3. 500 \* 10 \* C1 + 400 \* 4 \* C2
4. 500 \* C1 + 400 \* C2
5. C1 + C2
3. 这个问题的制约因素是什么?
1. 3 \* C1 + 2 \* C2 <= 12, C1 <= 10, C2 <= 4
2. 3 \* C1 + 2 \* C2 <= 12, C1 + C2 <= 14
3. 3 \* C1 <= 10, 2 \* C2 <= 4
4. C1 + C2 <= 12, C1 + C2 <= 14
4. 下面的问题将问你以下考试安排约束满足图,其中每个节点代表一个课程。每门课程都与可能的考试日的初始域相关联(大多数课程可能在周一、周二或周三;少数课程已经被限制在一天内)。两个节点之间的边意味着这两个课程必须在不同的日子进行考试。
在对整个问题满足弧一致性之后,变量 C、D 和 E 的结果域是什么?
1. C 的域是\{MonTue\}D 的域是\{Wed\}E 的域是\{Mon\}
2. C 的域是\{Mon\}D 的域是\{Wed\}E 的域为\{Tue\}
3. C 的域是\{Mon\}D 的域是\{Tue\}E 的域为\{Wed\}
4. C 的域是\{Mon\}D 的域是\{MonWed\}E 的域是\{TueWed\}
5. C 的域是\{MonTueWed\}D 的域是\{MonWed\}E 的域是\{MonTueWed\}
6. C 的域是\{Mon\}D 的域是\{MonWed\}E 的域是\{MonTueWed\}