Quickstart#

Logic#

The fundamental of the logic package is logic models. This is how you create a logic proposition

import puan.logic.plog as pl

# Whenever a string x is passed as a proposition,
# it will default into a puan.variable(id=x, bounds=(0,1)).
model = pl.Any("x","y",variable="A")

Propositions can also be created from JSON or tuple. See the API reference for details on the formats. A proposition can also be converted to those formats.

Linear algebra#

Polyhedron is the most central object in this part of Puan. It’s a numpy.ndarray subclass and represents a collection of linear equations forming a polyhedron. This is how you create a polyhedron representing the linear inequality \(x + y + z \ge 2\)

import numpy as np
import puan.ndarray as nd
ph = nd.ge_polyhedron(np.array([[2, 1, 1, 1]]), ["#b", "x", "y", "z"])

Configurator#

The puan.modules.configurator.StingyConfigurator collects and combines the neccessary tools from the logic and linear algebra packages to create a complete configurator. This is how you create a configurator

import puan.modules.configurator as cc
import puan.logic.plog as pg

configurator = cc.StingyConfigurator(cc.Any("x","y",variable="A"))

# View the polyhedron
configurator.ge_polyhedron.variables
configurator.ge_polyhedron
# Output :
#    variables              #b   A   x   y
#    ge_polyhedron_config([[ 1,  1,  0,  0],
#                          [ 0, -1,  1,  1]]))

# Get a solution
solutions = list(configurator.select({}))
solution_1 = solutions[0]
solution_1_variable_values = solution_1[0]
# Output
# solution_1_variable_values = {'A': 1, 'x': 1, 'y': 0}
# Each solution contains two more fields which we do not cover in this example

# Add priority to y and get a new solution
solutions = list(configurator.select({"y": 1}))
solution_2_variable_values = solutions[0][0]
# Output
# solution_2_variable_values = {'A': 1, 'x': 0, 'y': 1}
# Now we got y in the solution instead of x
# since we added the input: prio 1 to variable y (default is 0)

# If we prefer y over x we can add it to the model when creating the configurator
configurator = cc.StingyConfigurator(cc.Any("x","y", variable="A", default="y"))

# View the polyhedron
configurator.ge_polyhedron
# Output
# variables:             #b   A VAR.. x   y
# ge_polyhedron_config([[ 1,  1,  0,  0,  0],
#                       [ 0, -1,  1,  0,  1],
#                       [ 0,  0, -1,  1,  0]])
# The polyhedron has one more column than before
# which is due to a support variable handling the default
#
# Get a solution
solutions = list(configurator.select({}))
solution_3_variable_values = solutions[0][0]
# Output solution_3_variable_values =
#    {'A': 1,
#     'VARa94110f0d8bb5f16ce1239c8b4163962481545c104501daff7907979dff35024': 0,
#     'x': 0,
#     'y': 1}
# Here we see the support variable in the solution as well, id 'VARa94110...'
# To omit support variables in the output, set only_leafs to true
solutions = list(configurator.select({}, only_leafs=True))
solution_4_variable_values = solutions[0][0]
# Output: [{'x': 0, 'y': 1}]
# This option also filters out variable A since it is dependent on x and y.
# This makes it a support variable according to our definition
#
# The configurator can be extended with more logic using the add function
configurator.add(pg.Imply(pg.All("y"), cc.Xor("q", "r", default="q")))
# See all available logic classes and how to use them in the API reference