exclude both sources and sinks from findAcyclicInternalNewConns

This commit is contained in:
Michael Peters 2024-09-04 20:32:53 -07:00
parent a0a2e7c9bb
commit a5884a68db
3 changed files with 15 additions and 16 deletions

View File

@ -229,7 +229,7 @@
*/ */
import { edgesToNodes, NodeID, traceParents, RawEdge, traceChildren } from './network'; import { edgesToNodes, NodeID, traceParents, RawEdge, traceChildren } from './network';
import { keyMax, mapInvert, mapMap, randchoice, randint, randomNegPos, setDifference, setMap } from './util'; import { keyMax, mapInvert, mapMap, randchoice, randint, randomNegPos, setDifference, setMap, setUnion } from './util';
export interface GeneData { export interface GeneData {
innovation: number; innovation: number;
@ -548,19 +548,18 @@ export function findAcyclicInternalNewConns<DataT>(rawEdges: RawEdge<DataT>[]):
const parents = traceParents(nodes); const parents = traceParents(nodes);
const children = traceChildren(nodes); const children = traceChildren(nodes);
// TODO: exclude *both* sources and sinks // exclude *both* sources and sinks
// - sources are defined during think // - sources are defined during think, connections will be ignored
// - sinks should not be connected? <-- they probably could be, but not clean imo // - sinks should not be connected? <-- they probably could be, but it would be unclean imo
const sources = new Set(Array.from(parents.entries()).flatMap(([k, v]) => (v.size === 0 ? [k] : []))); const sources = new Set(Array.from(parents.entries()).flatMap(([k, v]) => (v.size === 0 ? [k] : [])));
const sinks = new Set(Array.from(children.entries()).flatMap(([k, v]) => (v.size === 0 ? [k] : []))); const sinks = new Set(Array.from(children.entries()).flatMap(([k, v]) => (v.size === 0 ? [k] : [])));
const acyclic = new Map<NodeID, Set<NodeID>>(); const acyclic = new Map<NodeID, Set<NodeID>>();
for (const [nodeID, nodeParents] of parents.entries()) { for (const [nodeID, nodeParents] of parents.entries()) {
const nodeParentIDs = setMap(nodeParents, n => n.id); const nodeParentIDs = setMap(nodeParents, n => n.id);
const nodeIDsAcyclic = setDifference(allNodeIDs, nodeParentIDs); const exclude = setUnion(nodeParentIDs, sources, sinks, new Set([nodeID]));
nodeIDsAcyclic.delete(nodeID); const nodeIDsAcyclic = setDifference(allNodeIDs, exclude);
const nodeIDsAcyclicNonSource = setDifference(nodeIDsAcyclic, sources); acyclic.set(nodeID, nodeIDsAcyclic);
acyclic.set(nodeID, nodeIDsAcyclicNonSource);
} }
// flatten // flatten

View File

@ -46,7 +46,7 @@ export function mapMap<K1, V1, K2, V2>(m: Map<K1, V1>, mapper: (k: K1, v: V1) =>
return new Map(Array.from(m.entries()).map(([k, v]) => mapper(k, v))); return new Map(Array.from(m.entries()).map(([k, v]) => mapper(k, v)));
} }
export function setIntersection<T>(...sets: Set<T>[]) { export function setIntersection<T>(...sets: Set<T>[]): Set<T> {
// a & b & ... // a & b & ...
if (sets.length === 0) return new Set(); if (sets.length === 0) return new Set();
const intersection = new Set(sets[0]!); const intersection = new Set(sets[0]!);
@ -56,7 +56,7 @@ export function setIntersection<T>(...sets: Set<T>[]) {
return intersection; return intersection;
} }
export function setUnion<T>(...sets: Set<T>[]) { export function setUnion<T>(...sets: Set<T>[]): Set<T> {
// a & b & ... // a & b & ...
if (sets.length === 0) return new Set(); if (sets.length === 0) return new Set();
const union = new Set(sets[0]!); const union = new Set(sets[0]!);

View File

@ -380,21 +380,21 @@ function testFindAcyclicInternalNewConns() {
const options = findAcyclicInternalNewConns(edges); const options = findAcyclicInternalNewConns(edges);
const expected = [ const expected = [
// not A -> B - B is a source // not A -> B - B is a source
{ src_id: 'A', dst_id: 'F' }, // not A -> F - F is a sink
// not B -> A - A is a source // not B -> A - A is a source
{ src_id: 'B', dst_id: 'C' }, { src_id: 'B', dst_id: 'C' },
{ src_id: 'B', dst_id: 'E' }, // not B -> E - E is a sink
{ src_id: 'B', dst_id: 'F' }, // not B -> F - F is a sink
// not C -> B - B is a source // not C -> B - B is a source
{ src_id: 'C', dst_id: 'D' }, { src_id: 'C', dst_id: 'D' },
{ src_id: 'C', dst_id: 'F' }, // not C -> F - F is a sink
{ src_id: 'D', dst_id: 'C' }, { src_id: 'D', dst_id: 'C' },
// not E -> B - B is a parent of E // not E -> B - B is a parent of E
{ src_id: 'E', dst_id: 'F' }, // not E -> F - F is a sink
// not F -> A - A is a parent of F // not F -> A - A is a parent of F
// not F -> B - B is a parent of F // not F -> B - B is a parent of F
{ src_id: 'F', dst_id: 'C' }, { src_id: 'F', dst_id: 'C' },
{ src_id: 'F', dst_id: 'E' }, // not F -> E - E is a sink
]; ];
function strcmp(a: string, b: string) { function strcmp(a: string, b: string) {