A new interval arithmetic to generate the complementary of contractors

Pierre Filiol, Théotime Bollengier, Luc Jaulin, Jean-Christophe Le Lann












This microsite is associated to the paper
A new interval arithmetic to generate the complementary of contractors

Contractor algebra is used to characterize a set defined as a composition of sets defined by inequalities. It mainly uses interval methods combined with constraint propagation. This algebra includes the classical operations we have for sets such as the intersection, the union and the inversion. Now, it does not include the complement operator. The reason for this is probably related to the interval arithmetic itself. In this work, we show that it we change the arithmetic used for intervals adding a single flag, similar to not a number, we are able to include easily the complement in the algebra of contractors







Code for computing the solution set in the introduction



from codac import * 
from vibes import * 
X0=IntervalVector([[-10,10],[-10,10]]) 
f = Function("x1","x2","x2+sqrt(x1+x2)") 
S=SepFwdBwd(f,sqr(Interval(1,2))) 
vibes.beginDrawing() 
SIVIA(X0,S,0.01)





Code for computing the solution set for Test case 1


Click below to see/run/modify the online program :




from vibes import *
from mybox import *

def sqrti(x,ix):
    y=sqrt(x)
    iy=(x.lb<0)|ix
    return y,iy

def sqrtirev(x,ix,y,iy):
    r,ir=Interval(1,0),False
    if y.is_empty(): return r,ir
    r=sqr(y)
    if (iy==True)       : r,ir=r|Interval(-oo,0),True
    return r&x,ir&ix

def addi(x,ix,y,iy):
    z=x+y
    iz=ix|iy
    return z,iz

def addirev(z,iz,x,ix,y,iy):
    if not(iz):
        x=x&(z-y)
        y=y&(z-x)
    return x,ix,y,iy

def ininterval(x,ix,y,outer):
    if outer: x=x&y; ix=False
    else:
        xa=x&Interval(-oo,y.lb)
        xb=x&Interval(y.ub,oo)
        x=xa|xb
        ix=ix&True
    return x,ix    


def S1(x,y,outer):       #y+sqrt(x) in [1,2]
    ix,iy=False,False
    a,ia=sqrti(x,ix)
    z,iz=addi(a,ia,y,iy)
    z,iz=ininterval(z,iz,Interval(1,2),outer)
    a,ia,y,iy=addirev(z,iz,a,ia,y,iy)
    x,ix=sqrtirev(x,ix,a,ia)
    return x,y


def S(x,y,outer):       #y+sqrt(x+y) in [1,2]
    Y=Interval(1,2)
    ix,iy=False,False
    b,ib=addi(x,ix,y,iy)
    a,ia=sqrti(b,ib)
    z,iz=addi(a,ia,y,iy)
    z,iz=ininterval(z,iz,Y,outer)
    a,ia,y,iy=addirev(z,iz,a,ia,y,iy)
    b,ib=sqrtirev(b,ib,a,ia)
    x,ix,y,iy=addirev(b,ib,x,ix,y,iy)
    return x,y

def sivia(X):
	if (X.width()<0.1): return
	vibes.drawBox(X.x.lb, X.x.ub,X.y.lb, X.y.ub, 'blue[cyan]')
	X.x,X.y = S(X.x,X.y,True)
	vibes.drawBox(X.x.lb, X.x.ub,X.y.lb, X.y.ub, 'red[magenta]')
	X.x,X.y = S(X.x,X.y,False)
	vibes.drawBox(X.x.lb, X.x.ub,X.y.lb, X.y.ub, '[yellow]')	
	sivia(X.left())
	sivia(X.right())
	

vibes.beginDrawing()
vibes.newFigure('Result')
vibes.setFigureProperties({'x': 0, 'y': 0, 'width': 1600, 'height': 1000})
X=Box(Interval(-10,10),Interval(-10,10))
sivia(X)
vibes.endDrawing()












Code for mybox.html


import math
from myinterval import *


