Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions Problems/NPComplete/NPC_VERTEXCOVER/VERTEXCOVER_Class.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class VERTEXCOVER : IGraphProblem<VertexCoverBruteForce,VCVerifier,VertexCoverDe
public string sourceLink { get; } = "https://cgi.di.uoa.gr/~sgk/teaching/grad/handouts/karp.pdf";
private static string _defaultInstance = "(({a,b,c,d,e},{{a,b},{a,c},{a,e},{b,e},{c,d}}),3)";
public string defaultInstance { get; } = _defaultInstance;
public string instanceFormat {get;} = "Graph and target cover size, shaped as ((nodes, edges), k). Nodes are a brace-delimited comma-separated list {n1,n2,...}; edges are a brace-delimited list of undirected pairs {{n1,n2},{n2,n3},...} drawn from the node set; k is the required vertex-cover size. Example: (({a,b,c,d},{{a,b},{a,c},{a,d}}),1)";
public string certificateFormat {get;} = "Comma-separated node names, optionally wrapped in braces. Must name nodes from the instance's node set such that every edge has at least one endpoint in the set (a vertex cover). Example: {a}";
public string instance {get;set;} = string.Empty;
private List<string> _nodes = new List<string>();
private List<KeyValuePair<string, string>> _edges = new List<KeyValuePair<string, string>>();
Expand Down Expand Up @@ -65,19 +67,27 @@ public VERTEXCOVER() : this(_defaultInstance) {

}
public VERTEXCOVER(string instanceInput) {
if (string.IsNullOrWhiteSpace(instanceInput)) {
throw new ProblemParseException("VERTEXCOVER", instanceInput, "instance is empty");
}

instance = instanceInput;

StringParser vertexCover = new("{((N,E),K) | N is set, E subset N unorderedcross N, K is int}");
vertexCover.parse(instanceInput);
nodes = vertexCover["N"].ToList().Select(node => node.ToString()).ToList();
edges = vertexCover["E"].ToList().Select(edge =>
{
List<UtilCollection> cast = edge.ToList();
return new KeyValuePair<string, string>(cast[0].ToString(), cast[1].ToString());
}).ToList();
_K = int.Parse(vertexCover["K"].ToString());
try {
vertexCover.parse(instanceInput);
nodes = vertexCover["N"].ToList().Select(node => node.ToString()).ToList();
edges = vertexCover["E"].ToList().Select(edge =>
{
List<UtilCollection> cast = edge.ToList();
return new KeyValuePair<string, string>(cast[0].ToString(), cast[1].ToString());
}).ToList();
_K = int.Parse(vertexCover["K"].ToString());

graph = new UtilCollectionGraph(vertexCover["N"], vertexCover["E"]);
graph = new UtilCollectionGraph(vertexCover["N"], vertexCover["E"]);
} catch (Exception ex) when (ex is not ProblemParseException) {
throw new ProblemParseException("VERTEXCOVER", instanceInput, ex.Message);
}
}
}

