我正在做一个模拟退火算法来优化给定的学生和项目分配。在
这是来自维基百科的语言无关的伪代码:
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
allocated
参数现在是False
)和讲师(如果他们的一个或多个项目不再分配,则释放插槽)aNew
,如果权重wNew
小于我在开始时选择的分配权重wOld
,那么这就是best_node
(由上面的Simulated Annealing
算法定义)。将算法应用于aNew
,然后继续。在wOld < wNew
,则将该算法再次应用于aOld
,然后继续。在分配/数据点表示为“节点”,这样node = (weight, allocation_dict, projects_dict, lecturers_dict)
现在,我只能执行这个算法一次,但是我需要尝试一个数字N(在Wikipedia代码片段中用kmax
表示),并确保我总是随身携带上一个node
和{
为了不修改我原来的字典(我可能想重新设置),我对字典做了一个浅拷贝。从我在文档中读到的内容来看,它似乎只复制了引用,而且由于我的词典包含对象,所以无论如何,更改复制的词典最终都会更改对象。所以我尝试使用copy.deepcopy()
,这些字典引用的是用SQLA映射的对象。在
Questions:
我已经得到了一些解决所面临的问题的方法,但由于我对Python的无知,它们对我来说听起来都相当神秘。在
Deepcopy不能很好地使用SQLA。有人告诉我,ORM对象上的deepcopy可能存在一些问题,使它无法像您预期的那样工作。显然,我最好是“构建复制构造函数,即defcopy(self):returnfoobar(…..)”有人能解释一下这是什么意思吗?
我检查后发现deepcopy
有问题,因为SQLAlchemy在您的对象上放置了额外的信息,即_sa_instance_state
属性,我不想在副本中出现,但对于对象来说是必需的。有人告诉我:“有很多方法可以手动删除旧的_sa_instance_state
并在对象上放置一个新的,但最简单的方法是用__init__()
创建一个新的对象,并设置重要的属性,而不是进行完全的深度复制。”这到底意味着什么?我是否要创建一个新的、未映射的类类似于旧的已映射类?
另一种解决方案是,我必须在您的对象上“实现__deepcopy__()
”,并确保设置了一个新的实例状态,其中包含sqlalchemy.orm.attributes这对我来说很有帮助。“这又一次超出了我的能力,所以有人能解释一下这意味着什么吗?
一个更一般的问题:对于上面的信息,有没有关于如何维护best_node
(必须始终在while循环中保持)和previous_node
(如果我的实际对象是被字典引用,因此节点)因释放/重新分配而发生变化?也就是说,不用拷贝?
你不想像那样复制sqlalchemy对象。您可以实现自己的方法,这些方法可以很容易地生成副本,但这可能不是您想要的。你不想在你的数据库里有学生和项目的副本吗?所以不要复制这些数据。在
所以你有一个字典来保存你的分配。在此过程中,不应修改SQLAlchemy对象。所有可以修改的信息都应该存储在这些字典中。如果需要修改对象以将其考虑在内,请在末尾将数据复制回。在
我有另一个可能的解决方案:使用事务。这可能仍然不是最好的解决方案,但实现它应该更快。在
首先创建这样的会话:
那样的话,它将是事务性的。事务的工作方式是}将还原这些更改。在
sess.commit()
将使您的更改永久化,而{在模拟退火的情况下,您希望在找到新的最佳解决方案时提交。以后,您可以调用rollback()将状态恢复到该位置。在
相关问题 更多 >
编程相关推荐