All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.chocosolver.solver.variables.impl.DirectedNodeInducedGraphVarImpl Maven / Gradle / Ivy

There is a newer version: 4.10.17
Show newest version
/*
 * This file is part of choco-solver, http://choco-solver.org/
 *
 * Copyright (c) 2023, IMT Atlantique. All rights reserved.
 *
 * Licensed under the BSD 4-clause license.
 *
 * See LICENSE file in the project root for full license information.
 */
package org.chocosolver.solver.variables.impl;

import org.chocosolver.solver.ICause;
import org.chocosolver.solver.Model;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.variables.delta.GraphDelta;
import org.chocosolver.solver.variables.events.GraphEventType;
import org.chocosolver.util.objects.graphs.DirectedGraph;

/**
 * Directed graph variable guaranteeing that any instantiation is a node-induced subgraph of the envelope
 * used to construct the graph variable. Any two nodes that are connected in the envelope are connected in
 * any instantiation containing these two nodes. More formally:
 *
 *  - G = (V, E) \in [G_lb, G_ub], with G_ub = (V_ub, E_ub);
 *  - E = { (x, y) \in E_ub | x \in V \land y \in V }.
 *
 * @author Dimitri Justeau-Allaire
 * @since 15/04/2021
 */
public class DirectedNodeInducedGraphVarImpl extends DirectedGraphVarImpl implements ICause {

    private final DirectedGraph originalUB;

    /**
     * Creates an directed node-induced (from the envelope) graph variable
     *
     * @param name
     * @param solver
     * @param LB
     * @param UB
     */
    public DirectedNodeInducedGraphVarImpl(String name, Model solver, DirectedGraph LB, DirectedGraph UB) {
        super(name, solver, LB, UB);
        this.originalUB = new DirectedGraph(UB);
    }

    @Override
    public boolean enforceNode(int x, ICause cause) throws ContradictionException {
        boolean nodeEnforced = super.enforceNode(x, cause);
        if (!nodeEnforced) {
            return false;
        }
        boolean edgeAdded = false;
        for (int y : originalUB.getSuccessorsOf(x)) {
            if (LB.containsNode(y)) {
                if (!UB.containsEdge(x, y)) {
                    this.contradiction(cause, "Cannot enforce node " + x + " because edge (" + x + ", " + y + ") was removed from the envelope");
                }
                if (LB.addEdge(x, y)) {
                    if (reactOnModification) {
                        delta.add(x, GraphDelta.EDGE_ENFORCED_TAIL, cause);
                        delta.add(y, GraphDelta.EDGE_ENFORCED_HEAD, cause);
                    }
                    edgeAdded = true;
                }
            } else if (UB.containsNode(y) && !UB.containsEdge(x, y)) {
                removeNode(y, this);
            }
        }
        for (int y : originalUB.getPredecessorsOf(x)) {
            if (LB.containsNode(y)) {
                if (!UB.containsEdge(x, y)) {
                    this.contradiction(cause, "Cannot enforce node " + x + " because edge (" + y + ", " + x + ") was removed from the envelope");
                }
                if (LB.addEdge(y, x)) {
                    if (reactOnModification) {
                        delta.add(y, GraphDelta.EDGE_ENFORCED_TAIL, cause);
                        delta.add(x, GraphDelta.EDGE_ENFORCED_HEAD, cause);
                    }
                    edgeAdded = true;
                }
            } else if (UB.containsNode(y) && !UB.containsEdge(y, x)) {
                removeNode(y, this);
            }
        }
        if (edgeAdded) {
            notifyPropagators(GraphEventType.ADD_EDGE, this);
        }
        return true;
    }

    @Override
    public boolean removeEdge(int x, int y, ICause cause) throws ContradictionException {
        boolean edgeRemoved = super.removeEdge(x, y, cause);
        if (!edgeRemoved) {
            return false;
        }
        boolean xInKer = getMandatoryNodes().contains(x);
        boolean yInKer = getMandatoryNodes().contains(y);
        if (xInKer && yInKer) {
            this.contradiction(cause, "Remove mandatory edge");
        }
        if (xInKer && !yInKer) {
            removeNode(y, this);
        }
        if (!xInKer && yInKer) {
            removeNode(x, this);
        }
        return true;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy