Commit faabcb97 authored by Ari Trachtenberg's avatar Ari Trachtenberg
Browse files

Merge branch 'problem2' into 'master'

problem 2 autograder

See merge request !1
parents e9342269 f4a8d84b
Loading
Loading
Loading
Loading

ci_cd/.gitlab-ci.yml

0 → 100644
+10 −0
Original line number Diff line number Diff line
stages:
  - prebuild
  - compile
  - test

include:
  - local: 'ci_cd/problem2.yml'   # Planar Subgraph

default:
  timeout: 5m

ci_cd/problem2.yml

0 → 100644
+48 −0
Original line number Diff line number Diff line
prebuild_problem_2:
  stage: prebuild
  script:
    - |
      # Check if source files exist
      if [ ! -f "impl/MaxPlanarSubgraph.cpp" ]; then
        echo "impl/MaxPlanarSubgraph.cpp does not exist";
        exit 1;
      fi
    - git clone https://agile.bu.edu/gitlab/configs/ec330/homeworks/homeworksix.git hw6
  artifacts:
    paths:
      - hw6/
  rules:
    - if: '$CI_COMMIT_REF_NAME == "problem2"'
  tags: [c++-17]

compile_problem_2:
  stage: compile
  needs:
    - job: prebuild_problem_2
      artifacts: true
  script:
    - ls -l hw6/tests/
    - cp impl/MaxPlanarSubgraph.cpp hw6/tests/impl/
    - cd hw6/tests
    - make problem2
  artifacts:
    paths:
      - hw6/
  rules:
    - if: '$CI_COMMIT_REF_NAME == "problem2"'
  tags: [c++-17]

exec_problem_2:
  stage: test
  needs:
    - job: compile_problem_2
      artifacts: true
  script:
    - cd hw6/tests
    - ./problem2
  artifacts:
    paths:
      - hw6/
  rules:
    - if: '$CI_COMMIT_REF_NAME == "problem2"'
  tags: [c++-17]

tests/Makefile

0 → 100644
+32 −0
Original line number Diff line number Diff line
# Makefile, generated with support of ChatGPT

# Compiler and flags
CXX = g++ -O2
CXXFLAGS = -std=c++17

# Source files
PROBLEM2_SRCS = testMaxPlanarSubgraph.cpp impl/MaxPlanarSubgraph.cpp impl/Vertex.cpp
SRCS = $(PROBLEM2_SRCS)

# Object files
PROBLEM2_OBJS = testMaxPlanarSubgraph.o impl/MaxPlanarSubgraph.o impl/Vertex.o
OBJS = $(PROBLEM2_OBJS)

# Executable name
PROBLEM2_EXEC = problem2
EXECS = $(PROBLEM2_EXEC)

# Default target to build the executable
all: $(PROBLEM2_EXEC)

# Rule to build the executable from object files
$(PROBLEM2_EXEC): $(PROBLEM2_OBJS) Makefile
	$(CXX) $(CXXFLAGS) -o $(PROBLEM2_EXEC) $(PROBLEM2_OBJS)

# Rules to build object files from source files
%.o: %.cpp Makefile
	$(CXX) $(CXXFLAGS) -c $< -o $@

# Clean target to remove compiled files
clean:
	rm -f $(OBJS) $(EXECS)
 No newline at end of file

tests/impl/Vertex.cpp

0 → 100644
+8 −0
Original line number Diff line number Diff line
//
// Created by Ari on 3/25/26.
//
#include "../include/Vertex.h"

// static variables
int Vertex::ID_COUNT = 0;
set<pair<int, int>> Vertex::locs;
 No newline at end of file
+231 −0
Original line number Diff line number Diff line
//
// Created by Ari on 3/25/26.
//

#ifndef HW6_ADMIN_DIRECTEDGRAPH_H
#define HW6_ADMIN_DIRECTEDGRAPH_H

#include <algorithm>
#include <optional>
#include <set>
#include <sstream>
#include <unordered_map>
#include <vector>

using namespace std;

/**
 * A generic directed graph whose vertices are referenced rather than copied.
 *
 * The public API uses vertex references, while the internal representation
 * stores pointers to vertices.  This allows the graph to work with vertex
 * types that are movable but not copyable.
 *
 * @tparam VLT Vertex label type
 * @tparam ELT Edge label type
 */
template<typename VLT, typename ELT>
class DirectedGraph {
public:
    // TYPES
    using VertexPtr = const VLT *;
    using NeighborMap = unordered_multimap<VertexPtr, ELT>;

    // MANIPULATORS
    /**
     * Adds a vertex to the graph.
     */
    void addVertex(const VLT &v) { vLabels.insert(&v); }

    /**
     * Adds a directed edge v1 -> v2 with label weight.
     * Missing endpoints are inserted automatically.
     */
    virtual void addEdge(const VLT &v1, const VLT &v2, ELT weight) {
        addVertex(v1);
        addVertex(v2);
        eLabels[&v1].emplace(&v2, weight);
    }

