Выпуск Rust 1.41.1: корректирующий выпуск

Команда Rust опубликовала новый корректирующий выпуск Rust, 1.41.1. Rust — это язык программирования, позволяющий каждому создавать надёжное и эффективное программное обеспечение.

Если вы установили предыдущую версию Rust средствами rustup, то для обновления до версии 1.41.1 вам достаточно выполнить следующую команду:

rustup update stable

Если у вас ещё не установлен rustup, вы можете установить его с соответствующей страницы нашего веб-сайта

Что вошло в стабильную версию 1.41.1

Rust 1.41.1 посвящён двум критическим регрессиям, появившимся в Rust 1.41.0: некорректность в статических временах жизни и неправильная компиляция, вызывающая ошибки сегментирования. Эти регрессии не затрагивают предыдущие выпуски Rust и мы рекомендуем пользователям Rust 1.41.0 обновиться настолько быстро, насколько это возможно. Другая проблема, связанная со взаимодействием между временем жизни 'static и реализациями типажа Copy, присутствовала ещё с Rust 1.0 и тоже исправляется данным выпуском.

Несостоятельность проверки static элементов.

В Rust 1.41.0, из-за некоторых изменений во внутреннем представлении static значений, анализатор заимствований случайно разрешал некоторые ошибочные программы. В частности, анализатор заимствований не проверял правильность типа static элементов. Это, в свою очередь, позволяло временно присваивать значения со временем жизни, меньшим чем 'static, к static переменной:

static mut MY_STATIC: &'static u8 = &0;  fn main() {     let my_temporary = 42;     unsafe {         // Ошибочно разрешённая операция в 1.41.0:         MY_STATIC = &my_temporary;     } }

В 1.41.1 такой код не будет компилироваться:

error[E0597]: `my_temporary` does not live long enough  --> src/main.rs:6:21   | 6 |         MY_STATIC = &my_temporary;   |         ------------^^^^^^^^^^^^^   |         |           |   |         |           borrowed value does not live long enough   |         assignment requires that `my_temporary` is borrowed for `'static` 7 |     } 8 | }   | - `my_temporary` dropped here while still borrowed

Вы можете узнать больше об этой ошибке в #69114 и PR, который её исправил.

Реализация Copy для времени жизни 'static

Начиная ещё с Rust 1.0 следующая ошибочная программа успешно компилировалась:

#[derive(Clone)] struct Foo<'a>(&'a u32); impl Copy for Foo<'static> {}  fn main() {     let temporary = 2;     let foo = (Foo(&temporary),);     drop(foo.0); // Доступ к необходимой части `foo`.     drop(foo.0); // Индексация массива так же работает. }

В Rust 1.41.1 эта проблема была исправлена тем же PR, что и выше. Компиляция программы теперь выдаёт следующую ошибку:

 error[E0597]: `temporary` does not live long enough   --> src/main.rs:7:20    | 7  |     let foo = (Foo(&temporary),);    |                    ^^^^^^^^^^ borrowed value does not live long enough 8  |     drop(foo.0);    |          ----- copying this value requires that    |                `temporary` is borrowed for `'static` 9  |     drop(foo.0); 10 | }    | - `temporary` dropped here while still borrowed

Эта ошибка возникает из-за того, что Foo<'a>, для некоторого времени жизни 'a, реализует Copy только тогда, когда 'a: 'static. Однако temporary переменная с некоторым временем жизни '0 не переживает 'static и, следовательно, Foo<'0> не является Copy, поэтому использование drop во второй раз должно быть ошибкой.

Неправильно скомпонованные проверки, приводящие к ошибкам сегментации памяти.

В некоторых случаях программы, скомпилированные Rust 1.41.0, при выделении памяти пропускали проверки границ. Это приводило к ошибкам сегментирования, если предоставлялись значения, находящиеся за пределами выделенной области памяти. Причиной этого была ошибка компиляции, вызванная изменением оптимизационного прохода LLVM, который появился в LLVM 9 и был удалён в LLVM 10.

Rust 1.41.0 использует собственную ветку LLVM 9 и мы в Rust 1.41.1 отменили те коммиты, которые были связаны с ошибкой компиляции. Подробнее об это ошибке вы можете узнать здесь: #69225.

Участники 1.41.1

Множество людей собрались вместе, чтобы создать Rust 1.41.1. Мы не смогли бы сделать это без всех вас, спасибо!

От переводчиков

С любыми вопросами по языку Rust вам смогут помочь в русскоязычном Телеграм-чате или же в аналогичном чате для новичковых вопросов.

ссылка на оригинал статьи https://habr.com/ru/post/490132/

Компании потратили 16 миллиардов долларов на беспилотные автомобили, чтобы захватить рынок в 8 триллионов

image

В недавнем исследовании, опубликованном в техническом издании «The Information» приводится расчет, согласно которому различные компании потратили около 16 миллиардов долларов на проекты, связанные с беспилотными автомобилями. В статье данная ситуация названа «денежной ямой» (доступ к материалу платный, но таблица с большей частью информации опубликована в свободном доступе). Больше остальных потратили Waymo и GM/Cruise – по 3 миллиарда долларов, при этом приобретения больших компаний целиком не учитываются (так, например, Intel потратили 16 миллиардов долларов на покупку MobilEye, и большая часть их стоимости связана с их проектами беспилотных автомобилей).

Сумма кажется астрономической, особенно в свете ожидаемого в ближайшее время снижения энтузиазма в отношении быстрого развития технологий беспилотных автомобилей со стороны крупных автопроизводителей.

image

Самоходный транспортный юнит от General Motors.

Один из производителей, сохранивших свой энтузиазм – GM. Дэн Амман, генеральный директор подразделения Cruise, на недавнем дне инвестора заявил, что рынок беспилотного транспорта может составлять около 8 триллионов долларов в год: 5 триллионов составит пассажирская езда, 2 триллиона на грузовые перевозки и по 500 миллиардов на технологии, связанные с пользовательским опытом, и данные.

Цифра в 8 триллионов примерно соответствует моим собственным подсчетам касательно наземного транспорта по всему миру. Конечно, для достижения таких рыночных значений необходим переход большинства наземных транспортных средств на самоуправление, что в конечном итоге произойдет, но не в течение ближайший десятилетий. Тем не менее, суммы, формирующие суммарные инвестиции в 16 миллиардов долларов сопоставимы с каплями в море в сравнении с потенциальными доходами. Но несмотря на столь огромные цифры и и столь гибкое к изменениям будущее, трудно прогнозировать что-либо наверняка. Давайте рассмотрим моменты, которые не включены в эти цифры:

