Google анонсировала новый язык программирования Logica.

МЕНЮ


Главная страница
Поиск
Регистрация на сайте
Помощь проекту
Архив новостей

ТЕМЫ


Новости ИИРазработка ИИВнедрение ИИРабота разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика

Авторизация



RSS


RSS новости


Учебник по Logica

Logica-это язык семейства Datalog, который может быть скомпилирован в StandardSQL. В большей части своего синтаксиса Logica следует Yedalog, языку, разработанному ранее в Google. Logica создана для того, чтобы одновременно наслаждаться краткой ясностью логического программирования и полной мощью SQL-систем, таких как BigQuery.

Logica семантически эквивалентна StandardSQL. Легко писать и, самое главное, читать средние и большие запросы, написанные на Logica. Эти запросы могут быть скомпилированы в StandardSQL и запущены на BigQuery.

**Зачем изучать Логику?**

Изучение нового языка-это инвестиция.
Logica приносит **читабельность и хорошие инженерные практики** общие для таких языков, как Python, C++, Java и т. Д. на ваши вопросы.
Как только вы изучите Логику, вы сможете легко сделать следующее**:

1. **Читайте** ваши запросы, а не просто пишите их! Даже если вы написали его давным-давно, вы сможете читать и вспоминать логику очень быстро.

2. **Повторное использование** подзапросов. Определение и повторное использование функций.

3. **Проверьте** ваши запросы.

4. Интеграция **CoLab** позволяет запускать один или несколько (потенциально взаимозависимых ) запросов и заполняет переменные Python результатами. Этот подход позволяет вам кратко выразить свою логику накопления данных в Logica и сосредоточить свой код Python на том, что Python делает лучше всего (визуализация, анализ временных рядов, машинное обучение и т. Д)

5. **Наслаждайтесь** написанием запросов. По вышеприведенным причинам Logica гораздо интереснее SQL!

В C, Python, C++, Java и т. Д. основным строительным блоком вашей программы является функция.

В SQL общий строительный блок в _query_.

В Логике основным строительным блоком является _предикат_.

**Определение**: Предикат-это оператор, содержащий переменные.

Предикат-это очень общее понятие. Функции и запросы (а также таблицы) можно рассматривать как особые виды предикатов.

!

Таким образом, Logica может легко выражать логику SQL-запросов. Logica также может выражать вычислительные инструкции, определяя функции и вспомогательные переменные, аналогичные таким языкам, как C++ и Python.

Синтаксис Logica аналогичен теории множеств и логической нотации, используемой в математике. Рассмотрим определение множества четных чисел:

$$EvenNumbers = {x | x in mathbb{Z} wedge  x / 2 in mathbb{Z} }$$

Утверждение формальной логики какое число четное:

$$x in mathbb{Z} wedge  x / 2 in mathbb{Z} vdash Even(x) $$

If $Z$ is a predicate corresponding to the set $mathbb{Z}$ then we could write

$$Z(x) wedge Z(x /2) vdash Even(x) $$

Правило Logica, определяющее Четный предикат из предиката Z, выглядит следующим образом.

```

Even(x) :- Z(x), Z(x / 2);

```

В отличие от математики в Логике нам приходится беспокоиться о вычислимости, поэтому мы не можем легко определить предикат как подмножество всех целых чисел. Но мы можем легко определить Даже предикат, определенный для подмножества положительных целых чисел от 0 до 20.

Сначала нам нужно установить и импортировать Logica в этот CoLab.
Установите Logica.!pip install logica Import Logica.из google.colab import authfrom logica import colab_logicaauth.authenticate_user()colab_logica.SetProject('YOUR_PROJECT')

Теперь мы можем определить Четный предикат.

%%logica Even

Z(x) :- x in Range(20);

Even(x) :- Z(x), Z(x / 2);

В CoLab любой вычисляемый предикат может быть доступен из Python через переменную dataframe с тем же именем.

print('Even numbers:', ', '.join(map(str, Even['col0'])))

Вы можете **создать копию этого учебника** и настроить запросы. Запросы выполняются мгновенно через BigQuery