96 changes: 28 additions & 68 deletions Problems/NPComplete/NPC_VERTEXCOVER/Verifiers/VCVerifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public string certificate {

// --- Methods Including Constructors ---
public VCVerifier() {

}

/// <summary>
Expand All @@ -36,91 +36,51 @@ public VCVerifier() {
/// <param name="certificate"></param>
/// <returns></returns>
public bool verify(VERTEXCOVER problem, string certificate){
//{{a,b,c,d,e,f,g} : {(a,b) & (a,c) & (c,d) & (c,e) & (d,f) & (e,f) & (e,g)} : 3}
//{{a,d,e} : {(a,b) & (a,c) & (c,d) & (c,e) & (d,f) & (e,f) & (e,g)} }
List<string> certificateNodes = getNodes(certificate);
// List<KeyValuePair<string, string>> edges = getEdges(c);
if (string.IsNullOrWhiteSpace(certificate))
{
throw new CertificateParseException(problem, certificate, "certificate is empty");
}

List<string> certificateNodes;
try
{
certificateNodes = getNodes(certificate);
}
catch (Exception ex)
{
throw new CertificateParseException(problem, certificate, ex.Message);
}
if (certificateNodes.Count == 0 || certificateNodes.Any(string.IsNullOrWhiteSpace))
{
throw new CertificateParseException(problem, certificate,
"certificate did not parse to a non-empty list of node names");
}
List<string> GNodes = problem.nodes;
List<KeyValuePair<string, string>> Gedges = problem.edges;


//var list = nodes.Except(GNodes);

// bool result1 = list?.Any() != true;

// int count = 0;
// foreach (KeyValuePair<string, string> edge in edges)
// {
// foreach (KeyValuePair<string, string> Gedge in Gedges){
// if (edge.Key.Equals(Gedge.Key) && edge.Value.Equals(Gedge.Value)){
// count += 1;
// }
// if (edge.Key.Equals(Gedge.Value) && edge.Value.Equals(Gedge.Key)){
// count += 1;
// }
// }
// }
// int size = Gedges.Count;
// bool result2 = false;
// if (size == count){
// result2 = true;
// }

// return (result1 == true) && (result2 == true) ? true : false;

//Step one of the verify method. Check if the input graph contains all the nodes in the certificate. If not, reject.
foreach(string cNode in certificateNodes){
if(!GNodes.Contains(cNode)){
foreach (string cNode in certificateNodes)
{
if (!GNodes.Contains(cNode)){
return false; //reject
}
}

//Step two of the verify method. Test whether the set of all edges incident to nodes in c equals the set of edges in G
//A node being incident to an edge means that that edge has the node as one of its two endpoints.

//To test incidence, we will ask the graph if it has any edges that don't have an endpoint contained in the certificate set.
foreach(KeyValuePair<string,string> kvp in Gedges){
if(!certificateNodes.Contains(kvp.Key) && !certificateNodes.Contains(kvp.Value)){ //if a kvp doesnt have a key or value found in the nodeset
foreach (KeyValuePair<string, string> kvp in Gedges)
{
if (!certificateNodes.Contains(kvp.Key) && !certificateNodes.Contains(kvp.Value)){ //if a kvp doesnt have a key or value found in the nodeset
return false; //reject
}

}
return true;

}

public List<string> getNodes(string nodesInput) {
return GraphParser.parseNodeListWithStringFunctions(nodesInput);

}

public List<KeyValuePair<string, string>> getEdges(string Ginput) {

List<KeyValuePair<string, string>> allGEdges = new List<KeyValuePair<string, string>>();

string strippedInput = Ginput.Replace("{", "").Replace("}", "").Replace(" ", "").Replace("(", "").Replace(")","");

// [0] is nodes, [1] is edges, [2] is k.
string[] Gsections = strippedInput.Split(':');
string[] Gedges = Gsections[1].Split('&');

foreach (string edge in Gedges) {
string[] fromTo = edge.Split(',');
string nodeFrom = fromTo[0];
string nodeTo = fromTo[1];

KeyValuePair<string,string> fullEdge = new KeyValuePair<string,string>(nodeFrom, nodeTo);
allGEdges.Add(fullEdge);
}

return allGEdges;
}

public int getK(string Ginput) {
string strippedInput = Ginput.Replace("{", "").Replace("}", "").Replace(" ", "").Replace("(", "").Replace(")","");

// [0] is nodes, [1] is edges, [2] is k.
string[] Gsections = strippedInput.Split(':');
return Int32.Parse(Gsections[2]);
return GraphParser.parseNodeListWithStringFunctions(nodesInput);
}
}
46 changes: 45 additions & 1 deletion redux-tests/Problems/NPC_VERTEXCOVER/VERTEXCOVER_Tests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Xunit;
using API.Interfaces;
using API.Interfaces.Graphs;
using API.Problems.NPComplete.NPC_VERTEXCOVER.ReduceTo.NPC_ARCSET;
using API.Problems.NPComplete.NPC_VERTEXCOVER.Verifiers;
Expand Down Expand Up @@ -46,7 +47,50 @@ public void VCSolver_Test()
}


[Theory] //tests with default graph string Certificates of this test represent junk or empty data.
// -------------------------------------------------------------------------
// Self-describing formats (§1.5)
// -------------------------------------------------------------------------

[Fact]
public void VERTEXCOVER_Declares_Formats()
{
VERTEXCOVER vCov = new VERTEXCOVER();
Assert.False(string.IsNullOrWhiteSpace(vCov.instanceFormat));
Assert.False(string.IsNullOrWhiteSpace(vCov.certificateFormat));
}

// -------------------------------------------------------------------------
// Constructor — invalid instances (all must throw ProblemParseException)
// -------------------------------------------------------------------------

[Theory]
[InlineData("")] // empty
[InlineData(" ")] // whitespace only
[InlineData("{{a,b,c} : {(a,b)} : 3}")] // old colon format
[InlineData("abc")] // bare string
[InlineData("(({a,b,c},{{a,b}}),x)")] // non-integer K
[InlineData("(({a,b,c},{{a,b}})")] // unbalanced / truncated
public void VERTEXCOVER_Constructor_Throws_On_Invalid_Instance(string instance)
{
Assert.Throws<ProblemParseException>(() => new VERTEXCOVER(instance));
}

// -------------------------------------------------------------------------
// Verifier — malformed certificates (must throw CertificateParseException)
// -------------------------------------------------------------------------

[Theory]
[InlineData("")] // empty
[InlineData(" ")] // whitespace only
[InlineData("{}")] // parses to a single empty token
public void VERTEXCOVER_Verifier_Throws_On_Malformed_Certificate(string certificate)
{
VERTEXCOVER testVert = new VERTEXCOVER();
VCVerifier verifier = testVert.defaultVerifier;
Assert.Throws<CertificateParseException>(() => verifier.verify(testVert, certificate));
}

[Theory] //tests with default graph string Certificates of this test represent junk or empty data.
[InlineData("(({a,b,c,d},{{a,b},{a,c},{a,d}}),1)", "{a}")] //four node graph dependent on a with a in cert
[InlineData("(({a,b,c,d},{{a,b},{a,c},{a,d}}),1)", "{b,c,d}")] //four node graph dependent on a with all nodes except a in cert
[InlineData("(({a,b,c,d,e},{{a,b},{a,c},{a,d},{a,e},{b,c},{b,d},{b,e},{c,e},{c,d},{d,e}}),5)","{a,b,c,d}}")] //five node connected graph, test four nodes
Expand Down