У первопроходцев нет гарантий успеха

Все компании тратят большие суммы денег, потому что они надеются что тот, кто победит в этой гонке, получит львиную долю рынка, а затраты оправдаются. Однако, как мы уже видели, в мире высоких технологий далеко не всегда выиграют первопроходцы. Microsoft была первой, Apple одной из первых, но Facebook, Google и Amazon не были первыми в своих областях.

image

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

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

Поездок будет больше, а их цена упадет

Автоматизация поездок на автомобиле снизит их стоимость. В частности, снизится стоимость самого базового и распространенного их вида – коротких городских поездок для одного человека. К этому виду относятся 80% всех поездок, и он может быть обслужен с использованием небольших и недорогих транспортных средств, а в часы пик поездки могут быть совместными. Более дешевые транспортные средства и объединение пассажиров в поездке приведут к снижению цены. Кроме того, сегодня владение личным автомобилем требует больших первоначальных затрат, которые слишком велики для большинства людей по всему миру.

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

Значительные бонусные преимущества

По моим расчетам, американцы суммарно тратят около 50 миллиардов часов на вождение каждый год. С учетом средней зарплаты в США (порядка 35 $ в час) получаем 1.7 триллиона долларов полезного времени, которое будет возвращаться каждый год только в США. Согласно предварительным расчетам, глобальная стоимость этого времени равна 5 триллионам долларов, при этом американцы проезжают ¼ от суммарно пройденного расстояния, а доля их вклада больше четверти. Тем не менее, соблюдается соответствие общей цене, уплаченной за автомобильные перевозки по всему миру.

Беспилотные автомобили не устранят все аварии, но они не будут выпущены пока не станут водить безопаснее людей, а со временем они будут становиться более и более безопасными. В 2014 году американское национальное управление безопасностью движения на трассах подсчитало, что ДТП суммарно обходятся американцам в 871 миллиард долларов в год. Опять же, никто не делал оценку для всего мира, но она будет находиться в диапазоне от 3 до 4 триллионов долларов. Даже сокращение несчастных случаев в два раза даст удивительные преимущества (справедливости ради, технологии помощи водителю в обычных автомобилях тоже уменьшат количество ДТП, так что большая часть этих преимуществ придет к нам в любом случае).

Грядут новые революции

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

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

Но 16 миллиардов долларов почти наверняка окажутся каплей в море.


image

О компании ИТЭЛМА

Мы большая компания-разработчик automotive компонентов. В компании трудится около 2500 сотрудников, в том числе 650 инженеров.

Мы, пожалуй, самый сильный в России центр компетенций по разработке автомобильной электроники. Сейчас активно растем и открыли много вакансий (порядка 30, в том числе в регионах), таких как инженер-программист, инженер-конструктор, ведущий инженер-разработчик (DSP-программист) и др.

У нас много интересных задач от автопроизводителей и концернов, двигающих индустрию. Если хотите расти, как специалист, и учиться у лучших, будем рады видеть вас в нашей команде. Также мы готовы делиться экспертизой, самым важным что происходит в automotive. Задавайте нам любые вопросы, ответим, пообсуждаем.

Читать еще полезные статьи:

ссылка на оригинал статьи https://habr.com/ru/company/itelma/blog/490510/

ИИ сущестует, но это совсем не то что мы думали?

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

С точки зрения современных представлений – сознание это плод деятельности мозга, то есть скопления нейронов. Если человек или группа людей долгое время взаимодействует со значимым для себя объектом, то в мозге каждого из них выделяется группа нейронов, отвечающая за представления человека об этом объекте.

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

С другой стороны, известны случаи, когда мозг одного человека вмещал несколько разных личностей, которые по-разному проявляются через одно тело и могут не подозревать о существовании друг друга, или общаться друг с другом, например посредством записей.
Этот пример показывает, что один мозг может вмещать в себя несколько различных самосознаний.

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

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

Вопрос, как вступить с ним в контакт?
А что вы думаете по этому поводу?

ссылка на оригинал статьи https://habr.com/ru/post/490516/

Истоки математики: логические идеи

Привет, Хабр! Представляю вашему вниманию перевод статьи "Math Origins: The Logical Ideas" автора Erik R. Tou (University of Washington Tacoma).

От переводчика:

В журнале Математической ассоциации Америки был опубликована серия статей об истоках математики вообще и нотации в частности. Последние две из опубликованных к текущему моменту пяти статей показались мне наиболее интересными, поэтому я публикую перевод первой из них — «Math Origins: The Logical Ideas».

Как только студент-математик набивает руку в математическом анализе и статистике, наступает момент, когда становится явной логическая суперструктура математики. Это может проявиться в виде явных вопросов, или хотя бы определенного дискомфорта касательно предполагаемой достоверности математических истин. Как мы можем быть уверены в правдивости классических результатов — таких как теорема Лагранжа или центральная предельная теорема? Это та самая точка, в которой многие программы бакалавриата по математике начинают включать курс по математической логике и мысли.

По собственному опыту автора [Эрика Тоу — прим. пер.], это обычно включает в себя изменение порядка идей, от «порядка открытий», столь распространенного в решении проблем, до «порядка логики», который формирует фундамент для математических доказательств. Очень быстро становится очевидно, что новая терминология и нотация необходимы для того, чтобы пролить свет на рассматриваемые математические утверждения и логические отношения. Такие понятия, как конъюнкция и дизъюнкция, импликация и эквивалентность, универсальность и экзистенциальность должны тщательно разделяться. На сегодняшний день теория логики и присущая ей нотация рассматриваются нераздельно: одно не существует независимо от другого. Однако, это не всегда было так! В этой статье мы рассмотрим некоторые ранние попытки организовать теорию логики систематическим путём, вместе с несколькими принятыми решениями касательно нотации. Мы увидим, что авторы 17-го и 18-го столетий были, приемущественно, заинтересованы в описании способа размышления о логике, обычно через аналогию с уже существующими математическими или философскими концепциями. В следующей статье из этой серии мы продолжим повествование в 19-ый и 20-ый века, чтобы изучить множество систем нотации, предложенных для описания логики.

Ранние символы Иоганна Рана