class Box:
	def __init__(X,a,b):
		X.x,X.y = a,b		
			
	def __repr__(X):
		return "[%f, %f] X [%f, %f]"%(X.x.lb, X.x.ub,X.y.lb, X.y.ub)

	def width(X):
		if X.x.is_empty() | X.y.is_empty():
			return -oo
		else:
			return max(X.x.width(),X.y.width())
	
	def left(X):
		if X.x.width()>X.y.width():
			return Box(X.x.left(),X.y)
		else:
			return Box(X.x,X.y.left())

	def right(X):
		if X.x.width()>X.y.width():
			return Box(X.x.right(),X.y)
		else:
			return Box(X.x,X.y.right())
	

if __name__ == '__main__':
	a = Interval(2,4)
	b = Interval(4,8)
	X=Box(a,b)
	print ("X = ",X)
	print ("X.left() = ",X.left())	
	print ("X.right() = ",X.right())	
	











Code for myinterval.pi



import math
oo= float('inf')
nan=float('nan')


class Interval:
	def __init__(x,a,b):
		if a>b:
			x.lb,x.ub = nan,nan
		else:
			x.lb,x.ub = a,b
		
	def is_empty(x):
		return math.isnan(x.lb)
	
	def __add__(x,y):
		return Interval(x.lb+y.lb, x.ub+y.ub)

	def __sub__(x, y):
		return Interval(x.lb-y.ub, x.ub-y.lb)

	def __mul__(x, y):
		L=[x.lb*y.lb,x.lb*y.ub,x.ub*y.lb,x.ub*y.ub]
		return Interval(min(L),max(L))

	def __rmul__(x, y):
		return x*Interval(y,y)

	def __contains__(x, a):
		return (x.lb<=a<=x.ub)

	def __truediv__(x, y):
		if 0 in y:
			return Interval(-oo, oo)
		else:
			return x*Interval(1./y.ub, 1./y.lb)

	def __and__(x,y):
		if (x.is_empty() or y.is_empty()):
			return Interval(1,0)
		else:
			return Interval(max(x.lb,y.lb),min(x.ub,y.ub))
		
	def __or__(x,y):
		if x.is_empty():
			return y
		elif y.is_empty():
			return x
		else:
			return Interval(min(x.lb,y.lb),max(x.ub,y.ub))

	def __repr__(x): 
		return '[{}, {}]'.format(x.lb, x.ub)
		
	def width(x): 
		return x.ub-x.lb
		
	def left(x):
		return Interval(x.lb,0.5*(x.lb+x.ub))

	def right(x):
		return Interval(0.5*(x.lb+x.ub),x.ub)


def sqr(x):
	L=[x.lb**2,x.ub**2]
	if 0 in x:
		return Interval(0,max(L))
	else:
		return Interval(min(L),max(L))

def sqrt(x):
	x=x&Interval(0,oo)
	return Interval(math.sqrt(x.lb),math.sqrt(x.ub))

def mini(x,y):
	return Interval(min(x.lb,y.lb),min(x.ub,y.ub))

def maxi(x,y):
	return Interval(max(x.lb,y.lb),max(x.ub,y.ub))

			
def exp(x):
	return Interval(math.exp(x.lb), math.exp(x.ub))

def log(x):
	if x.ub<=0:
		return Interval(1,0)
	elif 0 in x: 
		return Interval(-oo,math.log(x.ub))
	else:
		return Interval(math.log(x.lb), math.log(x.ub))

def subset(x,y):
	if x.is_empty():
		return True
	else:
		return (x.lb in y) and (x.ub in y)

def disjoint(x,y):
	return (x&y).is_empty()
	

if __name__ == '__main__':
	x = Interval(-2, 2)
	print("x = ",x)
	print("sqr(x)+2*x - exp(x) = ",sqr(x)+2*x - exp(x))
	
	print("sqrt(Interval(4,9)) = ",sqrt(Interval(4,9)))	
	print("sqrt(Interval(-9,-3)) = ",sqrt(Interval(-9,-3)))	
	print("sqrt(Interval(-9,4)) = ",sqrt(Interval(-9,4)))
	
	x = Interval(-1, 3)
	print("x = ",x)
	y = Interval(3, 4)
	print("y = ",y)
	print("subset(x,y) = ",subset(x,y))
	print("disjoint(x,y) = ",disjoint(x,y))