Files
fzu-product/4.人工智能/4.3.4.1程序示例.md
FallenYing 99f997e803 chore: add 4.3.4 文本优化 (#120)
* chore: add 4.3.4 文本优化

* Update 7.1.1.1基础部分.md

chore: 文本优化 更换已失效网址
2023-09-17 13:53:05 +08:00

342 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 程序示例
::: 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\}