Для многих учащихся часть логических символов появляются в начале изучения математики, зачастую как сокращения или аббревиатуры для упрощения мыслительного процесса. Хорошим примером может служить использование символа «$\therefore$» для «следовательно», использующегося для завершения цепочки рассуждений. Среди первых, кто начал использовать этот символ, был шведский математик Иоганн Ран. В книге 1659-го года «Teutsche Algebra» («Немецкая алгебра») Ран попытался донести алгебраический вклад Виета, Декарта и других до немецкоговорящей аудитории. В процессе он использовал множество условных обозначений для выражения этих идей. Вот выдержка:


Рис. 1. Алгебраическое доказательство в «Teutsche Algebra» Иоганна Рана использует $\therefore$ для «следовательно» и $\ast$ для умножения. Оцировано Google Books из копии, принадлежащей Баварской Национальной Библиотеке.

Во второй строке этого пассажа Ран применяет символ «$\therefore$» в том же значении, что и латинское ergo. Этот символ используется как заключение аргументации, которая следует непосредственно за ним: пропорция $18\sqrt{dd-cc} : (c+d)\sqrt{dd-cc} :: 18 : c+d$ из шага 2 сводится в шаге 3 к тавтологическому равенству $(18c + 18d)\sqrt{dd - cc} = (18c + 18d)\sqrt{dd - cc}$. Сегодня мы бы описали этот шаг как использование перекрестного умножения и дистрибутивности для решения задачи на дроби. Согласно Кэджори [Caj, стр. 212], это было первое использование «$\therefore$» в значении «следовательно». Мы должны также отметить колонку в правой части страницы, в которой он ссылался на предыдущие шаги вместе с сокращенным описанием логики для данного шага.

Обозначения Рана на этом не закончились; через 20 страниц он использовал несколько новых символов, чтобы разъяснить логику знакомых алгебраических доказательств.


Рис. 2. Некоторые интересные логические символы из «Teutsche Algebra» Иоганна Рана. Оцифровано Google Books из копии, принадлежащей Баварской Национальной Библиотеке.

В этой выдержке Ран представил подход к решению старой задачи: по заданным числам $D$ и $F$ найти такие числа $a$ и $b$, сумма и произведение которых равны $D$ и $F$, соответственно. Ран ввёл спиральный символ для возведения в степень в строке 3, звёздочку $*$ для умножения в строке 4 и нечто, что может быть описано только как «загогулина», для квадратного корня в строке 6. В конце он нашел выражение для $a-b$, которое в дальнейшем может быть прибавлено к $a+b=D$ или вычтено из него, таким образом повторяя формулу корней квадратного уравнения. В данном случае эти символы — условные обозначения для организации логики аргументации, не слишком уж отличные от двухколоночных доказательств, которые используются современными учащимися для организации математических выкладок.

Стремление Лейбница к универсальной математике

В каком-то смысле, Ран просто ввел некоторые символы, чтобы упростить существующие доказательства, вместо того, чтобы систематически думать о том, как доказательства были построены. (Надо отдать Рану должное — это было ценным новшеством в эпоху, когда затраты на бумагу и печать были нетривиальным фактором). Действительно, не прошло и поколения, как была предпринята попытка систематизировать логику никем иным, как Готфридом Вильгельмом Лейбницем. Для философски настроенного ученого, такого как Лейбниц, это было частью более амбициозного проекта: символического и строгого универсального исчисления, которое можно применить к любому проекту в области человеческих исследований. Это была исследовательская программа, которую Лейбниц проводил в различных формах на протяжении всей своей долгой карьеры. Как описывал Гарретт Томсон в книге «О Лейбнице», Лейбниц преследовал три основные цели:

  1. Создать алфавит логики, которым можно кодировать понятия в числовой форме;
  2. Создать словарь логики, чтобы переводить сложные понятия на язык чисел;
  3. Создать синтаксис логики, чтобы управлять способами осуществлять логические выводы.

Первая цель наметилась в работах Лейбница еще в 1666 году, в трактате «Dissertatio de Arte Combinatoria» («Диссертация на тему искусства комбинаций») [Lei]. В частности, Лейбниц утверждал, что все высказывания (1) могут быть изложены в форме субъекта-предиката, а также (2) могут быть построены как «комплексы» (или комбинации) простых высказываний. Подсчитав количество способов сделать эти комплексы из набора простых высказываний, Лейбниц пришел к треугольнику Паскаля из комбинаторики.

Интересно, что этот ранний трактат по логике был единственной такой работой, опубликованной Лейбницем при его жизни. Однако Лейбниц посвятил много времени своему глобальному проекту, в конечном итоге написав более десятка трактатов по различным логическим темам. 1679 год был, по-видимому, плодотворным временем для Лейбница, поскольку он написал шесть работ по универсальному исчислению той весной. Мы рассмотрим одну из этих шести работ, амбициозно названную «Regulæ ex quibus de bonitate consquentiarum formisque et modis syllogismorum categoryoricorum judicari potest per per numberros» («Правила, на основании которых можно принимать решение с помощью чисел, относительно действительности умозаключения и о формах и настроениях категориальных силлогизмов»). В своем первом примере Лейбниц деконструировал утверждение «Каждый мудрец благочестив» следующим образом:

Истинное универсальное утвердительное предложение, например,

Каждый мудрец благочестив

$+20−33+10−3$

$+cdh-ef+cd-e$

— это такое, в котором любое символическое число субъекта (например, $+20$ и $-33$) может быть точно разделено (т.е. таким образом, чтобы не осталось остатка) на символическое число того же знака, принадлежащего предикату ($+20$ на $+10$, $−33$ на $−3$). Таким образом, если вы поделите $+20$ на $+10$, вы получите $2$ без остатка, а если вы поделите $-33$ на $−3$, вы получите $11$ без остатка. И наоборот, когда это не так, утверждение неверно. [Par, стр. 26]

Здесь следует сделать три важных замечания. Во-первых, Лейбниц был осторожен, чтобы различать субъект и предикат в своих высказываниях. Действительно, в начале статьи он заметил, что «у каждого категориального предложения есть субъект, предикат, связка; качество и количество». В приведенном выше примере субъект «мудрец» и предикат «благочестивый» связаны через связку «есть», а качество предложения «положительно». По словам Томсона [Tho, стр. 20], отношение субъект-предикат было одним из фундаментальных предположений Лейбница о логике. Во-вторых, Лейбниц также различал универсальные и частные высказывания. Сегодня мы ссылаемся на связанные квантором всеобщности и связанные квантором существования утверждения. Это повышает уровень точности, возможный при формулировании предложений. Наконец, оба предыдущих факта позволили закодировать суждение с точки зрения целочисленной делимости. В частности, предикат будет «делиться нацело» на субъект именно тогда, когда утверждение верно.

