Все мы знаем, насколько впечатляюще развились большие языковые модели за последние годы, но трудно оценить точный уровень их совершенства в цифрах.
Это заставило меня вспомнить геометрическую задачу, которую я увидел на одном из YouTube-каналов год назад. В июне 2024 года я попытался заставить ведущую на тот момент большую языковую модель (GPT-4o) решить эту загадку. Результат получился не слишком удачным, потребовалось много усилий, чтобы добиться решения, и я задался вопросом, как с той же задачей справятся самые свежие модели.
Задача
Вот краткое напоминание о том, что я просил модель решить в прошлом. Представьте сетку из точек/узлов. В координатной плоскости x и y каждая точка расположена ровно на единицу от соседней. Она выглядит следующим образом,

Теперь вопрос, на который я хотел получить ответ,
Сколько различных квадратов можно нарисовать на этой диаграмме?Стало быстро ясно, что GPT-4o не знает ответа, поэтому я немного изменил подход и вместо этого попросил следующее.
Мне нужна программа на Python, которая отобразит все квадраты, которые можно нарисовать на прикрепленной диаграмме, предполагая, что углы любого квадрата должны лежать на одной из точек диаграммы. Предполагайте, что каждые соседние точки расположены на 1 единицу друг от друга как по оси x, так и по оси y. Также выведите сводку о количестве квадратов одного размера и их длинах сторон.В итоге, я в конце концов добился от GPT-4o правильного решения на базе Python. Тем не менее, на это ушло около двух часов и более 40 итераций обмена сообщениями с моделью, чтобы уточнить ее ответ, пока она не выдала рабочий вариант.
Кстати, вы уже разобрались с ответом? Даже сейчас я с трудом верю, что на этой схеме можно нарисовать 21 квадрат.
Взаимодействие с Sonnet 4.5
Это возвращает нас к сегодняшнему дню и недавнему релизу от Anthropic, который считается лучшей моделью для программирования на данный момент, а именно Claude Sonnet 4.5. Прошло около 16 месяцев с тех пор, как я в последний раз проверял это, так насколько же большие языковые модели улучшились за это время? Давайте посмотрим, как Sonnet 4.5 справляется с задачей.
Чтобы использовать Sonnet 4.5, я зашел на главную страницу Anthropic.
Там должна открыться страница вроде этой.

Нажмите на большую черную кнопку «Try Claude», расположенную в верхнем правом углу экрана. В этот момент вас попросят войти в систему. Если у вас еще нет аккаунта в Anthropic, создайте его прямо сейчас. Это совершенно бесплатно.
После входа вас перенаправит на экран с привычным чат-окном, где можно взаимодействовать с Sonnet 4.5 и задавать вопросы.
Прежде чем просить модель предоставить программу на Python для решения задачи, я задал прямой вопрос, чтобы проверить, знает ли она ответ заранее.