## Facts (aka Tables)

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

%%logica Employee

Employee(name: "Alice", role: "Product Manager");
Employee(name: "Bob", role: "Engineer");
Employee(name: "Caroline", role: "Engineer");
Employee(name: "David", role: "Data Scientist");
Employee(name: "Eve", role: "Data Scientist");

## Rules (aka Queries)

Правила определяют новые предикаты из существующих. Строительные блоки-предикаты-это таблицы, определенные в Logica (см. Выше), или существующие таблицы BigQuery, которые можно использовать непосредственно (см. Пример ниже).

### Expressions

Вы можете использовать базовые операторы, как и в большинстве популярных лагов. Конкатенация строк выполняется с помощью `++`.

%%logica Test

Test(a: 1, b: 2, c: "universe");
Test(a: 1 + 2, b: 2 * (2 + 1), c: "hello" ++ " " ++ "world");

### Structures

You can define structures via syntax that is similar to json and textproto.

%%logica StructureTest

StructureTest(a: {x: 1, y: 2, z: { w: "hello", v: "world"}});
StructureTest(a: {x: 3, y: 4, z: { w: "bonjour", v: "monde"}});

print(StructureTest['a'].values[0]['z']['w'])

### Variables

Вы можете определить структуры с помощью синтаксиса, аналогичного json и textproto.

%%logica Test

Test(y: value) :-
  value == x * x + 2 * x + 5,
  x == 10;

Существует несколько синтаксических соглашений, касающихся имен полей.

Если значение поля опущено, то предполагается, что значение поля-это переменная с тем же именем, что и имя поля.

Если имя поля опущено, то предполагается, что имя поля равно colX, где X-это позиция, в которой находится поле.

%%logica Test1, Test2

Test1(x:, y:) :-
  y == x * x + 2 * x + 5,
  x == 10;

Test2(x, 10 * x) :- x == 5;

### Базовое извлечение и фильтрация данных

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

%%logica EmployeeName, Engineer, EngineersAndProductManagers

Employee(name: "Alice", role: "Product Manager");
Employee(name: "Bob", role: "Engineer");
Employee(name: "Caroline", role: "Engineer");
Employee(name: "David", role: "Data Scientist");
Employee(name: "Eve", role: "Data Scientist");

EmployeeName(name:) :- Employee(name:);

Engineer(name:) :- Employee(name:, role: "Engineer");

EngineersAndProductManagers(name:) :-
  Employee(name:, role:),
  role == "Engineer" || role == "Product Manager";

Выражение `..<имя переменной>` используется для извлечения или выделения целой строки таблицы в виде одной записи.

%%logica Engineers

Employee(name: "Alice", role: "Product Manager");
Employee(name: "Bob", role: "Engineer");
Employee(name: "Caroline", role: "Engineer");
Employee(name: "David", role: "Data Scientist");
Employee(name: "Eve", role: "Data Scientist");

Engineers(..r) :- Employee(..r), r.role == "Engineer";

### Соединение (aka Join)

Чтобы объединить несколько таблиц, просто перечислите таблицы в теле и соедините столбцы с помощью того же имени или с помощью `==`.

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

%%logica EmployeeLocation

Employee(name: "Alice", role: "Product Manager", office: "SEA");
Employee(name: "Bob", role: "Engineer", office: "SEA");
Employee(name: "Caroline", role: "Engineer", office: "LAX");
Employee(name: "David", role: "Data Scientist", office: "LAX");
Employee(name: "Eve", role: "Data Scientist", office: "SEA");

OfficeLocation(office: "SEA", city: "Seattle");
OfficeLocation(office: "LAX", city: "Los Angeles");

Role(name: "PM", area: "Product");
Role(name: "Eng", area: "Software");
Role(name: "AMT", area: "Statitics");

EmployeeLocation(employee: name, city:) :-
  Employee(name:, office:),
  OfficeLocation(office:, city:);

### Дизъюнкция (она же Союз)

Символ `|` обозначает дизъюнкцию.

%%logica WritesCode