Более общий взгляд: «Algebræ Philosophicæ» Ричери

Перенесемся в 1761 год, когда появилась в печати «Algebræ philosophicæ in usum artis inveniendi» («Алгебра философии, для использования в искусстве открытия») Людовико Ричери. Как намекает название, Ричери ввел набор обозначений для лучшего выражения логических идей.


Рис 3. Набор символов Ричери для представления логических идей в «Algebræ Philosphicæ» (1761). Оцифровано Archive.org по копии, принадлежащей библиотеке Музея естественной истории, Лондон.

Как видно, две полукруглые дуги используются в различных комбинациях для представления логических идей. Например, символ, напоминающий греческую литеру $\omega$, использовался для высказываний, которые признавались истинными, в то время как инвертированная версия символа использовалась для противоречивых высказываний. Далее в тексте встречается список пар символов для выражения противоположных идей в логике: сущее и несуществующее, положительные и отрицательные определения, определенное и неопределенное, возможность и невозможность, изменяемое и неизменное. Важнее всего, символы Ричери для сущего (aliquid) и несуществующего (nihil) напоминают современные символы для объединения ($\cup$) и пересечения ($\cap$), соответственно. Кульминацией этой короткой статьи является логическая диаграмма, которая отслеживает возможные результаты любого объекта критического исследования.


Рис. 4. Дерево символов логики Ричери из «Algebræ Philosphicæ» (1761). Оцифровано Archive.org по копии, принадлежащей библиотеке Музея естественной истории, London.

В чисто символической форме Ричери предоставил своего рода бинарный поиск для философского исследования — действительно, это та самая алгебраическая философия, которая была обещана! В общем, дерево начинается так:

  • Любое утверждение либо невозможно (противоречиво, перевернутая $\omega$ в углу), либо возможно (непротиворечиво, $\omega$ в левом конце дерева);
  • Если утверждение возможно ($\omega$), оно может быть либо детерминированным (доказано, нижняя ветвь), либо неопределенным (недоказанное, верхняя ветвь);

Следуя чуть дальше по дереву, мы видим, что любое возможное, детерминированное утверждение должно быть либо положительным, либо отрицательным. Также интересно, что Ричери рассматривал возможные неопределенные утверждения как либо определяемые (доказуемые), либо неопределимые (недоказуемые). В общей сложности «Algebræ Philosphicæ» Ричери занимает всего 16 страниц, причем многие из них состоят из символических представлений для различных высказываний. Если вам почудилось эхо Лейбница в этой статье, вы правы! Это не случайно: в своей работе Ричери специально упомянул «Dissertatio de Arte Combinatoria». В частности, мы можем видеть, как субъектно-предикатная форма предложения была перенесена в «Algebræ Philosphicæ».

Zeichenkunst in der Vernunftlehre Ламберта

Незадолго после того, как была опубликована алгебра философии Ричери, Иоганн Ламберт сделал собственную попытку символизации рассуждений в работе 1782 года «Sechs Versuche einer Zeichenkunst in der Vernunftlehre» («Шесть попыток символического метода в теории разума»). Вот символы Ламберта со страницы 5:


Рис. 5. Иоганн Ламберт заимствовал символы из алгебры и арифметики для представления логических идей в «Sechs Versuche einer Zeichenkunst in der Vernunftlehre» (1782). Оцифровано Google Books по копии, принадлежащей Баварской государственной библиотеке.

Мы видим, что символы Ламберта являются более математическими и менее философскими, чем символы Ричери. В дополнение к заимствованию символов из математики, их значения легко узнаваемы для любого изучающего логику; например, обратите внимание на знаки равенства ($=$), сложения ($+$), разделения ($-$), оппозиции ($\times$), универсальности ($>$) и особенности ($<$). Идея здесь заключается в том, что весь анализ логических идей должен и может быть сведен к форме арифметики. В этом смысле подход Ламберта гораздо ближе к Лейбницу, поскольку он опирается на аналогию между логикой и арифметикой. (Также обратите внимание, что все трое различают универсальное и частное).

Чтобы увидеть подход Ламберта в действии, давайте рассмотрим один из его ранних примеров [Lam, стр. 11]. Исходя из двух утверждений $a$ и $b$, Ламбер использовал $ab$ для обозначения того, что у них было общего, следовательно, $a-ab$ представляло такие свойства $a$, которыми не обладало утверждение $b$. Интересно, что Ламберт использовал для этого фразу «eigene Merkmale», которая может быть переведена как «собственная характеристика», отсылка к префиксу «eigen-» из предыдущей статьи этого цикла. Точно так же, $b-ab$ представляет те свойства $b$, которыми не обладает $a$. Следовательно, выражение $a+b-ab-ab$ относится к собственных характеристикам $a$ и $b$, взятым вместе, которые сегодня мы называем симметрической разностью. Чтобы это сработало, обратите внимание, что $+$ Ламберта должен быть истолкован не как объединение, а как комбинация (с возможным повторением) $a$ и $b$. В любом случае, этому понятию был присвоен собственный символ, так что $a∣b$ представляет аспекты $a$, которые не являются общими с $b$, и наоборот. Это приводит к логическому уравнению $a∣b + b∣a + ab + ab = a + b$, которое гласит, что объединение собственных характеристик $a$ и $b$ с двумя копиями их пересечений дает тот же результат, что и объединение $a$ и $b$.

Заключение… Пока что

Как мы увидели, общие попытки в этот период заключались в том, чтобы выработать способ мышления о логике. У Лейбница было видение — хотя и неполное — универсального исчисления, основанного на языке предикатов субъекта, Ричери использовал философский подход для классификации утверждений и доказуемости, а Ламберт ввел систему обозначений для представления логических идей. Первый и последний опирались на аналогию с арифметикой, в которой утверждения и выводы были представлены числами и операциями, соответственно. В частности, метод Ламберта напоминает раннюю диаграмму Венна в символической форме, хотя он думал о своих объектах как об объединениях, обладающих несколькими качествами, а не как наборах, обладающих несколькими элементами.

