а cl:last вызывает SB-KERNEL:%LAST1, который проверяет тип параметра всегда (разве что ядро SBCL тоже перекомпилировать с safety = 0)
Вопрос в том, какой там машкод. Я имел ввиду, что, судя по наличию ворнинга, sbcl понимает «что-то тут не то» и, наверное, не применяет каких-то агрессивных safety-0 оптимизаций, которые бы применил в другом случае (если бы не знал что «что-то тут не то» => ворнинга бы не было). Например, тот же last он, думаю, в любом случае инлайнит, а потом в результате мби и проверку из полученного кода убирает, потому что программист же мамой поклялся.
Я имел ввиду, что, судя по наличию ворнинга, sbcl понимает «что-то тут не то» и, наверное, не применяет каких-то агрессивных safety-0 оптимизаций
Точно. Ошибка же:
is (1 2 1 2 1), not a LIST
Хотя на самом деле как раз LIST. Только декларация неверная. Похоже, при ошибке типов SBCL делает код, который всегда возвращает ошибку вместо вызова last.
Выкинул проверки на sb-thread, чтобы код был одинаков.
Получилось:
(declaim (optimize (speed 3) (safety 0) (space 0)))
(defmacro eval-A (i j)
`(let* ((n (+ ,i ,j))
(n+1 (1+ n)))
(declare (type (integer 0 22000) n n+1))
(/ (float (+ (ash (* n n+1) -1) ,i 1) 0d0))))
(defun eval-At-times-u (u n Au start end)
(declare (type fixnum n start end)
(type (simple-array double-float) u Au))
(loop for i from start below end do
(setf (aref Au i)
(loop for j below n
summing (* (aref u j) (eval-A j i))
of-type double-float))))
(defun eval-A-times-u (u n Au start end)
(declare (type fixnum n start end)
(type (simple-array double-float) u Au))
(loop for i from start below end do
(setf (aref Au i)
(loop for j below n
summing (* (aref u j) (eval-A i j))
of-type double-float))))
(defun execute-parallel (start end function )
(funcall function start end))
(defun eval-AtA-times-u (u AtAu v n start end)
(execute-parallel start end
(lambda (start end)
(eval-A-times-u u n v start end)))
(execute-parallel start end
(lambda (start end)
(eval-At-times-u v n AtAu start end))))
(defun main (n-supplied)
(let ((n n-supplied))
(declare (type fixnum n))
(or (typep (* (- (* 2 n) 1) (- (* 2 n) 2)) 'fixnum)
(error "The supplied value of 'n' breaks the optimizations in EVAL-A"))
(let ((u (make-array n :element-type 'double-float :initial-element 1.0d0))
(v (make-array n :element-type 'double-float))
(tmp (make-array n :element-type 'double-float)))
(declare (type (simple-array double-float) U V))
(dotimes (i 10)
(eval-AtA-times-u u v tmp n 0 n)
(eval-AtA-times-u v u tmp n 0 n))
(let ((vBv 0.0d0)
(vv 0.0d0))
(dotimes (i n)
(incf vBv (* (aref u i) (aref v i)))
(incf vv (* (aref v i) (aref v i))))
(format t "~11,9F~%" (sqrt (the (double-float 0d0) (/ vBv vv))))))))
Запустил:
CL-USER 1 > (time (main 1000))
Timing the evaluation of (MAIN 1000)
1.274224148
User time = 11.012
System time = 0.032
Elapsed time = 10.993
Allocation = 3840274500 bytes
0 Page faults
NIL
CL-USER 2 > (time (main 1500))
Timing the evaluation of (MAIN 1500)
1.274224151
User time = 26.028
System time = 0.012
Elapsed time = 25.981
Allocation = 8640423632 bytes
0 Page faults
NIL
Для сравнения в SBCL
* (time (main 1000))
1.274224148
Evaluation took:
0.339 seconds of real time
0.340000 seconds of total run time (0.340000 user, 0.000000 system)
100.29% CPU
608,955,666 processor cycles
93,040 bytes consed
NIL
* (time (main 1500))
1.274224151
Evaluation took:
0.739 seconds of real time
0.740000 seconds of total run time (0.740000 user, 0.000000 system)
100.14% CPU
1,328,040,588 processor cycles
129,808 bytes consed
Мне всегда казалось, что там только чистая математика: дифуры всякие, интегралы, системы уравнений... А вот как там циклы по массивам делать не представляю. Хотя, возможно, её просто недостаточно знаю. Всегда пользовался ею как справочником по интегралам.
Тут больше согласен. Это хотя бы язык программирования. Но, для меня, отладка удобней в Common Lisp — не требуется перезапуск алгоритма заново в случае ошибки. Да и синтаксис привычней.
В Google не видел ни одной базы данных которая имеено SQL, а не просто нереляционная с похожим на SQL языком запросов. Даже MySQL не совсем так работает
Мне всегда казалось, что там только чистая математика: дифуры всякие, интегралы, системы уравнений... А вот как там циклы по массивам делать не представляю.
Да можно точно также, все императивные конструкции там присутствуют, равно как и массивы (опционально - типизированные, опять же с возможной генерацией кода на сишке потом). Плюс преимущество той же математики/матлаба/чего-то еще аналогичного в том, что когда тебе понадобятся в ходе решения какие-то известные алгоритмы (ну например тот же симплекс метод) - они почти наверняка есть, причем выдроченные так, что твоя реализация на коленке в лучшем случае будет не слишком сильно проигрывать.
Вообще говоря, алгоритмы линейного программирования там офк тоже есть и вполне возможно даже ничего делать не придется - просто почитать доки и дернуть библиотечную ф-ю с нужными параметрами.
Тут больше согласен. Это хотя бы язык программирования. Но, для меня, отладка удобней в Common Lisp — не требуется перезапуск алгоритма заново в случае ошибки. Да и синтаксис привычней.
В математике тоже перезапускать не надо. И, кстати, mathematica language - чистейший лисп, (код является списком, голова - ф-я/спецформа, хвост - аргументы, есть лямбды и такое все) просто там много синтаксического математического сахара, который потом рассахаривается. Например, 1+2 это ни что иное как Plus[1,2] (что на самом деле просто список (Plus 1 2)), всякие красивые интегральчики, дроби значки сумм и т.п. - тоже просто сахар над списочной структурой.
То есть, если у меня работает что-то вроде
(mapcar (lambda (x) (/ 1 x)) l) и в списке встретится 0, то я могу указать что вернуть, возможно переопределить пару функций и продолжить выполнение алгоритма?
Наподобие
CL-USER 5 > (mapcar (lambda (x) (/ 1 x)) '(1 2 3 0 5))
Error: Division-by-zero caused by / of (1 0).
1 (continue) Return a value to use.
2 Supply new arguments to use.
3 (abort) Return to level 0.
4 Return to top loop level 0.
Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.
CL-USER 6 : 1 > :c 1
Supply a form to be evaluated and used: 0
(1 1/2 1/3 0 1/5)
То есть, если у меня работает что-то вроде (mapcar (lambda (x) (/ 1 x)) l) и в списке встретится 0
То просто вернется infinity и выплюнет эксцепшен, то есть вычисления закончатся вполне нормально :)
А рестартов вообще нету, да, обработка ошибок через catch-throw.
Но поскольку код пишется независимо запускаемыми кусками (а то и вовсе построчно), то это не проблема - ну упало наше (mapcar (lambda (x) (/ 1 x)) l), ее же пофиксили и перезапустили одну эту строчку.
Ну-ну. Попробуй для упомянутой транспортной задачи найти библиотечную функцию
Ну это же частный случай задачи линейного программирования. Так что можно просто LinearProgramming[*blah-blah*]. Более оптимальный руками придется, да.
Но даже в науке не всегда хватает широко известных алгоритмов
Конечно. Но в процессе реализации не слишком широко используемых широко используемые весьма часто применяются как шаг решения :)
поскольку код пишется независимо запускаемыми кусками
Тут же только что утверждалось, что есть нормальные циклы и массивы.
Если у меня через полчаса работы цикл упадёт, тем более без внятного описания в каком месте (состояния всех переменных), то от такой отладки никакого толка.
Тут же только что утверждалось, что есть нормальные циклы и массивы.
Ну так можно mapcar, можно массив аналогичный.
Если у меня через полчаса работы цикл упадёт тем более без внятного описания в каком месте (состояния всех переменных), то от такой отладки никакого толка.
Если там луп на полчаса - это уже не отладка явно.
Ну он такой же коммерческий, как LISP популярный. Размах «коммерции» SBCL по сравнению с Linux/GCC - это как капля в море. Так что ТАКОЙ коммерцией можно пренебречь :-)
В контексте мотивации разработки здесь надо сравнивать не размах коммерции, а отношение этого размаха на количество участников игры.
1. Есть состояние на момент падения. Все массивы, переменные цикла, временные переменные.
2. Можно в момент останова выполнять любые функции. Вычислить, например, детерминант массива.
3. Если стало понятно, что сделал не так (например, забыл проверку добавить, но таких значений мало, углы, например), то можно просто указать, что вернуть и продолжить вычисление не начиная заново.
если чтото упало, то рестарты тут уже не помогут
В CL как правило до конца не падает. Есть почти везде рестарт «использовать значение». И даже если нет, остаются пункты 1 и 2.
Когда я лабы по «выч методам в экспериментальной и теоретической физике» делал, там тестовый прогон был около 10-15 минут. Задача моделирования жидкости множеством точечных тел. Меньше не получалось, так как если тел десяток, то они уже не ведут себя как жидкость и нельзя проверить решение уравнениями гидродинамики. Так вот, (писал я тогда на Си) половину решения у меня занимал отладчик в стиле лиспа: если решение «ушло» от нормы, то останавливаемся и начинаем смотреть состояние на текущем шаге (+ несколько шагов назад сохранял). На CL всё свелось бы к сохранению истории.
Ну, во-первых, это еще надо искать и как-то склеивать друг с другом (в то время как в мат. пакетах все искаробки и just works), во-вторых например в той же махиме есть ли реализация для sparse arrays и есть ли альтернативные методы кроме симплекс-метода? В-третьих - ну йопта, линейное рпограммирования и симплекс-метод - какие-то совсем очевидные вещи, ессно они есть везде. А что-то менее специфичное? Например, ну, не знаю, пусть будет:
сравнивать ракету и cl в плане использования как программной лаборатории
Тут однозначно CL лучше. В ракете намеренно испортили режим «программной лаборатории», так как он часто конфликтует с режимом «написать надёжную программу. Подробнее (если интересно): Анализ пользователей Common Lisp и Racket
P.S. На Racket можно сделать среду для эффективной программной лаборатории. Но готовой нет (самое близкое Emacs + geiser, но отладчик сильно уступает SLDB).
И возможность увидеть данные на момент падения и вычислить любую функцию от этих данных тоже очень помогает
Ну классический дебаггер там есть, со стектрейсом, бряками и т.п. (можно поставить автоматические бряки на мессаджи типа «у вас деление на ноль») так что данные можно посмотреть и поприменять все что хочешь там же, нельзя только произвольное значение в середину control-flow запихать.
Опять же по набору методов и удобства применения по сравнению с фольфрамом посасывает, я там могу вот прямо img = Import["http://...«]; Inpaint[img, mask]. Мне эту картинку с результатом сразу нарисует в notebook, можно ее покрутить и сходу сохранить в любом удобном формате.
Какими наворотами-то? По-моему это миф какой-то. Все время говорят о наворотах, но не могут их назвать.
Хотя бы той же макросистемой. Хотя бы тот факт что «макросистема Racket является строгим надмножеством макросистемы CL» говорит где общий случай, а где - частный. Несмотря на «тупой» подход, макры CL просты и реально практичны. (Не надо мне заливать, пожалуйста, про гигиены, и про то, что возможно где-то кто-то когда-то используя чей-то макрос напорится на утечку абстракции, и что поэтому макры CL - это говно говённое, а вот в Рэкет - там они само совершенство. CL - это язык *моего* предпочтения, который позволяет мне быстренько заставлять компьютер делать то, что мне надо. Это многим важнее для меня, чем все рассказики про анафорическую муть и соблюдение канонов идеального совершенства программирования, или размышления о теоретических суждениях типа «а что если проект пишут тысяча разработчиков из разных концов света. Как же это они умудряться вести разработку в образе??11» - «Ну, тогда CL - отстой.»)
Сам язык Racket больше - операторов и функций, даже for/«на каждый чих». Потом, система модулей. В ООП опять эти private, public, опять интерфейсы, трэитсы. Потом продолжения и контракты. Так что Racket - это эдакий C++.
Ладно, убедил. Хотя из моего опыта научной работы, я сомневаюсь что при необходимости более-менее сложного мат. моделирования требуется широкий спектр алгоритмов. Вот нестандартные алгоритмы, точнее «чуть-чуть допиленные» стандартные требуются часто. Поэтому если ситуация «вот задача — нужен ответ», то Matlab/Mathematica, а если ситуация «нужно смоделировать приводнение капсулы на 2 км/секунду», или «вот набор фотографий, построй 3Д объект из них», то стандартные алгоритмы если и нужны, то с исходниками.
из десятка разных костылей собирать квадратноколесный велосипед
Все НИР с использованием выч.техники, которые я видел, так и делаются :-)
Ну дык CL для инженеров инженерами задумывался, вот и бери его для экспериментов, а там херак-херак-прототип и в продакшен :) не раз такое у меня было ;)
Несмотря на «тупой» подход, макры CL просты и реально практичны.
Так тебя никто не заставляет использовать всякую анальную акробатику. Простые макросы из CL можешь писать так же, как в CL - это будет даже _проще_ (т.к. не надо думать о связывании, за тебя уже подумали и все работает само по себе) и с большим функционалом (т.к. опять же, автоматически трекается source location и т.п. вещи). Еще раз - ты в этом никак не участвуешь, твои усилия нулевые (по сравнению с CL даже отрицательные) оно само по себе. Just works. А ты просто пишешь код и наслаждаешься результатом, который выше при более низких по сравнению с CL затратах.
Потом, система модулей. В ООП опять эти private, public, опять интерфейсы, трэитсы. Потом продолжения и контракты.
А в общелиспе нету ооп и метаобъектного протокола? А пекеджей и евал-вен вырвиглазных, с семантикой сложнее и тупее чем модули? Продолжения - вообще тривиальная вещь.
Как же это они умудряться вести разработку в образе??11