Employee(name: "Alice", role: "Product Manager", office: "SEA");
Employee(name: "Bob", role: "Engineer", office: "SEA");
Employee(name: "Caroline", role: "Engineer", office: "LAX");
Employee(name: "David", role: "Data Scientist", office: "LAX");
Employee(name: "Eve", role: "Data Scientist", office: "SEA");

# Инженеры и специалисты по обработке данных пишут код.
WritesCode(name:) :-
  Employee(name:, role: "Engineer") |
  Employee(name:, role: "Data Scientist");

### Отрицание

Отрицание предиката обозначается"~`, в то время как"! " используется для отрицания логического значения.

%%logica OutsideOfCalifornia

Employee(name: "Alice", role: "Product Manager", office: "SEA");
Employee(name: "Bob", role: "Engineer", office: "SEA");
Employee(name: "Caroline", role: "Engineer", office: "LAX");
Employee(name: "David", role: "Data Scientist", office: "LAX");
Employee(name: "Eve", role: "Data Scientist", office: "SEA");

InCalifornia(name:) :- Employee(name:, office:), office == "LAX";

OutsideOfCalifornia(name:) :- Employee(name:), ~InCalifornia(name:);

### Агрегация

Чтобы запустить агрегацию, вы используете ключевое слово " distinct` в заголовке правила. Агрегированное поле использует

```
<имя поля>? <aggregation_function>= <вход агрегации>

```
синтаксис. Keywork `distinct` должен использоваться для запуска агрегации (хотя есть одно исключение, см. раздел "Функции").

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

%%logica ByRoleCount

Employee(name: "Alice", role: "Product Manager", office: "SEA");
Employee(name: "Bob", role: "Engineer", office: "SEA");
Employee(name: "Caroline", role: "Engineer", office: "LAX");
Employee(name: "David", role: "Data Scientist", office: "LAX");
Employee(name: "Eve", role: "Data Scientist", office: "SEA");

ByRoleCount(role:, count? += 1) distinct :- Employee(role:);

Если агрегированные столбцы не заданы, то ключевое слово " distinct` естественным образом приводит к тому, что предикат становится списком
различных строк.

Logica реализует собственные агрегаторы `+`, `List`, `Set` и `Count`. Вы также можете вызвать любую агрегацию StandardSQL (преобразовав ее в camelcase).

%%logica OfficeColumn,Offices,EmployeesPerOffice,EmployeesOfOffice

Employee(name: "Alice", role: "Product Manager", office: "SEA");
Employee(name: "Bob", role: "Engineer", office: "SEA");
Employee(name: "Caroline", role: "Engineer", office: "LAX");
Employee(name: "David", role: "Data Scientist", office: "LAX");
Employee(name: "Eve", role: "Data Scientist", office: "SEA");

OfficeColumn(office:) :- Employee(office:);

Offices(office:) distinct :- Employee(office:);

EmployeesPerOffice(office:,
                  num_employees? += 1,
                  role_count? Count=role) distinct :-
  Employee(name: unused_name, office:, role:);
 
EmployeesOfOffice(office:, employees? List= name) distinct :-
  Employee(name:, office:);

#### Агрегация внутри записи

Синтаксис для агрегации внутри записи таков:
```
combine <оператор агрегации>=<агрегированное значение> [ :- <тело> ]
```

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

```
<result_var> <aggregation operator>=(<aggregated value> [  :- body  ])
```

%%logica AnonymizedStas

AnonymizedCodeContribution(cl_lengths: [110, 220, 405], org: "ads");
AnonymizedCodeContribution(cl_lengths: [30, 51, 95], org: "ads");
AnonymizedCodeContribution(cl_lengths: [10, 20, 1000], org: "games");

ClSize(l) = (
  if l < 50 then
    "S"
  else if l < 100 then
    "M"
  else if l < 500 then
    "L"
  else "XL"
);

AnonymizedStas(cl_sizes:, largest_cl:) :-
  cl_sizes List= (ClSize(l) :- l in cl_lengths),
  largest_cl Max= (l :- l in cl_lengths),
  AnonymizedCodeContribution(cl_lengths:);

#### Пользовательские функции агрегации

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