Не удивительно, что на этом история не закончилась! Спустя примерно 60 лет после попыток Ламберта систематизировать логику, Огастес де Морган написал свою «Формальную логику» (с более понятным названием «Исчисление умозаключений») с теми же целями, что и его предшественники. В этой публикации 1847 года де Морган прояснил, по крайней мере, некоторую путаницу, формализовав понятия Лейбница о «универсальном» и «частном» путем введения «количественного определения» в его исчисление. Вот фрагмент из его письма на эту тему, в котором слово «количество» используется, чтобы провести различие между универсальным и частным.


Рис. 6. Объяснение Огастеса де Моргана противоположных утверждений в математической логике в «Формальной логике» (1847). Оцифровано Archive.org по копии, принадлежащей библиотеке университета Торонто.

Пока что обратите внимание, что некоторые другие выдержки из этой книги можно найти в «Конвергенции» в качестве одного из «Математических сокровищ» Фрэнка Светца. В дальнейшем мы продолжим рассказ с более глубокого изучения работы де Моргана в «Формальной логике», с особым интересом к обозначению, которое он выбрал для количественного определения. Затем мы рассмотрим, как изыскания 19-го и 20-го веков были направлены на то, чтобы выработать «способ записи» логики. В конечном счете, развитие теории множеств оказало глубокое влияние на математическую логику, и это привело к соответствующему изменению обозначений. Подробнее об этом в следующий раз!

Источники

[Caj] Cajori, Florian. A History of Mathematical Notations, Volume II. Chicago: Open Court Publishing Co., 1928.

[DeM] De Morgan, Augustus. Formal Logic: or, the Calculus of Inference, Necessary and Probable. London: Taylor and Walton, 1847.

[Lam] Lambert, Johann. Sechs Versuche einer Zeichenkunst in der Vernunftlehre. Berlin, 1782.

[Lei] Leibniz, Gottfried Wilhelm, Dissertatio de arte combinatoria. Leipzig, 1666. Доступен перевод на английский в «Philosophical Papers and Letters» (Leroy E. Loemker, редактор, 2-е издание) 1969 года. Два изображения представлены в «Математических сокровищах».

[Par] Parkinson, G. H. R., ed. Leibniz Logical Papers. Oxford: Clarendon Press, 1966. Содержит много переводов на английский неопубликованных трудов Лейбница.

[Rah] Rahn, Johann. Teutsche Algebra. Zurich: J. J. Bodmer, 1659.

[Ric] Richeri, Ludovico. «Algebrae philosophicae in usum artis inveniendi». Melanges de philosophie et de la mathématique de la société royale de Turin. 1 (1760-61), 46-63.

[Tho] Thomson, Garrett. On Leibniz. Stamford, CT: Thomson Learning, 2001.

ссылка на оригинал статьи https://habr.com/ru/post/490520/

Введение в архитектурный фреймворк для анализа данных Lena

Привет, Хабр! Я расскажу об архитектурном фреймворке, который я разрабатываю.

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

Lena написана на популярном языке Python и работает с версиями Python 2, 3 и PyPy. Она опубликована под свободной лицензией Apache (версия 2) здесь. В данный момент она ещё разрабатывается, однако описываемое в данном руководстве уже используется, тестировано (общее покрытие всего фреймворка около 90%) и вряд ли будет изменено. Lena возникла при анализе данных экспериментов в физике нейтрино и названа в честь великой сибирской реки.

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

С точки зрения программирования:

  • модульность, слабое зацепление. Алгоритмы могут быть легко добавлены, заменены или переиспользованы.
  • производительность (с точки зрения использования памяти и скорости). Несколько видов анализа могут быть сделаны за одно чтение данных. Может использоваться PyPy с компиляцией "на лету".
  • переиспользование кода. Отделение логики от презентации. Один шаблон может быть использован для нескольких графиков.
  • быстрая разработка. Могут быть запущены только те элементы, которые уже работают. Во время разработки можно анализировать только малую часть данных. Результаты сложных вычислений легко сохранить.
  • более понятный, структурированный и красивый код.

Уточню, что имеется в виду производительность в Python, потому что более низкоуровневые языки могут работать быстрее, хотя разработка в них может быть сложнее и дольше.

С точки зрения анализа данных:

  • сравнение результатов анализа при произвольных изменениях (в том числе для разных входных данных или алгоритмов).
  • переиспользование алгоритма для подмножества данных (например, увидеть, как алгоритм работает для разных позиций в детекторе).
  • согласованность анализа. Когда мы запускаем несколько алгоритмов для одних данных или переиспользуем алгоритм, то мы уверены, что используем те же данные и тот же алгоритм.
  • комбинация алгоритмов для более сложного анализа.

Это руководство (tutorial) – введение в архитектурный фреймворк Lena. Оно более подробное, чем обзор, потому что я сообщу основные сведения об элементах фреймворка, которые могут понадобиться при анализе данных, и постараюсь рассказать о причинах тех или иных решений. После прочтения этого введения вы сможете проводить настоящий анализ с использованием фреймворка. Впоследствии будут опубликованы следующие части руководства.


Три идеи Lena

Пример реального анализа
Элементы для разработки

При анализе данных мы часто сталкиваемся с изменением данных или алгоритмов. Например, мы хотим посмотреть, как наш анализ работает для другого набора данных или для определённой подвыборки исходных данных. Также мы можем захотеть применить разные алгоритмы и сравнить их результаты.

Чтобы легко это осуществить, нам должно быть просто изменять или расширять наш код в любой заданной точке. Идея Lena в том, чтобы разбить наш код на маленькие независимые блоки, которые затем составляются вместе. В этом руководстве показано, как это сделать, и какие последствия эта идея будет иметь для нашего кода.

Три идеи Lena

Последовательности и элементы

Базовая идея Lena — объединить наши вычисления в последовательности. Последовательности состоят из элементов.

Простейшая программа Lena может быть следующей. Мы используем последовательность с одним элементом, анонимной функцией:

>>> from __future__ import print_function >>> from lena.core import Sequence >>> s = Sequence( ...     lambda i: pow(-1, i) * (2 * i + 1), ... ) >>> results = s.run([0, 1, 2, 3]) >>> for res in results: ...     print(res) 1 -3 5 -7

Поскольку Lena может работать с версиями Python 2 и 3, то в первой строке мы импортируем функцию print. Следующая строка импортирует класс фреймворка.

