Microsoft Solver Foundation — что это такое?

    Solver Foundation

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

На сегодняшний момент Solver Foundation обладает следующими ключевыми возможностями:

  • моделирование и решение сценариев с помощью ограничений, целей и данных;
  • разработка на языке Optimization Modeling Language (OML), императивно в C#, функционально в F# или на любом другом языке .NET;
  • встроенные решатели задач для наиболее распространенных типов моделей;
  • интеграция с популярными инструментами Microsoft Office Excel и SharePoint для создания и решения моделей.

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

    Пример MS Excel

Рассмотрим небольшой пример, который будет воспроизводится в MS Excel, для которого предварительно был установлен Solver Foundation Add-In. После установки появится дополнительная вкладка. Стоит отметить, что в Excel есть собственный Solver, но в данном случае интерес представляет внешняя библиотека.

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

Далее добавим еще две небольших таблицы.

Первая описывает количество, которое может быть отправлено и общую вместимость.

Вторая описывает количество, принятое и затребованное количество.

    Настройки модели

Теперь требуется посчитать общую минимально возможную стоимость затрат, для выполнения поставки затребованного количества. Для этого воспользуемся возможностями Solver Foundation. Для того, чтобы получить решение, прежде необходимо построить модель. Модель состоит из наборов, параметров, ограничений и целей. Модель пишется на языке OML. В текущем примере, упростим задачу и воспользуемся интерфейсом, который предоставляет Add-in. Для этого на панели «Solver Foundation» воспользуемся кнопкой «Model». Откроется боковая панель.

В ней есть все необходимое для решения задачи.

Для начала добавим в модель наборы. Раз существуют отправитель и получатель в примере, то набора будет два, как на рисунке ниже.

В свойствах набора изменяем только поле «Name». Также можно задать значения, которые будет содержать набор. Но в данном случае оставим настройки по умолчанию и будем использовать наши таблицы.

Далее, добавим параметры. Для этого перейдем на вкладку «Parameters». Добавим новый параметр, указав имя «COST» и настроив привязку к данным в столбце «COST». Для этого необходимо указать диапазон, где находится наша таблица с данными. И после этого выбрать из выпадающих списков необходимые значения.

Аналогично добавляем 2 параметра, «CAPACITY» и «DEMAND». Только для них указываем соответсвенно диапазоны 2-х небольших таблиц, в которых указана информация о вместимости и затребованном количестве.

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

Настраиваем цель. Переходим на вкладку «Goals». Целью будет являться минимальная сумма затрат на поставки.

Для этого находим суммы всех направлений. Выражение в развернутом виде выглядит так:

for (i = 0; i < N; i++)

{

for (j=0; j < M; j++)

{

TOTALCOST += COST[i, j] x SHIPMENTS[i, j];

}

}

Переходим к настройке ограничений. Переходим на закладку «Constraints». Добавим первое ограничение «SENTCAPACITY». В выражении опишем цикл, который контролирует, чтобы поставка в сумме не превышала вместимость приемника.

Добавим еще одно ограничение «RECEIVEDDEMAND». В выражении опишем цикл, который контролирует, чтобы поставка в сумме была не меньше затребованного количества.

    Запуск расчета

Настройка модели на этом закончена. Можно запускать расчет решения. Но перед этим можно увидеть описание модели на языке OML. Для этого необходимо перейти на вкладку «Model».

Для запуска расчета по модели, необходимо на панели «Solver foundation» нажать кнопку «Solver». На вкладке «Log» можно отслеживать ход процесса.

После расчета получили следующие результаты. В результатах расчета видна общая сумма затрат, направления и количества по ним. Результаты расчета отличаются от плановых поставок.

    Dynamics AX 2012

Конфигуратор продукции – это новое решения конфигуратора, использующего движок Solver Foundation. Это решение появилось в Dynamics AX 2012.

В Dynamics AX 2012 новый «Конфигуратор продукции» заменил старый, который использовался в предыдущих версиях Ax. Далее будет сделан акцент на том, как создать базу правил или базу ограничений для конкретного бизнес-сценария, чтобы обеспечить выбор правильной комбинации значений переменных моделирования в новом конфигураторе продукции.

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

Модель конфигурации:

