Changeset 802


Ignore:
Timestamp:
07/07/15 00:53:53 (11 months ago)
Author:
mmckerns
Message:

added integer programming tools and some examples from Google ORtools

Location:
mystic
Files:
5 added
2 edited

Legend:

Unmodified
Added
Removed
  • mystic/mystic/constraints.py

    r778 r802  
    545545 
    546546 
     547from random import randrange, shuffle 
     548def unique(seq, full=None): 
     549    """replace the duplicate values with unique values in 'full' 
     550 
     551    If full is a type (int or float), then unique values of the given type 
     552    are selected from range(min(seq),max(seq)). If full is a dict of 
     553    {'min':min, 'max':max}, then unique floats are selected from 
     554    range(min(seq),max(seq)). If full is a sequence (list or set), then 
     555    unique values are selected from the given sequence.  
     556    """ 
     557    unique = set() 
     558    # replace all duplicates with 'None' 
     559    seq = [x if x not in unique and not unique.add(x) else None for x in seq] 
     560    lseq = len(seq) 
     561    # check type if full not specified 
     562    if full is None: 
     563        if all([isinstance(x, int) for x in unique]): full = int 
     564        else: full = float 
     565        ok = True 
     566    else: ok = False 
     567    # check all unique show up in 'full' 
     568    if full in (int,float): # specified type, not range 
     569        ok = ok or full==float or all([isinstance(x, int) for x in unique]) 
     570        msg = "not all items are of type='%s'" % full.__name__ 
     571        _min = min(unique) 
     572        _max = max(unique) 
     573    elif isinstance(full, dict): # specified min/max for floats 
     574        ok = min(unique) >= full['min'] and max(unique) < full['max'] 
     575        if not ok: 
     576            oops = list(unique - set(range(full['min'],full['max']))) 
     577            msg = "x=%s not in %s <= x < %s" % (oops[-1],full['min'],full['max']) 
     578        _min = full['min'] 
     579        _max = full['max'] 
     580        full = float 
     581    else: # full is a list of all possible values 
     582        ok = unique.issubset(full) 
     583        if not ok: 
     584            oops = list(unique - set(full)) 
     585            msg = "%s not in given set" % oops[-1] 
     586        _min = _max = None 
     587    if not ok: raise ValueError(msg) 
     588    # check if a unique sequence is possible to build 
     589    if full is float: 
     590        if _min == _max and lseq > 1: 
     591            msg = "no unique len=%s sequence with %s <= x <= %s" % (lseq,_min,_max) 
     592            raise ValueError(msg) 
     593        # replace the 'None' values in seq with 'new' values 
     594        #XXX: HIGHLY UNLIKELY two numbers will be the same, but possible 
     595        return [randrange(_min,_max,_int=float) if x is None else x for x in seq] 
     596    # generate all possible values not found in 'unique' 
     597    if full is int: 
     598        if max(lseq - (_max+1 - _min), 0): 
     599            msg = "no unique len=%s sequence with %s <= x <= %s" % (lseq,_min,_max) 
     600            raise ValueError(msg) 
     601        new = list(set(range(_min,_max+1)) - unique) 
     602    else: 
     603        if lseq > len(full): 
     604            msg = "no unique len=%s sequence in given set" % lseq 
     605            raise ValueError(msg) 
     606        new = list(set(full) - unique) 
     607    # ensure randomly ordered 
     608    shuffle(new) 
     609    # replace the 'None' values in seq with 'new' values 
     610    return [new.pop() if x is None else x for x in seq] 
     611 
     612 
     613#XXX: enable impose_unique on selected members of x? (see constraints.integers) 
     614 
     615def impose_unique(seq=None): 
     616    """ensure all values are unique and found in the given set""" 
     617    def dec(f): 
     618        def func(x,*args,**kwds): 
     619            return f(unique(x, seq),*args,**kwds) 
     620        return func 
     621    return dec 
     622 
     623 
     624#XXX: enable near_integers and has_unique on selected members of x? 
     625 
     626from numpy import round, abs 
     627def near_integers(x): # use as a penalty for int programming 
     628    """the sum of all deviations from int values""" 
     629    return abs(x - round(x)).sum() 
     630 
     631def has_unique(x): # use as a penalty for unique numbers 
     632    """check for uniqueness of the members of x""" 
     633    return sum(x.count(xi) for xi in x) 
     634   #return len(x) - len(set(x)) 
     635 
     636 
     637 
    547638# EOF 
     639 
     640# EOF 
  • mystic/mystic/symbolic.py

    r776 r802  
    5858        # Flatten b, in case it's in the form [[0, 1, 2]] for example. 
    5959        if len(b) == 1: 
    60             b = list(ndarray.flatten(asarray(b))) 
     60            b = ndarray.flatten(asarray(b)).tolist() 
    6161 
    6262        # Check dimensions and give errors if incorrect. 
     
    8383        # Flatten h, in case it's in the form [[0, 1, 2]] for example. 
    8484        if len(h) == 1: 
    85             h = list(ndarray.flatten(asarray(h))) 
     85            h = ndarray.flatten(asarray(h)).tolist() 
    8686 
    8787        # Check dimensions and give errors if incorrect. 
Note: See TracChangeset for help on using the changeset viewer.