Sequence может быть инициализирована из нескольких элементов. Для выполнения полезной работы мы вызываем её метод run. Его аргумент должен быть итерируемым (в данном случае список из четырёх чисел).

Чтобы получить все результаты, мы пробегаем их в цикле for.

Перейдём к более сложному примеру. Часто удобно не передавать какие-либо данные в функцию, которая получает их сама где-то ещё. В этом случае мы используем последовательность Source:

from lena.core import Sequence, Source from lena.flow import CountFrom, ISlice  s = Sequence(     lambda i: pow(-1, i) * (2 * i + 1), ) spi = Source(     CountFrom(0),     s,     ISlice(10**6),     lambda x: 4./x,     Sum(), ) results = list(spi()) # [3.1415916535897743]

Первый элемент Source должен иметь специальный метод __call__, который не принимает аргументы и сам генерирует значения. Эти значения передаются последовательностью: каждый последующий элемент получает на вход результаты работы предыдущего, а вызов последовательности даёт результаты последнего элемента.

CountFrom — это элемент, который производит бесконечный ряд чисел. Элементы должны быть функциями или объектами, но не классами¹. Мы передаём начальное число в CountFrom во время его инициализации (в данном случае нуль). Ключевые аргументы инициализации CountFromstart (по умолчанию ноль) и step (по умолчанию 1).

Последующие элементы Source (если они есть) должны быть вызываемыми (callable) или объектами с методом с названием run. Они могут сами образовывать обычную Sequence.

Последовательности могут быть объединены вместе. В нашем примере мы используем ранее определённую последовательность s как второй элемент Source. Разницы бы не было, если бы мы использовали функцию из s вместо s.

Sequence может быть расположена перед, после и внутри другой Sequence. Sequence не может быть расположена перед Source, поскольку последняя не принимает никакой входящий поток (flow).

Примечание: если мы попытаемся создать экземпляр Sequence с Source в середине, инициализация сразу же откажет и выбросит LenaTypeError (подтип TypeError из Python).

Все исключения Lena — подклассы LenaException. Они генерируются насколько можно раньше (не после того, как длительный анализ был осуществлён и отброшен).

Поскольку мы не можем использовать бесконечные ряды на практике, мы должны остановиться в какой-то точке. Мы берём первый миллион значений используя элемент ISlice. ISlice и CountFrom похожи на функции islice и count из модуля itertools стандартной библиотеки Python. ISlice может быть также инициализирован с ключевыми аргументами start, stop[, step], которые позволяют пропустить определённый начальный или конечный поднабор данных (определённый своим индексом) или взять каждое step значение (если step равен двум, то все чётные индексы начиная с нуля).

Мы применяем дальнейшие преобразования данных с помощью анонимной функции, и суммируем получившиеся значения.

В конце мы материализуем результаты в список и получаем грубое приближение числа пи.

Ленивые вычисления

Посмотрим на последний элемент предыдущей последовательности. Его класс обладает методом run, который принимает входящий поток flow:

class Sum():     def run(self, flow):         s = 0         for val in flow:             s += val         yield s

Заметим, что мы выдаём окончательное значение с помощью не return, а yield. Yield — это ключевое слово Python, которое превращает обычную функцию в генератор.

Генераторы — это реализация ленивых вычислений на Python. В самом первом примере мы использовали строку

>>> results = s.run([0, 1, 2, 3])

Метод Sequence run является генератором. Когда мы вызываем генератор, мы получаем результат, но никаких вычислений на самом деле не происходит, никакие инструкции из кода генератора не выполняются. Чтобы в действительности вычислить результаты, генератор должен быть материализован. Это может быть сделано с помощью контейнера (такого как список или кортеж) или в цикле:

>>> for res in results: ...     print(res)

Преимущества ленивых вычислений:

  • производительность. Чтение файлов данных может быть одним из самых длительных шагов в анализе данных. Поскольку ленивые вычисления используют только одно значение в данный момент, это значение может быть моментально использовано, не ожидая, когда закончится чтение всего набора данных. Это позволяет нам сделать полный анализ за практически то же время, которое бы потребовалось только для чтения входных данных.
  • малое расходование памяти. Данные сразу используются и не хранятся где-либо. Это позволяет нам анализировать наборы данных большие, чем физическая память, и делает нашу программу масштабируемой.

Ленивые вычисления очень легко реализовать на Python с помощью ключевого слова yield. Генераторы нужно внимательно отличать от обычных функций в Lena. Если объект внутри последовательности имеет метод run, то он предполагается генератором. Иначе, если объект выполняем, то предполагается, что он функция, которая делает какое-то простое преобразование входящего значения.

Генераторы могут выдавать (yield) результаты ноль или неограниченное число раз. Используйте их чтобы изменить или сократить поток (flow) данных. Используйте функции или вызываемые объекты для вычислений, которые принимают и возвращают одно значение (value).

Контекст

Целью Lena является охватить процесс анализа от начала до конца. Конечные результаты анализа — таблицы и графики, которые могут быть использованы людьми.

Lena ничего не рисует сама, а полагается на другие программы. Она использует библиотеку Jinja для обработки текстовых шаблонов. В Lena нет предопределённых шаблонов или магических констант, и пользователи должны писать свои собственные. Пример одномерного графика в LaTeX:

% histogram_1d.tex \documentclass{standalone} \usepackage{tikz} \usepackage{pgfplots} \pgfplotsset{compat=1.15}  \begin{document} \begin{tikzpicture} \begin{axis}[] \addplot [     const plot, ] table [col sep=comma, header=false] {\VAR{ output.filepath }}; \end{axis} \end{tikzpicture} \end{document}

Это обычный TikZ шаблон, за исключением одной строки: \VAR{ output.filepath }. \VAR{ var } заменяется на текущее значение var во время рендеринга. Это позволяет использовать один шаблон для разных данных, вместо того чтобы создавать много идентичных файлов на каждый график. В данном примере переменная output.filepath передаётся в контексте рендеринга.

Более сложным примером может быть следующий:

\BLOCK{ set var = variable if variable else '' } \begin{tikzpicture} \begin{axis}[     \BLOCK{ if var.latex_name }         xlabel = { $\VAR{ var.latex_name }$         \BLOCK{ if var.unit }             [$\mathrm{\VAR{ var.unit }}$]         \BLOCK{ endif }         },     \BLOCK{ endif } ] ...