Имя переменной моделирования Значения
Type (Тип) «Sport Car», «Family Car»
Package (Пакет опций) «Deluxe», «Luxury», «Standard»
Frame (Кузов) «Convertible», «Hatchback», «Sedan»
Engine (Двигатель) «A», «B»
Transmission (Коробка передач) «Manual», «HalfAutomatic», «Automatic»

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

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

Правило 1: IF Package = «Deluxe» AND Frame = «Convertible» THEN Engine = «A»

Правило 2: IF Package = «Deluxe» AND Frame = «Hatchback» THEN Engine = «B»

Правило 3: IF Package = «Standard» AND Frame = «Convertible» THEN Engine = «A»

Правило 4: IF Engine = «A» THEN Transmission = «Manual»

Правило 5: IF Engine = «B» THEN Transmission = «Automatic»

Правило 6: IF Type = «Sport Car» THEN Frame = «Convertible»

Правило 7: IF Type = «Family Car» THEN Frame = «Sedan»

Правило 8: IF Type = «Sport Car» THEN Transmission = «Manual»

Правила 1, 2 и 3 используют тип автомобиля и кузов, чтобы определить, какой двигатель доступен. Правила 4 и 5 определяют коробку передач, в зависимости от двигателя. Правила 6 и 7 решают какой доступен кузов, если выбран тип автомобиля. Правило 8 используется для определения коробки передач, если был выбран тип автомобиля.

    Настройки модели

Далее необходимо создать модель для конфигуратора AX 2012 и перенести эти правила в модель. Для этого нужно определить атрибуты и типы атрибутов.

Типы атрибутов:

Имя типа атрибута Тип данных Фиксированные значения
CarType Text «Sport Car», «Family Car»
CarPackage Text «Deluxe», «Luxury», «Standard»
CarFrame Text «Convertible», «Hatchback», «Sedan»
CarEngine Text «A», «B»
CarTransmission Text «Manual», «HalfAutomatic», «Automatic»

Тип атрибута = «CarType»

Тип атрибута = «CarPackage»

Тип атрибута = «CarFrame»

Тип атрибута = «CarEngine»

Тип атрибута = «CarTransmission»

    

Все типы атрибутов созданы. Далее создаем модель и настраиваем в ней атрибуты.

    Что такое стратегия решателя?

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

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

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

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

Поэтому при создании новой модели стоит уделить внимание выбору стратегии решателя. Для этого на форме создания модели существует поле «Стратегия решателя» (Solver Strategy).

    Виды стратегий

  1. По умолчанию (Default) – используется, когда для принятия решения требуется использования множества табличных ограничений.
  2. Сверху вниз (Top down) – требуется много вычислений, мало или отсутствуют ограничения таблиц. Появилась с выходом обновления Ax2012 CU8.
  3. Сначала минимальные значения (Minimal domain first) – по сути дублирует стратегию «Сверху вниз». Оставлен для поддержки обратной совместимости.
  4. Z3 – стратегия была внедрена летом 2018 года в D365, также вышли обновления для Ax2012. Это рекомендованная Microsoft стратегия, как используемая по умолчанию. Базируется на Z3 Solver — доказатель теорем Microsoft Research, который получил несколько наград и имеет активное сообщество разработчиков открытого кода. Стратегия повышает производительность принятия решений.

Первые 3 стратегии используют Solver Foundation для принятия решений. Стратегия Z3 уже использует Z3 Solver.

Добавляем в модель атрибуты, на основе созданных типах атрибутов.

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

    Подходы к реализации

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

    Вариант 1. Подход на основе правил

Ранее были описаны 8 правил, по которым существует возможность сконфигурировать автомобиль. Теперь необходимо перенести их в модель конфигурации. Для этого на вкладке «Ограничения» («Constraints») добавим строки с выражениями, которые будут содержать наши правила.

Rule 1: IF Package = «Deluxe» AND Frame = «Convertible» THEN Engine = «A»

Rule 2: IF Package = «Deluxe» AND Frame = «Hatchback» THEN Engine = «B»

Rule 3: IF Package = «Standard» AND Frame = «Convertible» THEN Engine = «A»

Rule 4: IF Engine = «A» THEN Transmission = «Manual»

Rule 5: IF Engine = «B» THEN Transmission = «Automatic»

