Given an expanded property set, eliminate all redundancy: properties
        which are elements of other (composite) properties in the set will
        be eliminated. Non-symmetric properties equal to default values will be
        eliminated, unless the override a value from some composite property.
        Implicit properties will be expressed without feature
        grist, and sub-property values will be expressed as elements joined
        to the corresponding main property.

def minimize (properties):
    """ Given an expanded property set, eliminate all redundancy: properties
        which are elements of other (composite) properties in the set will
        be eliminated. Non-symmetric properties equal to default values will be
        eliminated, unless the override a value from some composite property.
        Implicit properties will be expressed without feature
        grist, and sub-property values will be expressed as elements joined
        to the corresponding main property.
    """
    if __debug__:
        from .property import Property
        assert is_iterable_typed(properties, Property)
    # remove properties implied by composite features
    components = []
    component_features = set()
    for property in properties:
        if property in __composite_properties:
            cs = __composite_properties[property]
            components.extend(cs)
            component_features.update(c.feature for c in cs)

    properties = b2.util.set.difference (properties, components)

    # handle subfeatures and implicit features

    # move subfeatures to the end of the list
    properties = [p for p in properties if not p.feature.subfeature] +\
        [p for p in properties if p.feature.subfeature]

    result = []
    while properties:
        p = properties[0]
        f = p.feature

        # locate all subproperties of $(x[1]) in the property set
        subproperties = [x for x in properties if is_subfeature_of(p, x.feature)]

        if subproperties:
            # reconstitute the joined property name
            subproperties.sort ()
            joined = b2.build.property.Property(p.feature, p.value + '-' + '-'.join ([sp.value for sp in subproperties]))
            result.append(joined)

            properties = b2.util.set.difference(properties[1:], subproperties)

        else:
            # eliminate properties whose value is equal to feature's
            # default and which are not symmetric and which do not
            # contradict values implied by composite properties.

            # since all component properties of composites in the set
            # have been eliminated, any remaining property whose
            # feature is the same as a component of a composite in the
            # set must have a non-redundant value.
            if p.value != f.default or f.symmetric or f in component_features:
                result.append (p)

            properties = properties[1:]

    return result