Если в контексте есть variable, назовём её var для краткости. Если у неё есть latex_name и unit (размерность), то эти значения могут быть использованы для метки оси x. Например, это может стать x [m] или E [keV] на картинке. Если имя или размерность не были переданы, график будет создан без метки, но также без ошибки или падения программы.

Jinja предоставляет очень богатые возможности для программирования. Шаблоны могут устанавливать переменные, использовать условные операторы и циклы. Обращайтесь к документации Jinja² за деталями.

Чтобы использовать Jinja с LaTeX, Lena немного изменила синтаксис по умолчанию³: блоки и переменные заключены в окружения \BLOCK и \VAR соответственно.

Контекст — это обычный словарь Python или его подтип. Flow в Lena состоит из кортежей пар (data, context). Обычно он не называется dataflow, потому что в нём также есть контекст. Как было показано ранее, контекст не обязателен для последовательностей Lena. Однако он значительно упрощает создание графиков и обеспечивает дополнительную к основным данным информацию. Чтобы добавить контекст в поток, просто передайте его вместе с данными как в следующем примере:

class ReadData():     """Read data from CSV files."""      def run(self, flow):         """Read filenames from flow and yield vectors.          If vector component could not be cast to float,         *ValueError* is raised.         """         for filename in flow:             with open(filename, "r") as fil:                 for line in fil:                     vec = [float(coord)                            for coord in line.split(',')]                     # (data, context) pair                     yield (vec, {"data": {"filename": filename}})

Мы читаем имена файлов из входящего flow и генерируем векторы координат. Мы добавляем имена файлов во вложенный словарь data (произвольно названный). На filename можно ссылаться в шаблоне как на data["filename"] или просто data.filename.

Рендеринг шаблонов широко используется в хорошо разработанной области веб-программирования, и разница между рендерингом HTML страницы или LaTeX файла, как и любого другого текстового файла, мала. Несмотря на мощь шаблонов, хороший дизайн предполагает использование их полных возможностей лишь при необходимости. Главная задача шаблонов — создание графиков, в то время как какие-либо нетривиальные вычисления должны содержаться в самих данных (и передаваться через контекст).

Контекст делает возможным отделение данных от презентации в Lena. Это считается хорошей практикой в программировании, потому что заставляет части программы фокусироваться на своих основных задачах и предотвращает повторение кода.

Поскольку весь поток данных передаётся внутри последовательностей фреймворка, контекст также необходим, когда требуется передать дополнительные данные в последующие элементы. Разные элементы обновляют контекст из потока своим собственным контекстом, который сохраняется, если его не удалят или не изменят.

Пример реального анализа

Сейчас мы готовы к настоящей обработке данных. Прочитаем данные из файла и создадим гистограмму из координат x.

Полный пример вместе с другими файлами из этого руководства можно найти в папке docs/examples/tutorial фреймворка или онлайн.

main.py

from __future__ import print_function  import os  from lena.core import Sequence, Source from lena.math import mesh from lena.output import HistToCSV, Writer, LaTeXToPDF, PDFToPNG from lena.output import MakeFilename, RenderLaTeX from lena.structures import Histogram  from read_data import ReadData  def main():     data_file = os.path.join("..", "data", "normal_3d.csv")     s = Sequence(         ReadData(),         lambda dt: (dt[0][0], dt[1]),         Histogram(mesh((-10, 10), 10)),         HistToCSV(),         MakeFilename("x"),         Writer("output"),         RenderLaTeX("histogram_1d.tex"),         Writer("output"),         LaTeXToPDF(),         PDFToPNG(),     )     results = s.run([data_file])     print(list(results))  if __name__ == "__main__":     main()

Если мы запустим этот скрипт, то итоговые графики и промежуточные файлы будут записаны в директорию output/, а вывод терминала будет близок к следующему:

$ python main.py pdflatex -halt-on-error -interaction batchmode -output-directory output output/x.tex pdftoppm output/x.pdf output/x -png -singlefile [(‘output/x.png’, {‘output’: {‘filetype’: ‘png’}, ‘data’: {‘filename’: ‘../data/normal_3d.csv’}, ‘histogram’: {‘ranges’: [(-10, 10)], ‘dim’: 1, ‘nbins’: [10]}})]

Во время запуска элемент LaTeXToPDF вызывает pdflatex, и PDFToPNG вызывает программу pdftoppm. Команды выводятся со всеми аргументами, так что если во время рендеринга в LaTeX возникла ошибка, вы можете запустить эту команду вручную пока обрабатываемый файл output/x.tex не будет исправлен (и затем исправить шаблон).

Последняя строка вывода — это данные и контекст, результаты запуска (run) последовательности. Элементы, которые создают файлы, обычно генерируют пары (путь к файлу, контекст). В данном случае есть одно итоговое значение, в качестве части данных (первая часть пары) имеющее строку output/x.png.

Вернёмся к скрипту и посмотрим на последовательность более детально. Последовательность s пробегает один файл данных (в списке легко могли быть ещё). Поскольку наш ReadData генерирует пару (data, context), последующая lambda оставляет контекстную часть неизменной, и получает нулевой индекс каждого входящего вектора (нулевой части пары (data, context)).

Эта функция lambda не очень читаема, и мы увидим лучший и более общий подход в следующей части руководства. Но она показывает, как поток может быть перехвачен и преобразован в любой точке внутри последовательности.

Получающиеся x компоненты заполняют гистограмму Histogram, которая инициализируется с границами бинов (edges), определяемыми сеткой (mesh) от -10 до 10 с десятью бинами.

Эта гистограмма, после того как ей передали весь поток, преобразуется в текст формата CSV (значения, разделённые запятыми). Чтобы внешние программы (такие как pdflatex) могли использовать получившуюся таблицу, она должна быть записана в файл.

MakeFilename добавляет имя файла в словарь context["output"]. Context.output.filename — это имя файла без пути и расширения (последнее будет установлено другими элементами в зависимости от формата данных: сначала это таблица csv, затем она может стать рисунком pdf и т.д.). Поскольку ожидается только один файл, мы можем просто назвать его x.

Элемент Writer записывает текстовые данные в файловую систему. Он инициализируется с именем директории для записи выходных данных. Чтобы значение было записано, его контекст должен иметь подсловарь "output".

После того как мы создали таблицу csv, мы можем обработать наш шаблон LaTeX histogram_1d.tex с этой таблицей и контекстом, и преобразовать график в pdf и png. Как и ранее, RenderLaTeX создаёт текст, который должен быть записан в файловую систему перед использованием.