Она ответила следующим,
Глядя на эту сетку, мне нужно подсчитать все возможные квадраты разных размеров, которые можно образовать, соединяя точки. Сначала определим структуру сетки. Точки образуют: 2 точки в верхнем ряду 2 точки во втором ряду 6 точек в третьем ряду 6 точек в четвертом ряду 2 точки в пятом ряду 2 точки в шестом ряду Это похоже на крестообразную или плюс-образную сетку. Теперь посчитаем квадраты по размерам: Квадраты 1×1: Они образуются любыми 4 точками, формирующими единичный квадрат. В горизонтальной средней секции (ряды 3-4): 5 квадратов на ряд × 1 = 5 квадратов В вертикальной средней секции (столбцы, где крест пересекается): подсчет вертикальных сегментов дает еще 5 квадратов Итого: 10 маленьких квадратов Квадраты 2×2: Для них нужны 4×4 расположения точек. В горизонтальной секции: 4 квадрата В вертикальной секции: 4 квадрата Пересечение в центре: -1 (посчитано дважды) Итого: 7 квадратов размером 2×2 Квадраты 3×3 и больше: Сетка максимум 6 точек в ширину, но форма креста ограничивает размещение больших квадратов. Проверяя геометрию: Один квадрат 3×3 может поместиться в центре, где ветви креста пересекаются Итого: 1 квадрат размером 3×3 Общий итог: 10 + 7 + 1 = 18 квадратовИтак, уверенно неверно. Заинтригованный упоминанием модели о квадрате 3×3 (который невозможен на этой сетке), я попросил показать этот квадрат на диаграмме. Она ответила так.
Глядя на сетку внимательнее, мне нужно пересмотреть, существует ли на самом деле квадрат 3×3. Для квадрата 3×3 требуется 4×4 расположение точек (поскольку квадрат 3×3 нуждается в 4 точках на каждой стороне). Проверим структуру сетки: Ряды 1-2: только по 2 точки каждая (по центру) Ряды 3-4: по 6 точек каждая (полная ширина) Ряды 5-6: только по 2 точки каждая (по центру) Для квадрата 3×3 нужны 4 последовательных ряда и 4 последовательных столбца с точками на пересечениях. Однако, учитывая крестообразный/плюс-образный узор: Верх только в 2 столбцах точек Середина в 6 столбцах точек Низ только в 2 столбцах точек Поскольку ряды 1-2 и 5-6 имеют только по 2 точки (не на полную ширину), на этой сетке нет блока 4×4 из точек. Я должен исправить свой ответ: Квадрата 3×3 на этой сетке быть не может. Общий итог: 10 (квадраты 1×1) + 7 (квадраты 2×2) = 17 квадратов Извините за ошибку в первоначальном подсчете. Крестообразный узор не позволяет формировать квадраты больше 2×2.Хорошо, модель частично исправилась с этим ответом, но в сущности она не указала правильно на 21 квадрат в общей сложности.
Финальный ответ
Чтобы сохранить справедливость в сравнении моделей за 16 месяцев, я задал Sonnet 4.5 точно тот же вопрос, что и GPT-4o, который, напомню, звучал так.
Мне нужна программа на Python, которая отобразит все квадраты, которые можно нарисовать на прикрепленной диаграмме, предполагая, что углы любого квадрата должны лежать на одной из точек диаграммы. Предполагайте, что каждые соседние точки расположены на 1 единицу друг от друга как по оси x, так и по оси y. Также выведите сводку о количестве квадратов одного размера и их длинах сторон.Sonnet 4.5 размышляла всего 5 секунд, прежде чем сгенерировать свой код на Python.
import matplotlib.pyplot as plt import numpy as np from itertools import combinations from collections import defaultdict # Define the grid points based on the image points = [ # Top two rows (2 dots each, centered) (3, 6), (4, 6), (3, 5), (4, 5), # Middle two rows (6 dots each, full width) (1, 4), (2, 4), (3, 4), (4, 4), (5, 4), (6, 4), (1, 3), (2, 3), (3, 3), (4, 3), (5, 3), (6, 3), # Bottom two rows (2 dots each, centered) (3, 2), (4, 2), (3, 1), (4, 1), ] def is_square(p1, p2, p3, p4): """Check if four points form a square and return side length if true.""" points = [p1, p2, p3, p4] # Calculate all pairwise distances distances = [] for i in range(len(points)): for j in range(i + 1, len(points)): dist = np.sqrt((points[i][0] - points[j][0])**2 + (points[i][1] - points[j][1])**2) distances.append(dist) distances.sort() # For a square: 4 equal sides and 2 equal diagonals # Diagonals should be sqrt(2) times the side length if len(distances) == 6: sides = distances[:4] diagonals = distances[4:] # Check if all sides are equal if np.allclose(sides, [sides[0]] * 4, atol=1e-6): # Check if diagonals are equal if np.allclose(diagonals, [diagonals[0]] * 2, atol=1e-6): # Check if diagonal = side * sqrt(2) if np.allclose(diagonals[0], sides[0] * np.sqrt(2), atol=1e-6): return True, sides[0] return False, 0 def order_square_points(p1, p2, p3, p4): """Order points of a square in counterclockwise order starting from bottom-left.""" points = [p1, p2, p3, p4] # Find centroid cx = sum(p[0] for p in points) / 4 cy = sum(p[1] for p in points) / 4 # Sort by angle from centroid def angle(p): return np.arctan2(p[1] - cy, p[0] - cx) points.sort(key=angle) return points # Find all squares squares = [] squares_by_size = defaultdict(list) for combo in combinations(points, 4): is_sq, side_length = is_square(*combo) if is_sq: ordered = order_square_points(*combo) squares.append(ordered) squares_by_size[round(side_length, 2)].append(ordered) # Print summary print("=" * 50) print("SUMMARY OF SQUARES FOUND") print("=" * 50) total_squares = 0 for side_length in sorted(squares_by_size.keys()): count = len(squares_by_size[side_length]) total_squares += count print(f"Side length {side_length}: {count} square(s)") print(f"
Total squares: {total_squares}") print("=" * 50) # Create visualization fig, axes = plt.subplots(2, 2, figsize=(14, 14)) axes = axes.flatten() # Plot 1: All dots ax = axes[0] x_coords = [p[0] for p in points] y_coords = [p[1] for p in points] ax.scatter(x_coords, y_coords, c='black', s=100, zorder=3) ax.set_xlim(0, 7) ax.set_ylim(0, 7) ax.set_aspect('equal') ax.grid(True, alpha=0.3) ax.set_title('Original Grid', fontsize=14, fontweight='bold') ax.set_xlabel('X') ax.set_ylabel('Y') # Plot 2: All squares overlaid ax = axes[1] ax.scatter(x_coords, y_coords, c='black', s=100, zorder=3) colors = plt.cm.rainbow(np.linspace(0, 1, len(squares))) for square, color in zip(squares, colors): square_closed = square + [square[0]] xs = [p[0] for p in square_closed] ys = [p[1] for p in square_closed] ax.plot(xs, ys, c=color, linewidth=2, alpha=0.6) ax.set_xlim(0, 7) ax.set_ylim(0, 7) ax.set_aspect('equal') ax.grid(True, alpha=0.3) ax.set_title(f'All {total_squares} Squares Overlaid', fontsize=14, fontweight='bold') ax.set_xlabel('X') ax.set_ylabel('Y') # Plot 3 & 4: Squares by size plot_idx = 2 for side_length in sorted(squares_by_size.keys()): if plot_idx >= len(axes): break ax = axes[plot_idx] ax.scatter(x_coords, y_coords, c='lightgray', s=100, zorder=2) squares_of_size = squares_by_size[side_length] colors = plt.cm.viridis(np.linspace(0, 1, len(squares_of_size))) for square, color in zip(squares_of_size, colors): square_closed = square + [square[0]] xs = [p[0] for p in square_closed] ys = [p[1] for p in square_closed] ax.plot(xs, ys, c=color, linewidth=2.5, marker='o', markersize=8) ax.set_xlim(0, 7) ax.set_ylim(0, 7) ax.set_aspect('equal') ax.grid(True, alpha=0.3) ax.set_title(f'Squares with side length {side_length} ({len(squares_of_size)} total)', fontsize=14, fontweight='bold') ax.set_xlabel('X') ax.set_ylabel('Y') plot_idx += 1 plt.tight_layout() plt.show()На первый взгляд я подумал, что Sonnet никак не мог так быстро придумать правильное решение. GPT-4o требовала часов. Однако я установил все необходимые библиотеки для кода и скопировал его в ячейку Jupyter Notebook, запустив и получив следующий вывод. Я опустил графики на данный момент, которые тоже были выведены.
================================================== SUMMARY OF SQUARES FOUND ================================================== Side length 1.0: 9 square(s) Side length 1.41: 4 square(s) Side length 2.24: 2 square(s) Side length 2.83: 4 square(s) Side length 3.61: 2 square(s) Total squares: 21 ================================================== # # Plus some graphs that I'm not showing here #Это меня поразило. Ответ был абсолютно точным.
Единственное небольшое, что модель не совсем правильно выполнила, — это отсутствие вывода графиков для каждого набора квадратов разного размера. Она показала только девять 1x1 и четыре √2x√2. Я исправил это, попросив Sonnet включить и остальные.
Можешь вывести графики в порядке длин сторон квадратов. Также сделай два графика бок о бок на каждой "строке".Вот что она создала.