%%logica OrgStats

AnonymizedCodeContribution(cl_lengths: [110, 220, 405], org: "ads");
AnonymizedCodeContribution(cl_lengths: [30, 51, 95], org: "ads");
AnonymizedCodeContribution(cl_lengths: [10, 20, 1000], org: "games");

HarmonicMean(x) = Sum(1) / Sum(1 / x);

OrgStats(
    org:,
    mean_cl_size? Avg= cl_size,
    harmonic_mean_cl_size? HarmonicMean= cl_size) distinct :-
  AnonymizedCodeContribution(cl_lengths:, org:),
  cl_size in cl_lengths;

### Inifinite предикаты

Предикаты, определенные выше всех, имели конечное число записей.

Здесь мы определяем и используем бесконечный предикат IsEngineer, который математически представляет собой набор всех возможных записей с ролью, равной "Eng".

%%logica Engineers

Employee(name: "Alice", role: "Product Manager", office: "SEA");
Employee(name: "Bob", role: "Engineer", office: "SEA");
Employee(name: "Caroline", role: "Engineer", office: "LAX");
Employee(name: "David", role: "Data Scientist", office: "LAX");
Employee(name: "Eve", role: "Data Scientist", office: "SEA");

IsEngineer(record) :- record.role == "Engineer";
 
Engineers(..r) :- Employee(..r), IsEngineer(r);

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

%%logica Description

Employee(name: "Alice", role: "Product Manager", office: "SEA");
Employee(name: "Bob", role: "Engineer", office: "SEA");
Employee(name: "Caroline", role: "Engineer", office: "LAX");
Employee(name: "David", role: "Data Scientist", office: "LAX");
Employee(name: "Eve", role: "Data Scientist", office: "SEA");

Describe(record, result) :-
  result ==
    record.name ++ " is " ++ record.role ++ " @ " ++  record.office;
 
Description(d) :- Employee(..r), Describe(r, d);

## Функции

В теории множеств функция $f$ от $A$ до $B$ является просто подмножеством декартова произведения $A imes B$, то есть $f subseteq A imes B$ с условием, что $f(x)$ обозначает $y$ так, что $(x, y) в f$.

Логика-это следующий подход. Когда вы определяете предикат с помощью синтаксиса функции

```
<some predicate>(<arguments>) = <value> [:- <body>].
```

it is interpreted exactly as

```
<some predicate>(<arguments>, logica_value: <value>) [:- <body>]
```

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

%%logica ExampleFunctionOne, ExampleFunctionTwo, Test

ExampleFunctionOne(x) = y :- x == "a", y == "b";

ExampleFunctionTwo("b", logica_value: "c");

Test("test_1", x, y) :- ExampleFunctionOne(x, logica_value: y);
Test("test_2", x, y) :- ExampleFunctionOne(x) == y;
Test("test_3", x, ExampleFunctionOne(x));
Test("test_4", x, ExampleFunctionTwo(ExampleFunctionOne(x)));

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

%%logica Test

F(x:, y:) :- y == x ^ 2 - 2 * x + 1;

Test(x:, y:) :- x in [0, 0.5, 1.0, 1.5, 2.0], F(x:, y:);

%%logica Test

F(x) = x ^ 2 - 2 * x + 1;

Test(x:, y: F(x)) :- x in [0, 0.5, 1.0, 1.5, 2.0];

### Функциональная агрегация

Вы можете вычислить значение предиката с помощью агрегации, как и с любым другим полем.
Если значение предиката агрегируется, то ключевое слово "distinct" не требуется (фактически не должно использоваться), так как уже очень ясно
, что агрегация выполняется.

%%logica EmployeesOfRole

Employee(name: "Alice", role: "Product Manager", office: "SEA");
Employee(name: "Bob", role: "Engineer", office: "SEA");
Employee(name: "Caroline", role: "Engineer", office: "LAX");
Employee(name: "David", role: "Data Scientist", office: "LAX");
Employee(name: "Eve", role: "Data Scientist", office: "SEA");

EmployeesOfRole(role) List= name :- Employee(name:, role:);