    // INFORMATIONAL
    /**
     * @return true iff the graph contains at least one edge v1 -> v2.
     */
    [[nodiscard]] bool hasEdge(const VLT &v1, const VLT &v2) const {
        auto outer = eLabels.find(&v1);
        if (outer == eLabels.end())
            return false;
        return outer->second.find(&v2) != outer->second.end();
    }

    /**
     * Returns the ii-th parallel edge label from v1 to v2, if it exists.
     */
    [[nodiscard]] optional<ELT> getEdge(const VLT &v1, const VLT &v2, const size_t ii = 0) const {
        auto outer = eLabels.find(&v1);
        if (outer == eLabels.end())
            return nullopt;

        const auto &inner = outer->second;
        auto range = inner.equal_range(&v2);

        size_t count = 0;
        for (auto it = range.first; it != range.second; ++it) {
            if (count == ii)
                return it->second;
            ++count;
        }
        return nullopt;
    }

    /**
     * @return the number of parallel edges from v1 to v2.
     */
    [[nodiscard]] size_t numEdges(const VLT &v1, const VLT &v2) const {
        auto outer = eLabels.find(&v1);
        if (outer == eLabels.end())
            return 0;
        return outer->second.count(&v2);
    }

    /**
     * @return the total number of edges in the graph.
     */
    [[nodiscard]] size_t numEdges() const {
        size_t total = 0;
        for (const auto &[u, inner]: eLabels) {
            (void) u;
            total += inner.size();
        }
        return total;
    }

    /**
     * @return the out-degree of v.
     */
    [[nodiscard]] size_t outDegree(const VLT &v) const {
        auto outer = eLabels.find(&v);
        if (outer == eLabels.end())
            return 0;
        return outer->second.size();
    }

    /**
     * @return the in-degree of v.
     */
    [[nodiscard]] size_t inDegree(const VLT &v) const {
        size_t count = 0;
        for (const auto &[u, inner]: eLabels) {
            (void) u;
            count += inner.count(&v);
        }
        return count;
    }

    /**
     * @return the number of vertices in the graph.
     */
    [[nodiscard]] size_t numVerts() const { return vLabels.size(); }

    /**
     * Read-only access to the set of stored vertex pointers.
     */
    [[nodiscard]] const set<VertexPtr> &getVerts() const { return vLabels; }

    /**
     * Read-only access to the edge map.
     */
    [[nodiscard]] const unordered_map<VertexPtr, NeighborMap> &getEdges() const { return eLabels; }

    /**
     * @return the outgoing neighbor multimap of v, or an empty map if none.
     */
    [[nodiscard]] const NeighborMap &neighbors(const VLT &v) const {
        static const NeighborMap empty;
        auto outer = eLabels.find(&v);
        return outer == eLabels.end() ? empty : outer->second;
    }

    /**
     * Returns the subgraph induced by the given vertex-pointer set.
     */
    [[nodiscard]] virtual DirectedGraph induced(const set<VertexPtr> &verts) const {
        DirectedGraph result;

        for (VertexPtr v: verts)
            result.vLabels.insert(v);

        for (VertexPtr u: verts) {
            auto outer = eLabels.find(u);
            if (outer == eLabels.end())
                continue;

            for (const auto &[v, w]: outer->second) {
                if (verts.count(v))
                    result.eLabels[u].emplace(v, w);
            }
        }

        return result;
    }

    /**
     * String representation of the graph.
     */
    [[nodiscard]] string toString() const {
        ostringstream oss;
        oss << "Graph:\n";

        for (VertexPtr u: vLabels) {
            oss << "  " << *u << " -> ";

            auto outer = eLabels.find(u);
            if (outer == eLabels.end() || outer->second.empty()) {
                oss << "{}\n";
                continue;
            }

            vector<pair<VertexPtr, ELT>> edges(outer->second.begin(), outer->second.end());

            sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) {
                if (!(*a.first == *b.first))
                    return *a.first < *b.first;
                return a.second < b.second;
            });

            oss << "{ ";
            for (size_t i = 0; i < edges.size(); ++i) {
                const auto &[v, w] = edges[i];
                if (i > 0)
                    oss << ", ";
                oss << "(" << *v << ", " << w << ")";
            }
            oss << " }\n";
        }

        return oss.str();
    }

    /**
     * Stream access to printing the graph.
     */
    friend ostream &operator<<(ostream &os, const DirectedGraph &g) { return os << g.toString(); }

    /**
     * Virtual destructor, to make sure all inherited destructors are called.
     */
    virtual ~DirectedGraph() = default;

protected:
    /**
     * The vertex set.
     */
    set<VertexPtr> vLabels;

    /**
     * Maps each source vertex to its outgoing labeled edges.
     */
    unordered_map<VertexPtr, NeighborMap> eLabels;
};

#endif // HW6_ADMIN_DIRECTEDGRAPH_H
Loading