Rule 6: IF Type = «Sport Car» THEN Frame = «Convertible»

Rule 7: IF Type = «Family Car» THEN Frame = «Sedan»

Rule 8: IF Type = «Sport Car» THEN Transmission = «Manual»

Получили список ограничений на основе правил.

Теперь, если произвести тестирование модели, то увидим следующий результат.

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

Тип автомобиля Пакет опций Кузов Двигатель Коробка передач

Исключения составляют «Кузов» = «Hatchback» и «Коробка передач» = «Half-automatic», которые были отфильтрованы из-за отсутствия соответствующих правил.

Однако, когда если указать предпочтение клиента «Sport Car» и «Deluxe», система автоматически отфильтрует все несоответствующие варианты, и конечный результат будет выглядеть следующим образом.

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

Тип автомобиля Пакет опций Кузов Двигатель Коробка передач

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

Также обратим внимание, что при использовании подхода, основанного на правилах, система реализует принцип вычета на основе существующих правил. Например, если указать «Коробка передач» = «Manual», система будет знать, что «Двигатель» = «А» на основании правила 4. И наоборот, если указать «Двигатель» = «А», система будет знать, что «Коробка передач» = «Manual» на основании правила 4.

    Вариант 2. Подход на основе ограничений

Чтобы использовать подход, основанный на ограничениях, требуется представлять правила по-разному, группируя их в 4 группы. Правила 1, 2 и 3 попадут в 1-ю группу, которая представляет все действительные комбинации «Пакет опций», «Кузов», «Двигатель». Правила 4 и 5 образуют 2-ю группу, которая представляет все действительные комбинации «Двигатель» и «Коробка передач». Правила 6 и 7 будут основой для 3-й группы, которая представляет все действительные комбинации «Тип автомобиля» и «Кузов». И Правило 8 будет представлять 4-ую группу с единственной действительной комбинацией «Тип автомобиля» и «Коробка передач», определенной на данный момент.

Группа 1.

Пакет опций Кузов Двигатель
Deluxe Convertible A
Deluxe Hatchback B
Standard Convertible A

Группа 2.

Двигатель Коробка передач
A Manual
B Automatic

Группа 3.

Тип автомобиля Кузов
Sport Car Convertible
Family Car Sedan

Группа 4.

Тип автомобиля Коробка передач
Sport Car Manual

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

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

Настраиваем группу PackageFrameEngine.

Настраиваем таким же способом остальные таблицы ограничений, на основании таблиц отношений, представленных выше.

После чего, добавляем настроенные таблицы ограничений в модель.

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

    

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

Далее проверяем модель, запускаем тестирование.

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

{Тип автомобиля = ‘Sport Car’, Пакет опций = ‘Deluxe’, Кузов = ‘Convertible’, Двигатель = ‘A’, Коробка передач = ‘Manual’}

и

{Тип автомобиля = ‘Sport Car’, Пакет опций = ‘Standard’, Кузов = ‘Convertible ‘, Двигатель = ‘A’, Коробка передач = ‘Manual’}.

Тип автомобиля Пакет опций Кузов Двигатель Коробка передач

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

Каждая группа представляет допустимые комбинации переменных моделирования. Также, определенные переменные моделирования используются несколько раз в разных группах, что означает, что можно уменьшить количество групп, объединив их вместе и убедившись, что выбор «общих» переменных моделирования в разных группах будет таким же. Объединим 1 и 2 группы по общей переменной моделирования «Двигатель».

Группа 1-2.

Пакет опций Кузов Двигатель Коробка передач
Deluxe Convertible A Manual
Deluxe Hatchback B Automatic
Standard Convertible A Manual

Далее объединим группу 1-2 с группой 3 по переменной «Кузов».

Группа 1-2-3.

Пакет опций Кузов Двигатель Коробка передач Тип автомобиля
Deluxe Convertible A Manual Sport Car
Standard Convertible A Manual Sport Car

Далее объединим группу 1-2-3 с группой 4 по переменной «Коробке передач».

Группа 1-2-3-4.

Пакет опций Кузов Двигатель Коробка передач Тип автомобиля
Deluxe Convertible A Manual Sport Car
Standard Convertible A Manual Sport Car

Группа 1-2-3-4 содержит все допустимые комбинации при текущих настроенных ограничениях.

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

    Использование конфигуратора продукции как Сервис

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

Для примера необходимо будет создать простую модель. Для модели необходимо будет настроить два атрибута «A» и «В». Каждый атрибут будет содержать два значения 0 и 1. Добавим в модель правило: Implies[A == 1, B == 0]. Правило гласит, что если А = 1, то B доступно значени 0 и наоборот.

Экспортируем модель и посмотрим ее структуру.

<Export Version="1">
    <AttributeTypes>
        <EcoResAttributeType Name="TestInt" DataType="4" IsEnumeration="0" HasBounds="1">
            <EcoResBoundedAttributeTypeValue Lower="0" Upper="1" />
        </EcoResAttributeType>
    </AttributeTypes>
    <TableConstraintDefintions />
    <Components>
        <PCClass Name="Test" ReuseEnabled="0">
            <EcoResCategoryTranslation FriendlyName="Test" Description="" LanguageId="en-us" />
            <EcoResAttribute Name="A" SolverName="A" AttributeType="TestInt" IncludeInReuse="0">
                <EcoResAttributeTranslation FriendlyName="A" Description="A" Language="en-us" />
            </EcoResAttribute>
            <EcoResAttribute Name="B" SolverName="B" AttributeType="TestInt" IncludeInReuse="0">
                <EcoResAttributeTranslation FriendlyName="B" Description="B" Language="en-us" />
            </EcoResAttribute>
            <PCComponentConstraint Name="AB" Description="AB">
                <PCExpressionConstraint Expression="Implies[ A == 1, B == 0]" />
            </PCComponentConstraint>
        </PCClass>
    </Components>
    <PCProductConfigurationModel Name="Test" RootComponentClass="Test" SolverStrategy="0">
        <PCProductConfigurationModelTranslation Name="Test" Description="Test" Language="en-us" />
        <PCConfigurationControl>
            <PCComponentControl UIOrder="1" />
        </PCConfigurationControl>
    </PCProductConfigurationModel>
</Export>

Если запустить конфигурацию, будет составлена ​​модель времени выполнения, которая выглядит следующим образом:

<Model name="Test"><Component name="Test" componentId="52565427706" instanceId="1"><Attribute name="A" displayName="A" uniqueId="11290926482" instanceId="2" type="integer"><IntegerDomain from="0" to="1" /></Attribute><Attribute name="B" displayName="B" uniqueId="11290926483" instanceId="3" type="integer"><IntegerDomain from="0" to="1" /></Attribute><Constraint constraintId="AB" uniqueId="11290924754" constraintText="Implies[ A == 1, B == 0]" /></Component></Model>

Изменять значения переменных, будем в рамках сеанса конфигурации. Обратим внимание, что будут выбраны некоторые значения переменных (UserSelected), но некоторые значения переменных будут устанавливаться системой автоматически на основе имеющихся ограничений (isUserSelected = 0/1).

<Session><Component name="Alex" uniqueId=""><Attribute name="A" uniqueId="11290926482" isUserSelected="1" type="integer" value="1" /></Component></Session>

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

<Session><Component name="Alex" uniqueId=""><Attribute name="A" uniqueId="11290926482" isUserSelected="1" type="integer" value="1" /><Attribute name="B" uniqueId="11290926483" isUserSelected="0" type="integer" value="0" /></Component></Session>

    Пример