Прекрасно.
Итог
Чтобы показать, насколько радикально продвинулись большие языковые модели примерно за год, я решил вернуться к сложной геометрической задаче, которую впервые пытался решить с помощью GPT-4o в июне 2024 года. Задача заключалась в написании программы на Python, которая находит и отображает все возможные квадраты на конкретной крестообразной сетке точек.
Мой опыт более года назад был полон трудностей; мне понадобилось около двух часов и свыше 40 подсказок, чтобы направить GPT-4o к правильному решению на Python.
Переходя к сегодняшнему дню, я протестировал новую Claude Sonnet 4.5. Когда я сначала задал модели вопрос напрямую, она не смогла рассчитать верное количество квадратов. Не самый лучший старт, однако настоящая проверка заключалась в предоставлении точно той же подсказки, что и для GPT-4o.
К моему удивлению, она выдала полное, правильное решение на Python с одного раза. Код, который она сгенерировала, не только обнаружил все 21 квадрат, но и правильно классифицировал их по уникальным длинам сторон, а также создал детальные графики для визуализации. Хотя для идеальных графиков потребовалась одна быстрая дополнительная подсказка, основная проблема была решена мгновенно.
Может ли быть, что сам факт моей попытки решить эту задачу год назад и публикации результатов ввел ее в веб-сферу, так что Anthropic просто проиндексировала это и включила в базу знаний модели? Да, возможно, но тогда почему модель не смогла правильно ответить на первый прямой вопрос о общем числе квадратов?
Для меня этот эксперимент ярко демонстрирует невероятный скачок в возможностях больших языковых моделей. То, что 16 месяцев назад было двухчасовой итеративной борьбой с ведущей моделью своего времени, теперь превратилось в пятисекундный успех с одного раза с ведущей моделью сегодня.