我正在做一个模拟退火算法来优化给定的学生和项目分配。
这是来自 Wikipedia 的与语言无关的伪代码:
s ← s0; e ← E(s) // Initial state, energy.
sbest ← s; ebest ← e // Initial "best" solution
k ← 0 // Energy evaluation count.
while k < kmax and e > emax // While time left & not good enough:
snew ← neighbour(s) // Pick some neighbour.
enew ← E(snew) // Compute its energy.
if enew < ebest then // Is this a new best?
sbest ← snew; ebest ← enew // Save 'new neighbour' to 'best found'.
if P(e, enew, temp(k/kmax)) > random() then // Should we move to it?
s ← snew; e ← enew // Yes, change state.
k ← k + 1 // One more evaluation done
return sbest // Return the best solution found.
以下是该技术的改编。我的主管说这个想法在理论上是好的。
首先,我从整组随机分配中提取一些分配(即整个学生词典及其分配的项目,包括项目的排名),将其复制并传递给我的函数。我们称之为分配aOld
(它是一个字典)。aOld
有一个与之相关的权重,称为wOld
。权重如下所述。
该函数执行以下操作:
- 让这个分配,
aOld
成为best_node
- 从所有学生中,选择随机数量的学生并粘贴在列表中
- 剥离(DEALLOCATE)他们的项目++反映项目的变化(
allocated
参数现在False
)和讲师(如果他们的一个或多个项目不再分配,则释放空位) - 随机化该列表
- 再次尝试分配(REALLOCATE)该列表项目中的每个人
- 计算权重(将排名相加,排名 1 = 1,排名 2 = 2...并且没有项目排名 = 101)
- 对于这个新的分配
aNew
,如果权重wNew
小于wOld
我一开始选择的分配权重,那么这就是best_node
(由上面的Simulated Annealing
算法定义)。将算法应用于aNew
并继续。 - 如果
wOld < wNew
,则再次应用该算法aOld
并继续。
分配/数据点表示为“节点”,使得node = (weight, allocation_dict, projects_dict, lecturers_dict)
现在,我只能执行这个算法一次,但我需要尝试一个数字 N(kmax
在 Wikipedia 片段中表示)并确保我总是随身携带,previousnode
和best_node
.
为了不修改我原来的字典(我可能想重置),我做了字典的浅拷贝。从我在文档中阅读的内容来看,它似乎只复制引用,并且由于我的字典包含对象,因此更改复制的字典最终会更改对象。所以我尝试使用copy.deepcopy()
。这些字典引用了已经用 SQLA 映射的对象。
Questions:
我已经为所面临的问题提供了一些解决方案,但由于我使用 Python 的超绿色能力,它们对我来说听起来都相当神秘。
Deepcopy 不能很好地与 SQLA 配合使用。有人告诉我,ORM 对象上的深拷贝可能存在阻止它按预期工作的问题。显然,我最好“构建复制构造函数,即 def copy(self): return FooBar(....)”。有人可以解释一下这是什么意思吗?
我检查并发现
deepcopy
存在问题,因为 SQLAlchemy 在您的对象上放置了额外的信息,即_sa_instance_state
属性,我不希望在副本中但对于对象来说是必需的。有人告诉我:“有一些方法可以手动清除旧的_sa_instance_state
并在对象上放置一个新的,但最直接的方法是创建一个新对象__init__()
并设置重要的属性,而不是做一个完整的深拷贝。” 这到底是什么意思呢?我是否创建了一个新的、未映射的类,类似于旧的映射类?另一种解决方案是我必须“
__deepcopy__()
在您的对象上实现并确保设置了新的 _sa_instance_state,sqlalchemy.orm.attributes 中有一些函数可以帮助解决这个问题。” 再一次,这超出了我的范围,所以有人可以解释一下这是什么意思吗?一个更普遍的问题:鉴于上述信息,是否有任何关于如何维护信息/状态的建议
best_node
(必须始终通过我的 while 循环持续存在)和previous_node
,如果我的实际对象(由字典引用,因此节点) 是否由于发生解除分配/重新分配而发生变化?也就是说,不使用副本?