static void PCSolveModelJob(Args _args)
{
    InteropPermission interopPermission;
    Microsoft.Dynamics.Ax.Frameworks.Controls.ProductConfiguration.ProductConfigurationServer serverSolver;

    str     modelXml = "<Model name=\"Test\"><Component name=\"Test\" componentId=\"52565427706\" instanceId=\"1\"><Attribute name=\"A\" displayName=\"A\" uniqueId=\"11290926482\" instanceId=\"2\" type=\"integer\"><IntegerDomain from=\"0\" to=\"1\" /></Attribute><Attribute name=\"B\" displayName=\"B\" uniqueId=\"11290926483\" instanceId=\"3\" type=\"integer\"><IntegerDomain from=\"0\" to=\"1\" /></Attribute><Constraint constraintId=\"AB\" uniqueId=\"11290924754\" constraintText=\"Implies[ A == 1, B == 0]\" /></Component></Model>";
    boolean isFinished;
    str     boundValues;

    str     userSelectedValues_good = "<Session><Component name=\"Test\" uniqueId=\"\"><Attribute name=\"A\" uniqueId=\"11290926482\" isUserSelected=\"1\" type=\"integer\" value=\"1\" /></Component></Session>";

    str     userSelectedValues_bad = "<Session><Component name=\"Test\" uniqueId=\"\"><Attribute name=\"A\" uniqueId=\"11290926482\" isUserSelected=\"1\" type=\"integer\" value=\"1\" /><Attribute name=\"B\" uniqueId=\"11290926483\" isUserSelected=\"1\" type=\"integer\" value=\"1\" /></Component></Session>";

    str     userSelectedValues_okay = "<Session><Component name=\"Test\" uniqueId=\"\"><Attribute name=\"A\" uniqueId=\"11290926482\" isUserSelected=\"1\" type=\"integer\" value=\"0\" /></Component></Session>";

    PCExecuteVariantConfiguration executeVariantConfiguration = PCExecuteVariantConfiguration::construct();
    PCConfigurationState          configurationState          = PCConfigurationState::construct();

    interopPermission = new InteropPermission(InteropKind::ClrInterop);
    interopPermission.assert();

    //bp deviation documented
    serverSolver = new Microsoft.Dynamics.Ax.Frameworks.Controls.ProductConfiguration.ProductConfigurationServer(modelXml);
    serverSolver.set_UserSelectedValues(userSelectedValues_good);

    isFinished = serverSolver.Solve();

    if (isFinished)
    {
        info("Feasible solution");
        boundValues = serverSolver.get_BoundValues();

        info(boundValues);
    }
    else
    {
        info("Infeasible solution");
    }
    CodeAccessPermission::revertAssert();
}

В приведенном выше коде использованы все структуры данных, описанные в начале. Также настроены 3 типа UserSelectedValues ​​для имитации различных результатов после решения: возможная полная модель, недопустимая модель и возможная неполная модель. Давайте рассмотрим эти промежуточные результаты.

Пример 1. UserSelectedValues_good

Входные данные:

<Session><Component name=\"Test\" uniqueId=\"\"><Attribute name=\"A\" uniqueId=\"11290926482\" isUserSelected=\"1\" type=\"integer\" value=\"1\" /></Component></Session>

Результат:

<Session><Component name="Alex" uniqueId=""><Attribute name="A" uniqueId="11290926482" isUserSelected="1" type="integer" value="1" /><Attribute name="B" uniqueId="11290926483" isUserSelected="0" type="integer" value="0" /></Component></Session>

 

Пример 2. UserSelectedValues_okay

Входные данные:

<Session><Component name=\"Test\" uniqueId=\"\"><Attribute name=\"A\" uniqueId=\"11290926482\" isUserSelected=\"1\" type=\"integer\" value=\"0\" /></Component></Session>

Результат:

<Session><Component name="Alex" uniqueId=""><Attribute name="A" uniqueId="11290926482" isUserSelected="1" type="integer" value="0" /></Component></Session>


Пример 3. UserSelectedValues_bad

Входные данные:

<Session><Component name=\"Test\" uniqueId=\"\"><Attribute name=\"A\" uniqueId=\"11290926482\" isUserSelected=\"1\" type=\"integer\" value=\"1\" /><Attribute name=\"B\" uniqueId=\"11290926483\" isUserSelected=\"1\" type=\"integer\" value=\"1\" /></Component></Session>

Результат:

Результата не будет, т.к. существует ограничение, которое не позволяет задавать 1 для обоих параметров.

 

На данном примере достаточно просто организовать сервис. Для этого нужно создать класс-контракт и класс-сервис. Контракт будет состоять из 2-х параметров: А и В. Сервисный класс будет принимать контракт, формировать входные данные на основании параметров контракта и запускать поиск решения.

 

habr.com

ax2012solveroptimization.blogspot.com

blogs.msdn.microsoft.com

smart-talks.org

docs.microsoft.com

community.dynamics.com

Comments

So empty here ... leave a comment!

Добавить комментарий

Sidebar