Проблема с копированием словарей и использованием глубокой копии на объекте ORM SQLAlchemy - PullRequest
0 голосов
/ 04 июня 2010

Я делаю алгоритм имитации отжига для оптимизации заданного распределения студентов и проектов.

Это не зависящий от языка псевдокод из Википедии:

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 в фрагменте Википедии) и убедиться, что у меня всегда есть предыдущий node и best_node.

Чтобы я не изменял свои исходные словари (которые я мог бы сбросить), я сделал мелкую копию словарей. Из того, что я прочитал в документации, кажется, что он только копирует ссылки, и, поскольку мои словари содержат объекты, изменение скопированного словаря в конечном итоге приводит к изменению объектов в любом случае. Поэтому я попытался использовать copy.deepcopy(). Эти словари ссылаются на объекты, которые были сопоставлены с SQLA.


Questions:

Мне были даны некоторые решения для проблем, с которыми я столкнулся, но из-за моей исключительной зелёности при использовании Python все они звучат довольно загадочно для меня.

  1. Deepcopy не очень хорошо работает с SQLA. Мне сказали, что у глубокой копии на объектах ORM, вероятно, есть проблемы, которые мешают ей работать так, как вы ожидаете. По-видимому, лучше было бы «создавать конструкторы копий, то есть def copy (self): return FooBar (....)». Может кто-нибудь объяснить, что это значит?

  2. Я проверил и обнаружил, что deepcopy имеет проблемы, потому что SQLAlchemy помещает дополнительную информацию в ваши объекты, то есть атрибут _sa_instance_state, который я не хотел бы видеть в копии, но необходим для того, чтобы объект имел , Мне сказали: «Есть способы вручную сдуть старый _sa_instance_state и наложить новый на объект, но самым простым является создание нового объекта с __init__() и настройка значимых атрибутов. вместо того, чтобы делать полную глубокую копию. " Что именно это значит? Создать новый не сопоставленный класс, похожий на старый, сопоставленный класс?

  3. Альтернативное решение состоит в том, что мне придется «реализовать __deepcopy__() на ваших объектах и ​​убедиться, что настроено новое _sa_instance_state, в sqlalchemy.orm.attributes есть функции, которые могут помочь с этим». Еще раз, это за мной, поэтому кто-то может объяснить, что это значит?

  4. Более общий вопрос: учитывая приведенную выше информацию, есть ли какие-либо предложения о том, как я могу поддерживать информацию / состояние для best_node (который всегда должен сохраняться в моем цикле while) и previous_node, если мой фактические объекты (на которые ссылаются словари, следовательно, узлы) изменяются из-за того, что происходит освобождение / перераспределение? То есть без использования копии?

Ответы [ 2 ]

2 голосов
/ 07 июня 2010

У меня есть другое возможное решение: использовать транзакции. Возможно, это еще не лучшее решение, но его реализация должна быть быстрее.

Сначала создайте свою сессию так:

# transactional session
Session = sessionmaker(transactional=True)
sess = Session()

Таким образом, это будет транзакция. Работа транзакций заключается в том, что sess.commit() сделает ваши изменения постоянными, а sess.rollback() вернет их.

В случае имитации отжига вы хотите зафиксировать, когда вы найдете новое лучшее решение. В любой последующий момент вы можете вызвать rollback (), чтобы вернуть статус обратно в эту позицию.

0 голосов
/ 06 июня 2010

Вы не хотите копировать объекты sqlalchemy. Вы можете реализовать свои собственные методы, которые делают копии достаточно легко, но, вероятно, вы этого не хотите. Вам не нужны копии студентов и проектов в вашей базе данных? Так что не копируйте эти данные.

Итак, у вас есть словарь, в котором хранятся ваши ассигнования. Во время этого процесса вы никогда не должны изменять объекты SQLAlchemy. Вся информация, которую можно изменить, должна храниться в этих словарях. Если вам нужно изменить объекты, чтобы учесть это, скопируйте данные обратно в конец.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...