Поздравляем: теперь вы можете делать полный анализ используя фреймворк, от начала до окончательных графиков. В конце этой части руководства мы покажем несколько элементов Lena, которые могут быть полезны при разработке.

Элементы для разработки

Давайте используем структуру предыдущего анализа и добавим ещё несколько элементов в последовательность:

from lena.context import Context from lena.flow import Cache, End, Print  s = Sequence(     Print(),     ReadData(),     # Print(),     ISlice(1000),     lambda val: val[0][0], # data.x     Histogram(mesh((-10, 10), 10)),     Context(),     Cache("x_hist.pkl"),     # End(),     HistToCSV(),     # ... )

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

ISlice, который мы встретили ранее, когда приближали число пи, ограничивает поток до заданного числа значений. Если мы не уверены, что наш анализ уже корректен, мы можем выбрать лишь небольшой объём данных, чтобы это проверить.

Context — это элемент, являющийся подклассом словаря, и он может быть использован в качестве контекста, когда нужен форматированный вывод. Если объект класса Context находится внутри последовательности, он преобразует контекстную часть потока в этот класс, который выводится с отступами (не в одну строчку, как обычный словарь). Это может помочь во время анализа человеком многих вложенных контекстов.

Cache сохраняет входящий поток или загружает его из файла. Его аргумент инициализации — имя файла, в котором будет сохранён поток. Если файл отсутствует, то Cache создаёт его, запускает предыдущие элементы, сохраняет значения из потока в файл и передаёт их дальше. Во время последующих запусков он загружает поток из файла, и никакие предыдущие элементы не выполняются. Cache использует pickle, который позволяет сериализацию и десериализацию большинства объектов Python (кроме кода функций). Если у вас есть длительное вычисление и вы хотите сохранить результаты (например, чтобы улучшить графики, находящиеся дальше в последовательности), можете использовать Cache. Если вы изменили алгоритм до Cache, просто удалите файл, чтобы он перезаполнился новым потоком.

End запускает все предыдущие элементы и останавливает анализ на этом месте. Если бы мы включили его в этом примере, Cache был бы заполнен или прочитан (как и без элемента End), но ничто не передалось бы в HistToCSV и далее. End можно использовать если точно известно, что последующий анализ не полон и потерпит неудачу.


Резюме

Lena поощряет разбиение анализа на небольшие независимые элементы, которые объединяются в последовательности. Это позволяет заменять, добавлять или удалять любой элемент или преобразовывать поток в любом месте, что может быть очень полезно при разработке. Последовательности могут быть элементами других последовательностей, что позволяет их переиспользование.

Элементы могут быть вызываемыми (callable) или генераторами. Простые вызываемые могут быть легко добавлены для преобразования каждого значения из потока, в то время как генераторы могут преобразовывать поток, добавляя в него значения или сокращая его. Генераторы позволяют делать ленивые вычисления, что снижает использование памяти и обобщает алгоритмы для использования потенциально многих значений вместо одного.

Полная информация об анализе передаётся через контекст. Ответственность пользователя — добавлять необходимый контекст и писать шаблоны графиков. Пользователь также должен предоставить начальный контекст для именования файлов и графиков, но помимо этого фреймворк передаёт и обновляет контекст самостоятельно.

Мы ввели две базовых последовательности. Sequence может помещаться до, после или внутри другой последовательности. Source похожа на Sequence, но никакая другая последовательность не может ей предшествовать.

Последовательность Инициализация Использование
Sequence Элементы с методами __call__(value) или run(flow) (или вызываемые) s.run(flow)
Source Первый элемент имеет метод __call__() (или вызываемый), другие образуют Sequence s()

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

Упражнения

  1. Иван хочет лучше узнать генераторы и реализует элемент End. Он создаёт такой класс:

    class End(object):     """Stop sequence here."""      def run(self, flow):         """Exhaust all preceding flow and stop iteration."""         for val in flow:             pass         raise StopIteration()

    и добавляет этот элемент в пример main.py выше. Когда он запускает программу, он получает

    Traceback (most recent call last): File “main.py”, line 46, in <module> main() File “main.py”, line 42, in main results = s.run([data_file]) File “lena/core/sequence.py”, line 70, in run flow = elem.run(flow) File “main.py”, line 24, in run raise StopIteration() StopIteration

    Похоже, что никакие последующие элементы, действительно, не были исполнены. Однако Иван вспоминает, что StopIteration внутри генератора должно вести к нормальному завершению и не должно быть ошибкой. Что было сделано не так?

  2. Светлана хочет убедиться, что никакая инструкция действительно не исполняется во время вызова генератора. Напишите простой генератор, чтобы это проверить.

  3. Count считает значения, проходящие через него. Для того чтобы он не менял поток данных, он должен добавлять результаты в контекст. Какие ещё решения по дизайну нужно рассмотреть? Напишите простую реализацию и проверьте, что она работает как элемент последовательности.

  4. Льву не нравится, как организован вывод в предыдущих примерах.

    "В наши объектно-ориентированные дни я мог воспользоваться только одним объектом чтобы сделать весь анализ",- говорит он. "Гистограмма в CSV, Записать, Сверстать, опять Записать,… Если наша система вывода остаётся той же, и нам надо повторять то же самое в каждом скрипте, то это code bloat (раздувание кода)."

    Как сделать только один элемент для всего процесса вывода? Какие преимущества и недостатки этих двух подходов?

  5. ** Вспомним реализацию Sum ранее. Предположим, вам нужно разделить поток на два и провести два анализа, так чтобы вам не нужно было считывать поток несколько раз или хранить его целиком в памяти.

    Позволит ли Sum сделать это, почему? Как она должна быть изменена? Эти вопросы будут отвечены в следующей части руководства.

Ответы на упражнения даны в конце руководства (https://lena.readthedocs.io/en/latest/tutorial/answers.html).

Сноски

1. Эта возможность может быть добавлена в будущем.
2. Документация Jinja: https://jinja.palletsprojects.com/
3. Использование Jinja для вёрстки LaTeX было предложено здесь и здесь, синтаксис шаблонов был взят из оригинальной статьи.

Альтернативы

Ruffus — вычислительный конвейер (computational pipeline) для Python, используемый в науке и биоинформатике. Он соединяет компоненты программы через запись и чтение файлов.

ссылка на оригинал статьи https://habr.com/ru/post/490518/