Вот еще несколько примеров функций.

%%logica EmployeeRole, ToolUsed, UsesTool, UsersOfTool

Employee(name: "Alice", role: "Product Manager", office: "SEA");
Employee(name: "Bob", role: "Engineer", office: "SEA");
Employee(name: "Caroline", role: "Engineer", office: "LAX");
Employee(name: "David", role: "Data Scientist", office: "LAX");
Employee(name: "Eve", role: "Data Scientist", office: "SEA");

RoleFullName("Product Manager") = "Product Manager";
RoleFullName("Engineer") = "Software Engineer";
RoleFullName("Data Scientist") = "Statistician";

EmployeeRole(name:, role_full_name: RoleFullName(role)) :- Employee(name:, role:);

ToolUsed("Product Manager") = "spreadsheet";
ToolUsed("Engineer") = "cloud";
ToolUsed("Engineer") = "python";
ToolUsed("Data Scientist") = "spreadsheet";
ToolUsed("Data Scientist") = "python";

UsesTool(name:, tool: ToolUsed(role)) :- Employee(name:, role:);

UsersOfTool(tool:) List= name :- UsesTool(name:, tool:);

## Пример: Популярные Детские имена

Здесь мы используем Logica, чтобы вычислить самые популярные детские имена по годам и построить график популярности этих самых популярных имен с течением времени.

%%logica BabyNamesSample,TopNameByYear,PlotNames,Graph,TotalBabies

# Основной предикат: TopNameByYear

# Подключение предиката к таблице.

BabyNames(..r) :- `bigquery-public-data.usa_names.usa_1910_current`(..r);

# Извлечение произвольной выборки из таблицы.
@Limit(BabyNamesSample, 10);
BabyNamesSample(..r) :- BabyNames(..r);  

NameCountByYear(name: , year:) += number :-
  BabyNames(name:, year:, number:);

# Поиск самого популярного имени за каждый го
@OrderBy(TopNameByYear, "year");
TopNameByYear(year) ArgMax= name -> NameCountByYear(name:, year:);

# Имена, для которых мы хотели бы построить график популярности.
PlotNames(name: TopNameByYear()) distinct;

# Получить график популярности для топ-имен.
@OrderBy(Graph, "name", "year");
Graph(name:, year:, count: NameCountByYear(name:, year:)) :-
  PlotNames(name:);

# Взгляните на общее количество младенцев времени.
@OrderBy(TotalBabies, "year");
TotalBabies(year:) += number :- BabyNames(year:, number:);

from matplotlib import pyplot

pyplot.figure(figsize=(10,5))
for name in PlotNames['name']:
  g = Graph[Graph['name'] == name]
  pyplot.plot(g['year'], g['count'], label=name)

_ = pyplot.legend(loc='best')

pyplot.figure(figsize=(10,5))
_ = pyplot.plot(TotalBabies['year'],
                TotalBabies['logica_value'],
                label='Total babies')
_ = pyplot.legend(loc='best')

## ПРИЛОЖЕНИЕ

### Присвоение и равенство

Необычно, что мы используем один и тот же оператор " = = ` как для присваивания, так и для сравнения.

Это происходит потому, что в Логике то, что означает"==`, определяется из контекста.

Рассмотрим простую игрушечную таблицу T и определенный дублет предикатов.

%%logica T, DoubleT

T(1, "apple");
T(2, "banana");
T(3, "orange");

DoubleT(d, y) :- T(x, y), d == 2 * x;

Здесь оказывается, что мы **присваиваем переменной $d$ значение $2 * x$.

Но теперь рассмотрим следующее использование:

%%logica MyFruit

T(1, "apple");
T(2, "banana");
T(3, "orange");

DoubleT(d, y) :- T(x, y), d == 2 * x;

MyFruit(f) :- DoubleT(6, f);

Здесь, когда запрашивается "myFruit", выражение `d == 2 * x " оказывается условием фильтрации строк T.

Таким образом, нет четкой разницы между равенством и присваиванием, и они не дифференцируются в синтаксисе.


Источник: colab.research.google.com

Комментарии: