DEV Community

Cover image for Building a Social Network Analyzer with CXXGraph: From Friend Recommendations to Influence Detection
ZigRazor
ZigRazor

Posted on

Building a Social Network Analyzer with CXXGraph: From Friend Recommendations to Influence Detection

Learn how to build production-ready social network features using modern C++ and graph theory

Introduction

Open any social media app today and you'll see sophisticated features powered by graph algorithms: "People You May Know" suggestions that are eerily accurate, influencer rankings that determine who gets verified, community recommendations that connect like-minded users, and viral content predictions that drive engagement.

Behind these features lies a common foundation: social graph analysis. Your users, their connections, and their interactions form a massive graph structure, and understanding this graph is the key to building compelling social features.

But here's the challenge: traditional social network analysis tools are either heavyweight frameworks with complex dependencies (hello, Boost), high-level languages that can't handle backend scale (Python's NetworkX), or specialized platforms that lock you into their ecosystem.

What if you could build production-ready social network analytics directly in C++, with a simple header-only library, and deploy it in your backend services today?

Enter CXXGraph - a modern C++ graph library that brings the power of social network analysis to your applications without the complexity.

In this comprehensive guide, we'll build a complete social network analysis system from scratch, covering everything from friend recommendations to viral content prediction. By the end, you'll have working code you can adapt to your own social platform.

Why CXXGraph for Social Network Analysis?

Before diving into code, let's understand why CXXGraph is perfect for social network backends:

πŸš€ Backend Performance

  • Native C++ speed handles millions of users
  • Zero-copy operations for edge traversal
  • Efficient memory usage for large graphs
  • No GC pauses during critical operations

πŸ”§ Production Ready

  • Header-only: no compilation or linking hassles
  • No external dependencies to manage
  • Modern C++17 syntax for maintainable code
  • Battle-tested algorithms (30+ graph operations)

πŸ“Š Rich Algorithm Library

  • Community detection (find user clusters)
  • Centrality metrics (identify influencers)
  • Shortest paths (connection suggestions)
  • Component analysis (network health)

πŸ’Ό Enterprise Friendly

  • Integrates with existing C++ backends
  • Works alongside databases and caches
  • Easy to wrap in REST APIs
  • Scales horizontally

Simply include one header:

#include "CXXGraph/CXXGraph.hpp"
Enter fullscreen mode Exit fullscreen mode

No build system configuration, no package managers, no hassle.

What We're Building: A Complete Social Analytics Platform

We'll create a production-grade social network analysis system with these features:

  1. βœ… User Relationship Modeling - Friends, followers, connections
  2. βœ… Friend Recommendations - "People You May Know" engine
  3. βœ… Influence Detection - Identify key influencers and opinion leaders
  4. βœ… Community Discovery - Find natural user clusters and groups
  5. βœ… Virality Prediction - Estimate content spread and reach
  6. βœ… Network Health Monitoring - Track engagement and connectivity

Here's what our analytics dashboard will output:

╔═══════════════════════════════════════════════╗
β•‘   SOCIAL NETWORK ANALYTICS DASHBOARD         β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

πŸ‘€ USER PROFILE
   Name: Alice Johnson
   Connections: 156
   Reach: 2,847 users

🀝 FRIEND RECOMMENDATIONS
   1. Bob Smith (12 mutual friends) - Score: 87.5
   2. Carol Davis (8 mutual friends) - Score: 76.2
   3. David Wilson (6 mutual friends) - Score: 64.8

⭐ INFLUENCE METRICS
   Your influence rank: Top 5%
   Content reach: 3,241 users
   Engagement score: 8.7/10

πŸ‘₯ COMMUNITIES
   Member of 3 communities:
   - Tech Enthusiasts (234 members, 89% cohesion)
   - Local Events (156 members, 76% cohesion)
   - Book Club (45 members, 94% cohesion)

πŸ“Š VIRAL POTENTIAL
   Latest post expected reach: 2,100 users
   Spread velocity: 45 shares/hour
   Virality score: 73/100
Enter fullscreen mode Exit fullscreen mode

Let's build it step by step.

Step 1: Data Modeling - Representing Users and Relationships

First, we need to model our social network entities:

#include "CXXGraph/CXXGraph.hpp"
#include <string>
#include <unordered_map>
#include <vector>
#include <memory>
#include <algorithm>
#include <cmath>

// User profile data
struct User {
    std::string id;
    std::string name;
    std::string email;
    std::string bio;
    int followerCount;
    int followingCount;
    long long joinedTimestamp;

    User(const std::string& uid, const std::string& uname)
        : id(uid), name(uname), followerCount(0), followingCount(0), 
          joinedTimestamp(0) {}
};

// Different types of social connections
enum class RelationType {
    FRIEND,        // Bidirectional (Facebook-style)
    FOLLOW,        // Unidirectional (Twitter-style)
    COLLEAGUE,     // Professional connection (LinkedIn-style)
    FAMILY,        // Strong tie
    BLOCKED        // Negative relationship
};

// Relationship metadata
struct Relationship {
    RelationType type;
    int strength;           // 1-10, based on interaction frequency
    long long createdAt;    // Timestamp when connection was made
    int messageCount;       // Number of direct messages
    int sharedPosts;        // Number of shared/retweeted posts

    Relationship() 
        : type(RelationType::FRIEND), strength(5), 
          createdAt(0), messageCount(0), sharedPosts(0) {}
};

// Calculate relationship strength from interaction data
int calculateStrength(const Relationship& rel) {
    double score = 0.0;

    // Factor in different types of interactions
    score += rel.messageCount * 0.5;     // Messages are strong signals
    score += rel.sharedPosts * 0.3;      // Sharing shows engagement

    // Time decay - older connections might be weaker
    long long daysSinceCreation = 
        (std::time(nullptr) - rel.createdAt) / (24 * 3600);
    double decayFactor = std::max(0.5, 1.0 - (daysSinceCreation / 365.0) * 0.1);

    score *= decayFactor;

    // Clamp to 1-10 range
    return std::max(1, std::min(10, static_cast<int>(score)));
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Building the Social Graph

Now let's create our core social network class:

class SocialNetwork {
private:
    std::unordered_map<std::string, User> users_;
    CXXGraph::Graph<std::string> graph_;
    std::unordered_map<std::string, Relationship> relationships_;
    CXXGraph::T_EdgeSet<std::string> edgeSet_;
    bool graphDirty_ = false;  // Track if graph needs rebuilding

public:
    // Add a new user to the network
    void addUser(const User& user) {
        users_[user.id] = user;
        std::cout << "βœ“ Added user: " << user.name << " (" << user.id << ")\n";
    }

    // Create a friend connection (bidirectional)
    void addFriendship(const std::string& user1, const std::string& user2,
                       int interactionScore = 5) {
        if (!validateUsers(user1, user2)) return;

        CXXGraph::Node<std::string> node1(user1, user1);
        CXXGraph::Node<std::string> node2(user2, user2);

        // Create weighted undirected edge
        auto edge = std::make_shared<CXXGraph::UndirectedWeightedEdge<std::string>>(
            makeEdgeId(user1, user2), 
            node1, node2, 
            static_cast<double>(interactionScore)
        );

        edgeSet_.insert(edge);

        // Store relationship metadata
        Relationship rel;
        rel.type = RelationType::FRIEND;
        rel.strength = interactionScore;
        rel.createdAt = std::time(nullptr);
        relationships_[makeEdgeId(user1, user2)] = rel;

        graphDirty_ = true;
    }

    // Create a follow relationship (unidirectional)
    void addFollowRelation(const std::string& follower, 
                          const std::string& following) {
        if (!validateUsers(follower, following)) return;

        CXXGraph::Node<std::string> followerNode(follower, follower);
        CXXGraph::Node<std::string> followingNode(following, following);

        // Directed edge for asymmetric relationship
        auto edge = std::make_shared<CXXGraph::DirectedWeightedEdge<std::string>>(
            follower + "->" + following, 
            followerNode, followingNode, 
            1.0
        );

        edgeSet_.insert(edge);
        users_[following].followerCount++;
        users_[follower].followingCount++;

        Relationship rel;
        rel.type = RelationType::FOLLOW;
        rel.createdAt = std::time(nullptr);
        relationships_[follower + "->" + following] = rel;

        graphDirty_ = true;
    }

    // Update relationship strength based on new interactions
    void recordInteraction(const std::string& user1, const std::string& user2,
                          bool isMessage = false, bool isShare = false) {
        std::string edgeId = makeEdgeId(user1, user2);

        if (relationships_.find(edgeId) != relationships_.end()) {
            if (isMessage) relationships_[edgeId].messageCount++;
            if (isShare) relationships_[edgeId].sharedPosts++;

            // Recalculate strength
            int newStrength = calculateStrength(relationships_[edgeId]);
            relationships_[edgeId].strength = newStrength;

            // Update edge weight in graph
            updateEdgeWeight(edgeId, newStrength);
        }
    }

    // Getters
    const CXXGraph::Graph<std::string>& getGraph() {
        if (graphDirty_) {
            rebuildGraph();
        }
        return graph_;
    }

    const User& getUser(const std::string& userId) const {
        return users_.at(userId);
    }

    std::vector<std::string> getAllUserIds() const {
        std::vector<std::string> ids;
        ids.reserve(users_.size());
        for (const auto& [id, user] : users_) {
            ids.push_back(id);
        }
        return ids;
    }

    size_t getUserCount() const { return users_.size(); }
    size_t getConnectionCount() const { return edgeSet_.size(); }

private:
    bool validateUsers(const std::string& user1, const std::string& user2) {
        if (users_.find(user1) == users_.end()) {
            std::cerr << "βœ— User not found: " << user1 << "\n";
            return false;
        }
        if (users_.find(user2) == users_.end()) {
            std::cerr << "βœ— User not found: " << user2 << "\n";
            return false;
        }
        return true;
    }

    std::string makeEdgeId(const std::string& user1, const std::string& user2) {
        // Ensure consistent edge ID regardless of order (for undirected)
        if (user1 < user2) {
            return user1 + "<->" + user2;
        }
        return user2 + "<->" + user1;
    }

    void rebuildGraph() {
        graph_ = CXXGraph::Graph<std::string>(edgeSet_);
        graphDirty_ = false;
    }

    void updateEdgeWeight(const std::string& edgeId, int newWeight) {
        // Remove old edge and add updated one
        // (Simplified - in production, you'd have more efficient updates)
        graphDirty_ = true;
    }
};
Enter fullscreen mode Exit fullscreen mode

Design Notes:

  • We separate graph structure (CXXGraph) from business logic (metadata)
  • Relationship strength is dynamically calculated from interactions
  • Graph is lazy-rebuilt only when needed (performance optimization)
  • Both directed and undirected relationships are supported

Step 3: Friend Recommendations - "People You May Know"

This is the feature everyone recognizes. Let's implement it properly:

class FriendRecommender {
public:
    struct Recommendation {
        std::string userId;
        std::string userName;
        int mutualFriends;
        int commonInterests;  // Could be based on tags, groups, etc.
        double socialDistance; // Graph distance
        double score;

        std::string getReason() const {
            if (mutualFriends > 10) {
                return "Many mutual connections";
            } else if (mutualFriends > 5) {
                return std::to_string(mutualFriends) + " mutual friends";
            } else if (commonInterests > 3) {
                return "Similar interests";
            } else {
                return "You might know this person";
            }
        }
    };

    static std::vector<Recommendation> recommendFriends(
        const SocialNetwork& network,
        const std::string& userId,
        int maxRecommendations = 10) {

        const auto& graph = network.getGraph();
        CXXGraph::Node<std::string> userNode(userId, userId);

        // Step 1: Get user's direct connections
        auto directFriends = getDirectFriends(graph, userId);

        // Step 2: Find friends-of-friends
        std::unordered_map<std::string, int> mutualFriendCount;
        std::unordered_map<std::string, double> distances;

        for (const auto& friendId : directFriends) {
            auto friendsOfFriend = getDirectFriends(graph, friendId);

            for (const auto& candidateId : friendsOfFriend) {
                // Skip if it's the user or already a friend
                if (candidateId == userId || 
                    isDirectFriend(directFriends, candidateId)) {
                    continue;
                }

                mutualFriendCount[candidateId]++;

                // Calculate graph distance (simplified - using BFS depth)
                if (distances.find(candidateId) == distances.end()) {
                    distances[candidateId] = 2.0; // Friends-of-friends are distance 2
                }
            }
        }

        // Step 3: Calculate comprehensive scores
        std::vector<Recommendation> recommendations;

        for (const auto& [candidateId, mutualCount] : mutualFriendCount) {
            Recommendation rec;
            rec.userId = candidateId;

            try {
                rec.userName = network.getUser(candidateId).name;
            } catch (...) {
                continue; // Skip if user data unavailable
            }

            rec.mutualFriends = mutualCount;
            rec.socialDistance = distances[candidateId];
            rec.commonInterests = 0; // Would be calculated from user data

            // Scoring algorithm
            rec.score = calculateRecommendationScore(
                network, userId, candidateId, rec);

            recommendations.push_back(rec);
        }

        // Step 4: Sort by score and return top N
        std::sort(recommendations.begin(), recommendations.end(),
                 [](const Recommendation& a, const Recommendation& b) {
                     return a.score > b.score;
                 });

        if (recommendations.size() > static_cast<size_t>(maxRecommendations)) {
            recommendations.resize(maxRecommendations);
        }

        return recommendations;
    }

    // Advanced: Recommend based on network position
    static std::vector<Recommendation> recommendBridgeConnections(
        const SocialNetwork& network,
        const std::string& userId) {

        // Find users who would connect disparate parts of the user's network
        // These are "bridge" connections that increase network diversity

        const auto& graph = network.getGraph();
        auto friends = getDirectFriends(graph, userId);

        // Find communities among friends
        std::vector<std::vector<std::string>> friendCommunities = 
            identifyFriendClusters(graph, friends);

        std::vector<Recommendation> bridges;

        // For each community, find connectors to other communities
        for (size_t i = 0; i < friendCommunities.size(); ++i) {
            for (size_t j = i + 1; j < friendCommunities.size(); ++j) {
                auto bridgeCandidates = findBridgeUsers(
                    graph, 
                    friendCommunities[i], 
                    friendCommunities[j]
                );

                for (const auto& candidateId : bridgeCandidates) {
                    if (candidateId != userId && 
                        !isDirectFriend(friends, candidateId)) {

                        Recommendation rec;
                        rec.userId = candidateId;
                        try {
                            rec.userName = network.getUser(candidateId).name;
                            rec.score = 80.0; // Bridge connections are valuable
                            bridges.push_back(rec);
                        } catch (...) {}
                    }
                }
            }
        }

        return bridges;
    }

private:
    static std::vector<std::string> getDirectFriends(
        const CXXGraph::Graph<std::string>& graph,
        const std::string& userId) {

        std::vector<std::string> friends;
        CXXGraph::Node<std::string> userNode(userId, userId);

        auto bfsResult = graph.breadth_first_search(userNode);

        for (const auto& nodeId : bfsResult) {
            if (nodeId != userId) {
                friends.push_back(nodeId);
            }
        }

        return friends;
    }

    static bool isDirectFriend(const std::vector<std::string>& friends, 
                              const std::string& userId) {
        return std::find(friends.begin(), friends.end(), userId) != friends.end();
    }

    static double calculateRecommendationScore(
        const SocialNetwork& network,
        const std::string& userId,
        const std::string& candidateId,
        const Recommendation& rec) {

        double score = 0.0;

        // Factor 1: Mutual friends (strongest signal)
        score += rec.mutualFriends * 10.0;

        // Factor 2: Graph distance (closer is better)
        score += std::max(0.0, 20.0 - rec.socialDistance * 5.0);

        // Factor 3: Similar network size (people prefer similar-sized networks)
        try {
            const auto& user = network.getUser(userId);
            const auto& candidate = network.getUser(candidateId);

            int followerDiff = std::abs(
                user.followerCount - candidate.followerCount);
            double similarityBonus = std::max(0.0, 10.0 - followerDiff / 100.0);
            score += similarityBonus;
        } catch (...) {}

        // Factor 4: Common interests (if available)
        score += rec.commonInterests * 5.0;

        // Factor 5: Recency bonus (newer users might need more connections)
        try {
            const auto& candidate = network.getUser(candidateId);
            long long accountAge = std::time(nullptr) - candidate.joinedTimestamp;
            if (accountAge < 30 * 24 * 3600) { // Less than 30 days old
                score += 5.0; // Help new users connect
            }
        } catch (...) {}

        return score;
    }

    static std::vector<std::vector<std::string>> identifyFriendClusters(
        const CXXGraph::Graph<std::string>& graph,
        const std::vector<std::string>& friends) {

        // Simplified clustering - in production, use proper community detection
        std::vector<std::vector<std::string>> clusters;
        // Implementation would use graph.connectedComponents() on subgraph
        return clusters;
    }

    static std::vector<std::string> findBridgeUsers(
        const CXXGraph::Graph<std::string>& graph,
        const std::vector<std::string>& cluster1,
        const std::vector<std::string>& cluster2) {

        std::vector<std::string> bridges;
        // Find users connected to both clusters
        return bridges;
    }
};
Enter fullscreen mode Exit fullscreen mode

Algorithm Breakdown:

  1. Mutual Friends: Primary signal - people with many mutual connections
  2. Social Distance: Prefer closer connections in the graph
  3. Network Similarity: People with similar-sized networks often connect
  4. Bridge Detection: Advanced feature to diversify user networks

Step 4: Influence Detection - Finding Key Players

Every network has influencers. Let's identify them scientifically:

class InfluenceAnalyzer {
public:
    struct InfluenceMetrics {
        std::string userId;
        std::string userName;

        // Basic metrics
        int directConnections;
        int totalReach;          // Total users reachable

        // Advanced metrics
        double centralityScore;   // Betweenness centrality
        double pageRank;         // Google's algorithm adapted for social
        int bridgingScore;       // Connects different communities

        // Composite score
        double overallInfluence;

        std::string getInfluenceLevel() const {
            if (overallInfluence > 90) return "Top Influencer";
            if (overallInfluence > 75) return "Key Opinion Leader";
            if (overallInfluence > 50) return "Active Connector";
            if (overallInfluence > 25) return "Engaged User";
            return "Casual User";
        }
    };

    static std::vector<InfluenceMetrics> analyzeInfluence(
        const SocialNetwork& network,
        int topN = 20) {

        const auto& graph = network.getGraph();
        auto allUsers = network.getAllUserIds();

        std::vector<InfluenceMetrics> allMetrics;
        allMetrics.reserve(allUsers.size());

        std::cout << "Analyzing influence for " << allUsers.size() << " users...\n";

        for (const auto& userId : allUsers) {
            InfluenceMetrics metrics;
            metrics.userId = userId;

            try {
                metrics.userName = network.getUser(userId).name;
            } catch (...) {
                continue;
            }

            // Calculate metrics
            CXXGraph::Node<std::string> userNode(userId, userId);

            // Direct connections (immediate reach)
            auto neighbors = graph.breadth_first_search(userNode);
            metrics.directConnections = neighbors.size() - 1; // Exclude self

            // Total reach (all users accessible)
            metrics.totalReach = neighbors.size();

            // Centrality (how often user is on shortest paths between others)
            metrics.centralityScore = calculateBetweennessCentrality(
                graph, userId, allUsers);

            // PageRank (iterative importance calculation)
            metrics.pageRank = calculateSimplifiedPageRank(
                graph, userId, allUsers);

            // Bridging score (connects different communities)
            metrics.bridgingScore = calculateBridgingScore(
                graph, userId);

            // Overall influence (weighted combination)
            metrics.overallInfluence = 
                metrics.directConnections * 0.2 +
                metrics.totalReach * 0.15 +
                metrics.centralityScore * 0.25 +
                metrics.pageRank * 0.25 +
                metrics.bridgingScore * 0.15;

            allMetrics.push_back(metrics);
        }

        // Sort by influence
        std::sort(allMetrics.begin(), allMetrics.end(),
                 [](const InfluenceMetrics& a, const InfluenceMetrics& b) {
                     return a.overallInfluence > b.overallInfluence;
                 });

        if (allMetrics.size() > static_cast<size_t>(topN)) {
            allMetrics.resize(topN);
        }

        return allMetrics;
    }

    // Calculate how many users can be reached within N hops
    static int calculateReach(
        const CXXGraph::Graph<std::string>& graph,
        const std::string& userId,
        int maxHops) {

        std::unordered_set<std::string> reached;
        std::queue<std::pair<std::string, int>> queue;

        queue.push({userId, 0});
        reached.insert(userId);

        while (!queue.empty()) {
            auto [currentId, depth] = queue.front();
            queue.pop();

            if (depth >= maxHops) continue;

            CXXGraph::Node<std::string> node(currentId, currentId);
            auto neighbors = graph.breadth_first_search(node);

            for (const auto& neighborId : neighbors) {
                if (reached.find(neighborId) == reached.end()) {
                    reached.insert(neighborId);
                    queue.push({neighborId, depth + 1});
                }
            }
        }

        return reached.size() - 1; // Exclude self
    }

    // Find users who would maximize spread (greedy algorithm)
    static std::vector<std::string> findOptimalInfluencers(
        const SocialNetwork& network,
        int count) {

        const auto& graph = network.getGraph();
        auto allUsers = network.getAllUserIds();

        std::vector<std::string> selected;
        std::unordered_set<std::string> covered;

        for (int i = 0; i < count; ++i) {
            std::string bestUser;
            int maxNewReach = 0;

            // Greedy: pick user who reaches most uncovered users
            for (const auto& userId : allUsers) {
                if (std::find(selected.begin(), selected.end(), userId) != selected.end()) {
                    continue; // Already selected
                }

                CXXGraph::Node<std::string> node(userId, userId);
                auto reachable = graph.breadth_first_search(node);

                int newReach = 0;
                for (const auto& reachedId : reachable) {
                    if (covered.find(reachedId) == covered.end()) {
                        newReach++;
                    }
                }

                if (newReach > maxNewReach) {
                    maxNewReach = newReach;
                    bestUser = userId;
                }
            }

            if (!bestUser.empty()) {
                selected.push_back(bestUser);

                // Mark all reachable users as covered
                CXXGraph::Node<std::string> node(bestUser, bestUser);
                auto reachable = graph.breadth_first_search(node);
                for (const auto& reachedId : reachable) {
                    covered.insert(reachedId);
                }
            }
        }

        return selected;
    }

private:
    static double calculateBetweennessCentrality(
        const CXXGraph::Graph<std::string>& graph,
        const std::string& userId,
        const std::vector<std::string>& allUsers) {

        // Simplified betweenness centrality
        // Full calculation: count shortest paths through this node

        double centrality = 0.0;
        int sampleSize = std::min(50, static_cast<int>(allUsers.size()));

        for (int i = 0; i < sampleSize; ++i) {
            for (int j = i + 1; j < sampleSize; ++j) {
                if (i >= static_cast<int>(allUsers.size()) || 
                    j >= static_cast<int>(allUsers.size())) break;

                const auto& source = allUsers[i];
                const auto& target = allUsers[j];

                if (source == userId || target == userId) continue;

                CXXGraph::Node<std::string> srcNode(source, source);
                CXXGraph::Node<std::string> tgtNode(target, target);

                auto result = graph.dijkstra(srcNode, tgtNode);

                if (result.success) {
                    // Check if userId is on the path
                    for (const auto& nodeOnPath : result.path) {
                        if (nodeOnPath == userId) {
                            centrality += 1.0;
                            break;
                        }
                    }
                }
            }
        }

        // Normalize
        if (sampleSize > 2) {
            centrality = (centrality * 100.0) / (sampleSize * (sampleSize - 1) / 2);
        }

        return centrality;
    }

    static double calculateSimplifiedPageRank(
        const CXXGraph::Graph<std::string>& graph,
        const std::string& userId,
        const std::vector<std::string>& allUsers) {

        // Simplified PageRank: importance based on connections to important nodes
        // Real PageRank requires iterative computation

        CXXGraph::Node<std::string> userNode(userId, userId);
        auto neighbors = graph.breadth_first_search(userNode);

        double rank = static_cast<double>(neighbors.size());

        // Bonus for being connected to well-connected users
        for (const auto& neighborId : neighbors) {
            if (neighborId == userId) continue;

            CXXGraph::Node<std::string> neighborNode(neighborId, neighborId);
            auto secondOrder = graph.breadth_first_search(neighborNode);
            rank += secondOrder.size() * 0.1;  // Damping factor
        }

        return rank;
    }

    static int calculateBridgingScore(
        const CXXGraph::Graph<std::string>& graph,
        const std::string& userId) {

        // Users who connect otherwise disconnected communities
        // Use articulation points or similar analysis

        auto articulationPoints = graph.tarjan();

        for (const auto& point : articulationPoints) {
            if (point == userId) {
                return 100; // This user is a critical bridge
            }
        }

        return 0;
    }
};
Enter fullscreen mode Exit fullscreen mode

Key Metrics Explained:

  • Betweenness Centrality: How often a user lies on shortest paths between others
  • PageRank: Recursive importance (important people connected to other important people)
  • Bridging Score: Connects disparate communities (articulation points)

Step 5: Community Detection - Finding Natural Groups

Social networks naturally form clusters - friend groups, interest communities, professional circles. Let's detect them:

class CommunityDetector {
public:
    struct Community {
        std::string id;
        std::vector<std::string> members;
        double cohesion;        // How tightly connected (0-1)
        double isolation;       // How separate from other communities
        std::string theme;      // Identified topic/interest

        // Community characteristics
        int internalEdges;      // Connections within community
        int externalEdges;      // Connections to outside

        double getModularity() const {
            // Measure of community quality
            int totalEdges = internalEdges + externalEdges;
            if (totalEdges == 0) return 0.0;
            return static_cast<double>(internalEdges) / totalEdges;
        }

        std::string getQualityRating() const {
            if (cohesion > 0.8) return "Very Strong Community";
            if (cohesion > 0.6) return "Strong Community";
            if (cohesion > 0.4) return "Moderate Community";
            return "Loose Association";
        }
    };

    static std::vector<Community> detectCommunities(
        const SocialNetwork& network) {

        const auto& graph = network.getGraph();

        std::cout << "πŸ” Detecting communities in network...\n";

        // Use connected components for basic community detection
        auto components = graph.connectedComponents();

        std::vector<Community> communities;
        int communityId = 1;

        for (const auto& component : components) {
            if (component.size() < 3) continue; // Skip tiny groups

            Community comm;
            comm.id = "community_" + std::to_string(communityId++);
            comm.members = component;

            // Calculate cohesion (how connected members are to each other)
            comm.cohesion = calculateCohesion(graph, component);

            // Calculate isolation (how separate from rest of network)
            comm.isolation = calculateIsolation(graph, component, 
                                               network.getAllUserIds());

            // Count internal vs external edges
            auto edgeCounts = countEdges(graph, component);
            comm.internalEdges = edgeCounts.first;
            comm.externalEdges = edgeCounts.second;

            // Identify theme (in real system, analyze user profiles/interests)
            comm.theme = identifyTheme(network, component);

            communities.push_back(comm);
        }

        // Sort by size
        std::sort(communities.begin(), communities.end(),
                 [](const Community& a, const Community& b) {
                     return a.members.size() > b.members.size();
                 });

        std::cout << "βœ“ Found " << communities.size() << " communities\n";

        return communities;
    }

    // Find tight-knit friend groups (cliques)
    static std::vector<std::vector<std::string>> findCliques(
        const SocialNetwork& network,
        int minSize = 3) {

        const auto& graph = network.getGraph();

        std::cout << "πŸ” Finding cliques (fully connected groups)...\n";

        // Use Bron-Kerbosch algorithm for maximal cliques
        auto allCliques = graph.bronKerbosch();

        // Filter by minimum size
        std::vector<std::vector<std::string>> cliques;
        for (const auto& clique : allCliques) {
            if (clique.size() >= static_cast<size_t>(minSize)) {
                cliques.push_back(clique);
            }
        }

        std::cout << "βœ“ Found " << cliques.size() << " cliques\n";

        return cliques;
    }

    // Find overlapping communities (users can be in multiple)
    static std::unordered_map<std::string, std::vector<std::string>> 
    findOverlappingCommunities(const SocialNetwork& network) {

        const auto& graph = network.getGraph();
        auto allUsers = network.getAllUserIds();

        std::unordered_map<std::string, std::vector<std::string>> userCommunities;

        // For each user, identify which communities they participate in
        for (const auto& userId : allUsers) {
            CXXGraph::Node<std::string> node(userId, userId);
            auto neighbors = graph.breadth_first_search(node);

            // Analyze neighbor clusters
            auto neighborGroups = identifyNeighborClusters(graph, neighbors);

            userCommunities[userId] = neighborGroups;
        }

        return userCommunities;
    }

    // Recommend communities for a user to join
    static std::vector<Community> recommendCommunities(
        const SocialNetwork& network,
        const std::string& userId,
        const std::vector<Community>& existingCommunities) {

        std::vector<Community> recommendations;

        const auto& graph = network.getGraph();
        CXXGraph::Node<std::string> userNode(userId, userId);
        auto userFriends = graph.breadth_first_search(userNode);

        for (const auto& community : existingCommunities) {
            // Check if user is already in community
            if (std::find(community.members.begin(), 
                         community.members.end(), 
                         userId) != community.members.end()) {
                continue;
            }

            // Count mutual friends in community
            int friendsInCommunity = 0;
            for (const auto& friendId : userFriends) {
                if (std::find(community.members.begin(), 
                             community.members.end(), 
                             friendId) != community.members.end()) {
                    friendsInCommunity++;
                }
            }

            // Recommend if user has multiple friends in community
            if (friendsInCommunity >= 3) {
                recommendations.push_back(community);
            }
        }

        // Sort by number of friends in community
        std::sort(recommendations.begin(), recommendations.end(),
                 [&userFriends](const Community& a, const Community& b) {
                     int aCount = 0, bCount = 0;
                     for (const auto& friendId : userFriends) {
                         if (std::find(a.members.begin(), a.members.end(), 
                                      friendId) != a.members.end()) aCount++;
                         if (std::find(b.members.begin(), b.members.end(), 
                                      friendId) != b.members.end()) bCount++;
                     }
                     return aCount > bCount;
                 });

        return recommendations;
    }

private:
    static double calculateCohesion(
        const CXXGraph::Graph<std::string>& graph,
        const std::vector<std::string>& members) {

        if (members.size() <= 1) return 1.0;

        // Calculate density: actual edges / possible edges
        int maxPossibleEdges = members.size() * (members.size() - 1) / 2;
        int actualEdges = 0;

        for (size_t i = 0; i < members.size(); ++i) {
            for (size_t j = i + 1; j < members.size(); ++j) {
                CXXGraph::Node<std::string> node1(members[i], members[i]);
                CXXGraph::Node<std::string> node2(members[j], members[j]);

                auto result = graph.dijkstra(node1, node2);
                if (result.success && result.path.size() == 2) {
                    // Direct connection exists
                    actualEdges++;
                }
            }
        }

        return static_cast<double>(actualEdges) / maxPossibleEdges;
    }

    static double calculateIsolation(
        const CXXGraph::Graph<std::string>& graph,
        const std::vector<std::string>& members,
        const std::vector<std::string>& allUsers) {

        int internalConnections = 0;
        int externalConnections = 0;

        for (const auto& memberId : members) {
            CXXGraph::Node<std::string> node(memberId, memberId);
            auto neighbors = graph.breadth_first_search(node);

            for (const auto& neighborId : neighbors) {
                if (neighborId == memberId) continue;

                bool isInternal = std::find(members.begin(), members.end(), 
                                          neighborId) != members.end();
                if (isInternal) {
                    internalConnections++;
                } else {
                    externalConnections++;
                }
            }
        }

        int totalConnections = internalConnections + externalConnections;
        if (totalConnections == 0) return 0.0;

        return static_cast<double>(internalConnections) / totalConnections;
    }

    static std::pair<int, int> countEdges(
        const CXXGraph::Graph<std::string>& graph,
        const std::vector<std::string>& members) {

        int internal = 0;
        int external = 0;

        for (const auto& memberId : members) {
            CXXGraph::Node<std::string> node(memberId, memberId);
            auto neighbors = graph.breadth_first_search(node);

            for (const auto& neighborId : neighbors) {
                if (neighborId == memberId) continue;

                bool isInternal = std::find(members.begin(), members.end(), 
                                          neighborId) != members.end();
                if (isInternal) {
                    internal++;
                } else {
                    external++;
                }
            }
        }

        return {internal / 2, external}; // Divide internal by 2 (counted twice)
    }

    static std::string identifyTheme(
        const SocialNetwork& network,
        const std::vector<std::string>& members) {

        // In real system: analyze user profiles, shared hashtags, 
        // common groups, interaction patterns

        if (members.size() > 100) return "Large Network";
        if (members.size() > 50) return "Active Community";
        if (members.size() > 20) return "Friend Circle";
        return "Small Group";
    }

    static std::vector<std::string> identifyNeighborClusters(
        const CXXGraph::Graph<std::string>& graph,
        const std::vector<std::string>& neighbors) {

        // Simplified - identify distinct groups among neighbors
        std::vector<std::string> clusters;
        // Real implementation would use sub-graph clustering
        return clusters;
    }
};
Enter fullscreen mode Exit fullscreen mode

Step 6: Virality Prediction - Content Spread Simulation

Predict how content will spread through the network:

class ViralityPredictor {
public:
    struct ViralityScore {
        double expectedReach;      // Number of users expected to see it
        double spreadVelocity;     // How fast it spreads (users/hour)
        double persistence;        // How long it stays relevant (hours)
        double engagementRate;     // Expected likes/shares ratio
        double overallScore;       // Combined metric (0-100)

        std::string getViralityLevel() const {
            if (overallScore > 80) return "πŸ”₯ Highly Viral";
            if (overallScore > 60) return "⚑ Strong Potential";
            if (overallScore > 40) return "πŸ“ˆ Moderate Spread";
            if (overallScore > 20) return "πŸ“Š Limited Reach";
            return "πŸ’€ Minimal Impact";
        }
    };

    static ViralityScore predictVirality(
        const SocialNetwork& network,
        const std::string& originUserId,
        double contentQuality = 0.5,    // 0-1 scale
        double shareability = 0.5) {    // 0-1 scale

        const auto& graph = network.getGraph();
        ViralityScore score;

        std::cout << "πŸ“Š Analyzing viral potential...\n";

        // Factor 1: Origin user's influence
        auto influenceMetrics = InfluenceAnalyzer::analyzeInfluence(network, 100);
        double userInfluence = 0.0;

        for (const auto& metric : influenceMetrics) {
            if (metric.userId == originUserId) {
                userInfluence = metric.overallInfluence;
                break;
            }
        }

        // Factor 2: Network reach potential
        int maxReach = InfluenceAnalyzer::calculateReach(graph, originUserId, 5);
        score.expectedReach = maxReach * contentQuality * shareability;

        // Factor 3: Spread velocity (based on network density)
        CXXGraph::Node<std::string> originNode(originUserId, originUserId);
        auto immediateReach = graph.breadth_first_search(originNode);
        double networkDensity = static_cast<double>(immediateReach.size()) / 
                               network.getUserCount();

        score.spreadVelocity = userInfluence * networkDensity * 
                              shareability * 100.0;

        // Factor 4: Content persistence
        score.persistence = contentQuality * 48.0; // Hours content stays relevant

        // Factor 5: Engagement rate estimation
        score.engagementRate = (contentQuality + shareability) / 2.0;

        // Calculate overall virality score
        score.overallScore = 
            (score.expectedReach / network.getUserCount()) * 30.0 +
            std::min(100.0, score.spreadVelocity) * 0.3 +
            (score.persistence / 48.0) * 20.0 +
            score.engagementRate * 20.0;

        std::cout << "βœ“ Analysis complete\n";

        return score;
    }

    // Simulate actual spread using infection model
    static std::vector<int> simulateSpread(
        const SocialNetwork& network,
        const std::string& originUserId,
        int timeSteps = 24,              // Hours
        double spreadProbability = 0.3,  // Chance of sharing
        double decayRate = 0.1) {        // Content relevance decay

        const auto& graph = network.getGraph();
        std::vector<int> spreadCount(timeSteps);

        std::unordered_set<std::string> exposed;
        std::unordered_set<std::string> newlyExposed;

        exposed.insert(originUserId);
        newlyExposed.insert(originUserId);
        spreadCount[0] = 1;

        double currentRelevance = 1.0;

        for (int t = 1; t < timeSteps; ++t) {
            std::unordered_set<std::string> nextExposed;

            // Decay content relevance over time
            currentRelevance *= (1.0 - decayRate);

            // Each newly exposed user can spread to their network
            for (const auto& userId : newlyExposed) {
                CXXGraph::Node<std::string> node(userId, userId);
                auto neighbors = graph.breadth_first_search(node);

                for (const auto& neighborId : neighbors) {
                    if (exposed.find(neighborId) == exposed.end()) {
                        // Probabilistic spread with decay
                        double effectiveProbability = 
                            spreadProbability * currentRelevance;

                        double roll = static_cast<double>(rand()) / RAND_MAX;
                        if (roll < effectiveProbability) {
                            nextExposed.insert(neighborId);
                            exposed.insert(neighborId);
                        }
                    }
                }
            }

            newlyExposed = nextExposed;
            spreadCount[t] = exposed.size();

            // Stop if no new spread
            if (nextExposed.empty()) {
                for (int remaining = t + 1; remaining < timeSteps; ++remaining) {
                    spreadCount[remaining] = exposed.size();
                }
                break;
            }
        }

        return spreadCount;
    }

    // Find optimal users to target for maximum viral spread
    static std::vector<std::string> findViralSeeds(
        const SocialNetwork& network,
        int seedCount = 5) {

        std::cout << "🎯 Finding optimal viral seeds...\n";

        // Use greedy algorithm: pick users with maximum marginal reach
        return InfluenceAnalyzer::findOptimalInfluencers(network, seedCount);
    }

    // Predict cascade patterns
    struct CascadePattern {
        std::vector<std::vector<std::string>> waves;  // Users exposed in each wave
        int depth;                                     // How many hops
        double growthRate;                            // Exponential growth factor

        std::string getPatternType() const {
            if (growthRate > 2.0) return "Explosive Growth";
            if (growthRate > 1.5) return "Viral Cascade";
            if (growthRate > 1.0) return "Steady Spread";
            return "Limited Diffusion";
        }
    };

    static CascadePattern predictCascade(
        const SocialNetwork& network,
        const std::string& originUserId,
        int maxDepth = 5) {

        const auto& graph = network.getGraph();
        CascadePattern pattern;

        std::unordered_set<std::string> visited;
        std::vector<std::string> currentWave = {originUserId};
        visited.insert(originUserId);

        for (int depth = 0; depth < maxDepth && !currentWave.empty(); ++depth) {
            pattern.waves.push_back(currentWave);
            std::vector<std::string> nextWave;

            for (const auto& userId : currentWave) {
                CXXGraph::Node<std::string> node(userId, userId);
                auto neighbors = graph.breadth_first_search(node);

                for (const auto& neighborId : neighbors) {
                    if (visited.find(neighborId) == visited.end()) {
                        nextWave.push_back(neighborId);
                        visited.insert(neighborId);
                    }
                }
            }

            currentWave = nextWave;
        }

        pattern.depth = pattern.waves.size();

        // Calculate growth rate
        if (pattern.waves.size() >= 2) {
            double totalGrowth = 0.0;
            int growthSamples = 0;

            for (size_t i = 1; i < pattern.waves.size(); ++i) {
                if (pattern.waves[i-1].size() > 0) {
                    double waveGrowth = static_cast<double>(pattern.waves[i].size()) / 
                                       pattern.waves[i-1].size();
                    totalGrowth += waveGrowth;
                    growthSamples++;
                }
            }

            pattern.growthRate = growthSamples > 0 ? totalGrowth / growthSamples : 1.0;
        } else {
            pattern.growthRate = 1.0;
        }

        return pattern;
    }
};
Enter fullscreen mode Exit fullscreen mode

Step 7: Complete Analytics Dashboard

Now let's put it all together in a comprehensive dashboard:

class SocialNetworkDashboard {
public:
    SocialNetworkDashboard(SocialNetwork& network) : network_(network) {}

    void generateFullReport(const std::string& targetUserId) {
        printHeader();
        displayUserProfile(targetUserId);
        displayNetworkOverview();
        displayFriendRecommendations(targetUserId);
        displayInfluenceMetrics(targetUserId);
        displayCommunities(targetUserId);
        predictContentVirality(targetUserId);
        displayHealthMetrics();
        printFooter();
    }

private:
    SocialNetwork& network_;

    void printHeader() {
        std::cout << "\n";
        std::cout << "╔═══════════════════════════════════════════════╗\n";
        std::cout << "β•‘   SOCIAL NETWORK ANALYTICS DASHBOARD         β•‘\n";
        std::cout << "β•‘   Powered by CXXGraph                         β•‘\n";
        std::cout << "β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\n\n";
    }

    void displayUserProfile(const std::string& userId) {
        std::cout << "πŸ‘€ USER PROFILE\n";
        std::cout << "   ═══════════════\n";

        try {
            const auto& user = network_.getUser(userId);
            std::cout << "   Name: " << user.name << "\n";
            std::cout << "   ID: " << user.id << "\n";
            std::cout << "   Followers: " << user.followerCount << "\n";
            std::cout << "   Following: " << user.followingCount << "\n\n";
        } catch (...) {
            std::cout << "   ⚠️  User not found\n\n";
        }
    }

    void displayNetworkOverview() {
        std::cout << "🌐 NETWORK OVERVIEW\n";
        std::cout << "   ══════════════════\n";
        std::cout << "   Total Users: " << network_.getUserCount() << "\n";
        std::cout << "   Total Connections: " << network_.getConnectionCount() << "\n";

        // Calculate network density
        size_t userCount = network_.getUserCount();
        size_t maxConnections = userCount * (userCount - 1) / 2;
        double density = maxConnections > 0 ? 
            static_cast<double>(network_.getConnectionCount()) / maxConnections * 100.0 : 0.0;

        std::cout << "   Network Density: " << std::fixed 
                  << std::setprecision(2) << density << "%\n\n";
    }

    void displayFriendRecommendations(const std::string& userId) {
        std::cout << "🀝 FRIEND RECOMMENDATIONS\n";
        std::cout << "   ═══════════════════════\n";

        auto recommendations = FriendRecommender::recommendFriends(
            network_, userId, 5);

        if (recommendations.empty()) {
            std::cout << "   No recommendations available\n\n";
            return;
        }

        for (size_t i = 0; i < recommendations.size(); ++i) {
            const auto& rec = recommendations[i];
            std::cout << "   " << (i + 1) << ". " << rec.userName << "\n";
            std::cout << "      " << rec.getReason() << "\n";
            std::cout << "      Score: " << std::fixed 
                     << std::setprecision(1) << rec.score << "/100\n";
            if (i < recommendations.size() - 1) std::cout << "\n";
        }
        std::cout << "\n";
    }

    void displayInfluenceMetrics(const std::string& userId) {
        std::cout << "⭐ YOUR INFLUENCE\n";
        std::cout << "   ═══════════════\n";

        auto allInfluencers = InfluenceAnalyzer::analyzeInfluence(network_, 100);

        // Find user's rank
        size_t userRank = 0;
        const InfluenceAnalyzer::InfluenceMetrics* userMetrics = nullptr;

        for (size_t i = 0; i < allInfluencers.size(); ++i) {
            if (allInfluencers[i].userId == userId) {
                userRank = i + 1;
                userMetrics = &allInfluencers[i];
                break;
            }
        }

        if (userMetrics) {
            std::cout << "   Influence Rank: #" << userRank 
                     << " of " << network_.getUserCount() << "\n";
            std::cout << "   Level: " << userMetrics->getInfluenceLevel() << "\n";
            std::cout << "   Direct Connections: " << userMetrics->directConnections << "\n";
            std::cout << "   Total Reach: " << userMetrics->totalReach << " users\n";
            std::cout << "   Influence Score: " << std::fixed 
                     << std::setprecision(1) << userMetrics->overallInfluence << "/100\n";
        } else {
            std::cout << "   Could not calculate influence metrics\n";
        }
        std::cout << "\n";

        // Show top influencers
        std::cout << "   πŸ“Š Top 5 Influencers in Network:\n";
        for (size_t i = 0; i < std::min(size_t(5), allInfluencers.size()); ++i) {
            const auto& inf = allInfluencers[i];
            std::cout << "   " << (i + 1) << ". " << inf.userName 
                     << " (" << std::fixed << std::setprecision(1) 
                     << inf.overallInfluence << ")\n";
        }
        std::cout << "\n";
    }

    void displayCommunities(const std::string& userId) {
        std::cout << "πŸ‘₯ COMMUNITY ANALYSIS\n";
        std::cout << "   ══════════════════\n";

        auto communities = CommunityDetector::detectCommunities(network_);

        std::cout << "   Total Communities: " << communities.size() << "\n\n";

        // Show user's communities
        std::vector<CommunityDetector::Community> userCommunities;
        for (const auto& comm : communities) {
            if (std::find(comm.members.begin(), comm.members.end(), userId) 
                != comm.members.end()) {
                userCommunities.push_back(comm);
            }
        }

        if (!userCommunities.empty()) {
            std::cout << "   Your Communities (" << userCommunities.size() << "):\n";
            for (const auto& comm : userCommunities) {
                std::cout << "   β€’ " << comm.theme << "\n";
                std::cout << "     Members: " << comm.members.size() << "\n";
                std::cout << "     Cohesion: " << std::fixed 
                         << std::setprecision(0) << (comm.cohesion * 100) << "%\n";
                std::cout << "     Quality: " << comm.getQualityRating() << "\n\n";
            }
        }

        // Show largest communities
        std::cout << "   Largest Communities in Network:\n";
        for (size_t i = 0; i < std::min(size_t(3), communities.size()); ++i) {
            const auto& comm = communities[i];
            std::cout << "   " << (i + 1) << ". " << comm.theme 
                     << " (" << comm.members.size() << " members)\n";
        }
        std::cout << "\n";
    }

    void predictContentVirality(const std::string& userId) {
        std::cout << "πŸ“Š VIRALITY PREDICTION\n";
        std::cout << "   ═══════════════════\n";

        // Predict for high-quality content
        auto score = ViralityPredictor::predictVirality(
            network_, userId, 0.8, 0.7);

        std::cout << "   If you post high-quality content:\n\n";
        std::cout << "   Expected Reach: " << std::fixed 
                 << std::setprecision(0) << score.expectedReach << " users\n";
        std::cout << "   Spread Velocity: " << std::fixed 
                 << std::setprecision(1) << score.spreadVelocity << " users/hour\n";
        std::cout << "   Content Lifespan: " << std::fixed 
                 << std::setprecision(1) << score.persistence << " hours\n";
        std::cout << "   Engagement Rate: " << std::fixed 
                 << std::setprecision(0) << (score.engagementRate * 100) << "%\n\n";
        std::cout << "   Virality Level: " << score.getViralityLevel() << "\n";
        std::cout << "   Overall Score: " << std::fixed 
                 << std::setprecision(1) << score.overallScore << "/100\n\n";
    }

    void displayHealthMetrics() {
        std::cout << "πŸ₯ NETWORK HEALTH\n";
        std::cout << "   ══════════════════\n";

        const auto& graph = network_.getGraph();

        // Check connectivity
        bool connected = graph.isConnectedGraph();
        std::cout << "   Connectivity: " 
                  << (connected ? "βœ“ Fully Connected" : "⚠️  Fragmented") << "\n";

        if (!connected) {
            auto components = graph.connectedComponents();
            std::cout << "   Isolated Segments: " << components.size() << "\n";
        }

        // Find critical users (articulation points)
        auto critical = graph.tarjan();
        std::cout << "   Critical Users: " << critical.size();
        if (critical.size() > 0) {
            std::cout << " ⚠️  (Network vulnerable to these users leaving)";
        }
        std::cout << "\n\n";

        // Health score
        double healthScore = 100.0;
        if (!connected) healthScore -= 30.0;
        healthScore -= critical.size() * 2.0;  // Penalty for critical nodes
        healthScore = std::max(0.0, healthScore);

        std::cout << "   Overall Health Score: " << std::fixed 
                 << std::setprecision(1) << healthScore << "/100\n";

        if (healthScore < 70.0) {
            std::cout << "   πŸ’‘ Recommendation: Encourage more connections\n";
            std::cout << "      to improve network resilience\n";
        }
        std::cout << "\n";
    }

    void printFooter() {
        std::cout << "═══════════════════════════════════════════════\n";
        std::cout << "Report generated by CXXGraph Social Analytics\n";
        std::cout << "═══════════════════════════════════════════════\n\n";
    }
};
Enter fullscreen mode Exit fullscreen mode

Step 8: Real-World Production Example

Let's build a complete working example that demonstrates everything:

#include "CXXGraph/CXXGraph.hpp"
#include <iostream>
#include <iomanip>
#include <random>

// [Include all classes above: SocialNetwork, FriendRecommender, 
//  InfluenceAnalyzer, CommunityDetector, ViralityPredictor, 
//  SocialNetworkDashboard]

// Helper function to generate realistic test data
class NetworkGenerator {
public:
    static void populateTestNetwork(SocialNetwork& network, int userCount = 50) {
        std::cout << "πŸ”§ Generating test network with " << userCount << " users...\n";

        // Create users with realistic names
        std::vector<std::string> firstNames = {
            "Alice", "Bob", "Carol", "David", "Eve", "Frank", "Grace", 
            "Henry", "Iris", "Jack", "Kate", "Leo", "Mary", "Noah", 
            "Olivia", "Paul", "Quinn", "Rachel", "Steve", "Tina"
        };

        std::vector<std::string> lastNames = {
            "Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia",
            "Miller", "Davis", "Rodriguez", "Martinez"
        };

        std::vector<std::string> userIds;

        // Generate users
        for (int i = 0; i < userCount; ++i) {
            std::string firstName = firstNames[i % firstNames.size()];
            std::string lastName = lastNames[i % lastNames.size()];
            std::string userId = "user_" + std::to_string(i + 1);

            User user(userId, firstName + " " + lastName);
            user.joinedTimestamp = std::time(nullptr) - (rand() % (365 * 24 * 3600));
            network.addUser(user);
            userIds.push_back(userId);
        }

        std::cout << "βœ“ Created " << userCount << " users\n";

        // Create realistic connection patterns
        std::cout << "πŸ”— Generating connections...\n";

        // Pattern 1: Dense clusters (friend groups)
        int clusterSize = 7;
        for (int cluster = 0; cluster < userCount / clusterSize; ++cluster) {
            int baseIdx = cluster * clusterSize;

            // Connect everyone in cluster to each other
            for (int i = 0; i < clusterSize && baseIdx + i < userCount; ++i) {
                for (int j = i + 1; j < clusterSize && baseIdx + j < userCount; ++j) {
                    int strength = 5 + (rand() % 4); // 5-8 strength
                    network.addFriendship(
                        userIds[baseIdx + i], 
                        userIds[baseIdx + j], 
                        strength
                    );
                }
            }
        }

        // Pattern 2: Inter-cluster bridges (weak ties)
        for (int i = 0; i < userCount - clusterSize; i += clusterSize) {
            int j = i + clusterSize;
            if (j < userCount) {
                network.addFriendship(userIds[i], userIds[j], 3); // Weaker connection
            }
        }

        // Pattern 3: Random connections (acquaintances)
        int randomConnections = userCount / 2;
        for (int i = 0; i < randomConnections; ++i) {
            int idx1 = rand() % userCount;
            int idx2 = rand() % userCount;
            if (idx1 != idx2) {
                network.addFriendship(userIds[idx1], userIds[idx2], 2);
            }
        }

        // Pattern 4: Influencer follows (asymmetric)
        std::vector<int> influencerIndices = {0, 1, 2}; // First few users are influencers
        for (int inf : influencerIndices) {
            for (int follower = 3; follower < std::min(userCount, 15); ++follower) {
                if (rand() % 3 == 0) { // 33% chance to follow
                    network.addFollowRelation(userIds[follower], userIds[inf]);
                }
            }
        }

        std::cout << "βœ“ Created " << network.getConnectionCount() << " connections\n";
        std::cout << "βœ“ Network generation complete!\n\n";
    }

    // Simulate user interactions over time
    static void simulateInteractions(SocialNetwork& network, 
                                     const std::vector<std::string>& userIds,
                                     int interactionCount = 100) {
        std::cout << "πŸ’¬ Simulating " << interactionCount << " interactions...\n";

        for (int i = 0; i < interactionCount; ++i) {
            int idx1 = rand() % userIds.size();
            int idx2 = rand() % userIds.size();

            if (idx1 != idx2) {
                bool isMessage = rand() % 2 == 0;
                bool isShare = rand() % 3 == 0;

                network.recordInteraction(
                    userIds[idx1], 
                    userIds[idx2], 
                    isMessage, 
                    isShare
                );
            }
        }

        std::cout << "βœ“ Interactions simulated\n\n";
    }
};

// Complete demo application
int main() {
    std::srand(std::time(nullptr));

    std::cout << "\n";
    std::cout << "╔════════════════════════════════════════════════╗\n";
    std::cout << "β•‘  SOCIAL NETWORK ANALYTICS - POWERED BY CXXGRAPH β•‘\n";
    std::cout << "╔════════════════════════════════════════════════╗\n\n";

    // Create network
    SocialNetwork network;

    // Generate realistic test data
    NetworkGenerator::populateTestNetwork(network, 50);

    // Simulate some interactions
    auto userIds = network.getAllUserIds();
    NetworkGenerator::simulateInteractions(network, userIds, 100);

    // Interactive menu
    bool running = true;

    while (running) {
        std::cout << "\n";
        std::cout << "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
        std::cout << "  MAIN MENU\n";
        std::cout << "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
        std::cout << "1. Generate Full Analytics Report\n";
        std::cout << "2. Friend Recommendations\n";
        std::cout << "3. Influence Analysis\n";
        std::cout << "4. Community Detection\n";
        std::cout << "5. Virality Prediction\n";
        std::cout << "6. Network Health Check\n";
        std::cout << "7. Simulate Content Spread\n";
        std::cout << "8. Exit\n";
        std::cout << "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
        std::cout << "Choose option: ";

        int choice;
        std::cin >> choice;

        if (choice == 8) {
            running = false;
            continue;
        }

        std::string targetUser = userIds[0]; // Default to first user

        switch (choice) {
            case 1: {
                // Full report
                SocialNetworkDashboard dashboard(network);
                dashboard.generateFullReport(targetUser);
                break;
            }

            case 2: {
                // Friend recommendations
                std::cout << "\n🀝 FRIEND RECOMMENDATIONS\n";
                std::cout << "   ═══════════════════════\n\n";

                auto recs = FriendRecommender::recommendFriends(
                    network, targetUser, 10);

                for (size_t i = 0; i < recs.size(); ++i) {
                    std::cout << (i + 1) << ". " << recs[i].userName << "\n";
                    std::cout << "   " << recs[i].getReason() << "\n";
                    std::cout << "   Mutual Friends: " << recs[i].mutualFriends << "\n";
                    std::cout << "   Score: " << std::fixed << std::setprecision(1) 
                             << recs[i].score << "\n\n";
                }
                break;
            }

            case 3: {
                // Influence analysis
                std::cout << "\n⭐ TOP INFLUENCERS\n";
                std::cout << "   ═══════════════\n\n";

                auto influencers = InfluenceAnalyzer::analyzeInfluence(network, 10);

                for (size_t i = 0; i < influencers.size(); ++i) {
                    const auto& inf = influencers[i];
                    std::cout << (i + 1) << ". " << inf.userName << "\n";
                    std::cout << "   Level: " << inf.getInfluenceLevel() << "\n";
                    std::cout << "   Connections: " << inf.directConnections << "\n";
                    std::cout << "   Reach: " << inf.totalReach << " users\n";
                    std::cout << "   Influence Score: " << std::fixed 
                             << std::setprecision(1) << inf.overallInfluence << "\n\n";
                }
                break;
            }

            case 4: {
                // Community detection
                std::cout << "\nπŸ‘₯ COMMUNITY DETECTION\n";
                std::cout << "   ══════════════════\n\n";

                auto communities = CommunityDetector::detectCommunities(network);

                std::cout << "Found " << communities.size() << " communities:\n\n";

                for (size_t i = 0; i < std::min(size_t(5), communities.size()); ++i) {
                    const auto& comm = communities[i];
                    std::cout << (i + 1) << ". " << comm.theme << "\n";
                    std::cout << "   Members: " << comm.members.size() << "\n";
                    std::cout << "   Cohesion: " << std::fixed << std::setprecision(0)
                             << (comm.cohesion * 100) << "%\n";
                    std::cout << "   Quality: " << comm.getQualityRating() << "\n";
                    std::cout << "   Modularity: " << std::fixed << std::setprecision(2)
                             << comm.getModularity() << "\n\n";
                }

                // Find cliques
                auto cliques = CommunityDetector::findCliques(network, 4);
                std::cout << "Found " << cliques.size() 
                         << " tight-knit groups (4+ members)\n";
                break;
            }

            case 5: {
                // Virality prediction
                std::cout << "\nπŸ“Š VIRALITY PREDICTION\n";
                std::cout << "   ═══════════════════\n\n";

                auto score = ViralityPredictor::predictVirality(
                    network, targetUser, 0.8, 0.7);

                std::cout << "If " << network.getUser(targetUser).name 
                         << " posts quality content:\n\n";
                std::cout << "Expected Reach: " << std::fixed << std::setprecision(0)
                         << score.expectedReach << " users\n";
                std::cout << "Spread Velocity: " << std::fixed << std::setprecision(1)
                         << score.spreadVelocity << " users/hour\n";
                std::cout << "Content Lifespan: " << score.persistence << " hours\n";
                std::cout << "Engagement Rate: " << std::fixed << std::setprecision(0)
                         << (score.engagementRate * 100) << "%\n\n";
                std::cout << "Virality Level: " << score.getViralityLevel() << "\n";
                std::cout << "Overall Score: " << std::fixed << std::setprecision(1)
                         << score.overallScore << "/100\n";
                break;
            }

            case 6: {
                // Network health
                std::cout << "\nπŸ₯ NETWORK HEALTH CHECK\n";
                std::cout << "   ═══════════════════\n\n";

                const auto& graph = network.getGraph();

                bool connected = graph.isConnectedGraph();
                std::cout << "Connectivity: " 
                         << (connected ? "βœ“ Fully Connected" : "⚠️  Fragmented") << "\n";

                if (!connected) {
                    auto components = graph.connectedComponents();
                    std::cout << "Isolated Segments: " << components.size() << "\n";
                }

                auto critical = graph.tarjan();
                std::cout << "Critical Users: " << critical.size() << "\n";

                if (critical.size() > 0) {
                    std::cout << "\n⚠️  Critical users (network vulnerable if they leave):\n";
                    for (size_t i = 0; i < std::min(size_t(5), critical.size()); ++i) {
                        try {
                            std::cout << "   β€’ " << network.getUser(critical[i]).name << "\n";
                        } catch (...) {}
                    }
                }

                std::cout << "\n";
                break;
            }

            case 7: {
                // Simulate spread
                std::cout << "\nπŸ“ˆ CONTENT SPREAD SIMULATION\n";
                std::cout << "   ═══════════════════════\n\n";

                auto spreadData = ViralityPredictor::simulateSpread(
                    network, targetUser, 12, 0.3, 0.1);

                std::cout << "Hour | Users Reached | New Exposures\n";
                std::cout << "-----+---------------+--------------\n";

                for (size_t hour = 0; hour < spreadData.size(); ++hour) {
                    int newExposures = hour > 0 ? 
                        spreadData[hour] - spreadData[hour - 1] : spreadData[0];

                    std::cout << std::setw(4) << hour << " | "
                             << std::setw(13) << spreadData[hour] << " | "
                             << std::setw(12) << newExposures << "\n";
                }

                std::cout << "\nFinal Reach: " << spreadData.back() << " users\n";

                // Predict cascade pattern
                auto cascade = ViralityPredictor::predictCascade(
                    network, targetUser, 4);

                std::cout << "\nCascade Pattern: " << cascade.getPatternType() << "\n";
                std::cout << "Cascade Depth: " << cascade.depth << " waves\n";
                std::cout << "Growth Rate: " << std::fixed << std::setprecision(2)
                         << cascade.growthRate << "x per wave\n";

                std::cout << "\nWave Analysis:\n";
                for (size_t i = 0; i < cascade.waves.size(); ++i) {
                    std::cout << "Wave " << (i + 1) << ": " 
                             << cascade.waves[i].size() << " users\n";
                }

                break;
            }

            default:
                std::cout << "Invalid option. Please try again.\n";
        }

        std::cout << "\nPress Enter to continue...";
        std::cin.ignore();
        std::cin.get();
    }

    std::cout << "\n";
    std::cout << "╔════════════════════════════════════════════════╗\n";
    std::cout << "β•‘  Thank you for using CXXGraph!                  β•‘\n";
    std::cout << "β•‘  ⭐ Star us: github.com/ZigRazor/CXXGraph      β•‘\n";
    std::cout << "β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\n\n";

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Advanced Techniques and Optimizations

1. Caching for Performance

For production systems with millions of users:

class CachedSocialAnalytics {
private:
    struct CacheEntry {
        std::chrono::steady_clock::time_point timestamp;
        std::vector<FriendRecommender::Recommendation> data;
    };

    std::unordered_map<std::string, CacheEntry> recommendationCache_;
    std::chrono::seconds cacheLifetime_{3600}; // 1 hour

public:
    std::vector<FriendRecommender::Recommendation> getRecommendations(
        const SocialNetwork& network,
        const std::string& userId) {

        auto now = std::chrono::steady_clock::now();

        // Check cache
        auto it = recommendationCache_.find(userId);
        if (it != recommendationCache_.end()) {
            auto age = std::chrono::duration_cast<std::chrono::seconds>(
                now - it->second.timestamp);

            if (age < cacheLifetime_) {
                return it->second.data; // Return cached data
            }
        }

        // Cache miss or expired - compute fresh
        auto recs = FriendRecommender::recommendFriends(network, userId, 10);

        recommendationCache_[userId] = {now, recs};
        return recs;
    }

    void invalidateCache(const std::string& userId) {
        recommendationCache_.erase(userId);
    }

    void invalidateAllCaches() {
        recommendationCache_.clear();
    }
};
Enter fullscreen mode Exit fullscreen mode

2. Incremental Updates

For real-time systems, update metrics incrementally instead of recalculating everything:

class IncrementalInfluenceTracker {
private:
    std::unordered_map<std::string, double> influenceScores_;

public:
    void onNewConnection(const std::string& user1, const std::string& user2) {
        // Update both users' scores incrementally
        influenceScores_[user1] += 0.5;
        influenceScores_[user2] += 0.5;
    }

    void onInteraction(const std::string& user1, const std::string& user2,
                      double weight) {
        // Boost influence based on interaction
        influenceScores_[user1] += weight * 0.1;
        influenceScores_[user2] += weight * 0.1;
    }

    double getInfluenceScore(const std::string& userId) const {
        auto it = influenceScores_.find(userId);
        return it != influenceScores_.end() ? it->second : 0.0;
    }
};
Enter fullscreen mode Exit fullscreen mode

3. Batch Processing for Scale

Process analytics in batches during off-peak hours:

class BatchAnalyticsProcessor {
public:
    struct AnalyticsBatch {
        std::vector<std::string> userIds;
        std::chrono::steady_clock::time_point scheduledTime;

        enum class Priority {
            LOW,
            MEDIUM,
            HIGH
        } priority;
    };

    void scheduleInfluenceUpdate(const std::vector<std::string>& userIds,
                                 AnalyticsBatch::Priority priority) {
        AnalyticsBatch batch;
        batch.userIds = userIds;
        batch.scheduledTime = std::chrono::steady_clock::now();
        batch.priority = priority;

        batchQueue_.push(batch);
    }

    void processBatches(SocialNetwork& network, int maxBatchSize = 100) {
        while (!batchQueue_.empty()) {
            auto batch = batchQueue_.front();
            batchQueue_.pop();

            // Process batch
            for (size_t i = 0; i < batch.userIds.size() && i < maxBatchSize; ++i) {
                // Update analytics for this user
                auto metrics = InfluenceAnalyzer::analyzeInfluence(network, 1);
                // Store results in database/cache
            }
        }
    }

private:
    std::queue<AnalyticsBatch> batchQueue_;
};
Enter fullscreen mode Exit fullscreen mode

4. Distributed Graph Processing

For massive networks, distribute across multiple machines:

class DistributedGraphPartitioner {
public:
    struct Partition {
        std::vector<std::string> userIds;
        CXXGraph::Graph<std::string> subgraph;
        std::unordered_set<std::string> borderNodes; // Connect to other partitions
    };

    static std::vector<Partition> partitionGraph(
        const SocialNetwork& network,
        int partitionCount) {

        std::vector<Partition> partitions(partitionCount);

        // Use vertex-cut algorithm from CXXGraph
        auto cuts = network.getGraph().greedyVertexCut(partitionCount);

        for (size_t i = 0; i < cuts.size(); ++i) {
            partitions[i].userIds = cuts[i];
            // Build subgraph for this partition
            // Identify border nodes that connect to other partitions
        }

        return partitions;
    }
};
Enter fullscreen mode Exit fullscreen mode

Integration with Backend Services

REST API Wrapper

// Example using any C++ web framework (Crow, Pistache, etc.)
class SocialAnalyticsAPI {
private:
    SocialNetwork& network_;
    CachedSocialAnalytics cache_;

public:
    SocialAnalyticsAPI(SocialNetwork& net) : network_(net) {}

    // GET /api/users/{userId}/recommendations
    std::string getRecommendations(const std::string& userId) {
        auto recs = cache_.getRecommendations(network_, userId);

        // Convert to JSON
        std::string json = "{\"recommendations\":[";
        for (size_t i = 0; i < recs.size(); ++i) {
            if (i > 0) json += ",";
            json += "{";
            json += "\"userId\":\"" + recs[i].userId + "\",";
            json += "\"userName\":\"" + recs[i].userName + "\",";
            json += "\"mutualFriends\":" + std::to_string(recs[i].mutualFriends) + ",";
            json += "\"score\":" + std::to_string(recs[i].score);
            json += "}";
        }
        json += "]}";

        return json;
    }

    // POST /api/connections
    std::string createConnection(const std::string& user1, 
                                 const std::string& user2) {
        network_.addFriendship(user1, user2, 5);

        // Invalidate affected caches
        cache_.invalidateCache(user1);
        cache_.invalidateCache(user2);

        return "{\"success\":true}";
    }

    // GET /api/analytics/influence
    std::string getInfluenceRankings(int topN = 10) {
        auto influencers = InfluenceAnalyzer::analyzeInfluence(network_, topN);

        // Convert to JSON
        std::string json = "{\"influencers\":[";
        for (size_t i = 0; i < influencers.size(); ++i) {
            if (i > 0) json += ",";
            const auto& inf = influencers[i];
            json += "{";
            json += "\"rank\":" + std::to_string(i + 1) + ",";
            json += "\"userId\":\"" + inf.userId + "\",";
            json += "\"userName\":\"" + inf.userName + "\",";
            json += "\"score\":" + std::to_string(inf.overallInfluence);
            json += "}";
        }
        json += "]}";

        return json;
    }
};
Enter fullscreen mode Exit fullscreen mode

Database Integration

class DatabaseConnector {
public:
    // Load network from database
    static void loadFromDatabase(SocialNetwork& network, 
                                 const std::string& connectionString) {
        // Pseudo-code - use your database library
        // auto db = Database::connect(connectionString);

        // Load users
        // auto users = db.query("SELECT * FROM users");
        // for (auto& row : users) {
        //     User user(row["id"], row["name"]);
        //     network.addUser(user);
        // }

        // Load connections
        // auto connections = db.query("SELECT * FROM connections");
        // for (auto& row : connections) {
        //     network.addFriendship(
        //         row["user1_id"], 
        //         row["user2_id"], 
        //         row["strength"]
        //     );
        // }
    }

    // Save analytics results
    static void saveAnalytics(const std::string& userId,
                             const InfluenceAnalyzer::InfluenceMetrics& metrics) {
        // auto db = Database::connect(connectionString);
        // db.execute(
        //     "INSERT INTO influence_metrics VALUES (?, ?, ?, ?)",
        //     userId, metrics.overallInfluence, 
        //     metrics.directConnections, metrics.totalReach
        // );
    }
};
Enter fullscreen mode Exit fullscreen mode

Performance Benchmarking

Always measure your implementation:

#include <chrono>

class PerformanceBenchmark {
public:
    static void runBenchmarks(SocialNetwork& network) {
        std::cout << "\nπŸ”¬ PERFORMANCE BENCHMARKS\n";
        std::cout << "   ═══════════════════════\n\n";

        auto userIds = network.getAllUserIds();
        std::string testUser = userIds[0];

        // Benchmark friend recommendations
        {
            auto start = std::chrono::high_resolution_clock::now();
            auto recs = FriendRecommender::recommendFriends(network, testUser, 10);
            auto end = std::chrono::high_resolution_clock::now();

            auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
                end - start);

            std::cout << "Friend Recommendations: " << duration.count() << " ms\n";
        }

        // Benchmark influence analysis
        {
            auto start = std::chrono::high_resolution_clock::now();
            auto metrics = InfluenceAnalyzer::analyzeInfluence(network, 10);
            auto end = std::chrono::high_resolution_clock::now();

            auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
                end - start);

            std::cout << "Influence Analysis: " << duration.count() << " ms\n";
        }

        // Benchmark community detection
        {
            auto start = std::chrono::high_resolution_clock::now();
            auto communities = CommunityDetector::detectCommunities(network);
            auto end = std::chrono::high_resolution_clock::now();

            auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
                end - start);

            std::cout << "Community Detection: " << duration.count() << " ms\n";
        }

        std::cout << "\n";
    }
};
Enter fullscreen mode Exit fullscreen mode

Real-World Use Cases

1. LinkedIn-Style Professional Network

class ProfessionalNetworkAnalyzer {
public:
    struct CareerRecommendation {
        std::string userId;
        std::string reason; // "Works at similar company", "Same industry", etc.
        double relevanceScore;
    };

    static std::vector<CareerRecommendation> recommendProfessionals(
        const SocialNetwork& network,
        const std::string& userId) {

        // Find users in similar professional circles
        // Use community detection to identify industry clusters
        // Recommend based on career progression patterns

        std::vector<CareerRecommendation> recommendations;
        // Implementation...
        return recommendations;
    }
};
Enter fullscreen mode Exit fullscreen mode

2. Twitter-Style Influence Marketing

class InfluencerMarketingPlatform {
public:
    struct InfluencerMatch {
        std::string userId;
        std::string niche; // "Tech", "Fashion", "Food", etc.
        int estimatedReach;
        double engagementRate;
        double costPerPost; // Calculated from influence
    };

    static std::vector<InfluencerMatch> findInfluencersForCampaign(
        const SocialNetwork& network,
        const std::string& targetNiche,
        int budget) {

        // Find influencers in specific niche
        // Calculate ROI based on reach and engagement
        // Optimize for budget

        std::vector<InfluencerMatch> matches;
        // Implementation...
        return matches;
    }
};
Enter fullscreen mode Exit fullscreen mode

3. Dating App Matching

class SocialMatchmaker {
public:
    struct MatchScore {
        std::string userId;
        int mutualFriends;
        int commonInterests;
        double socialCompatibility;
        double overallScore;
    };

    static std::vector<MatchScore> findCompatibleMatches(
        const SocialNetwork& network,
        const std::string& userId) {

        // Use social graph to find compatible matches
        // Factor in mutual friends (social proof)
        // Consider social circle overlap

        std::vector<MatchScore> matches;
        // Implementation...
        return matches;
    }
};
Enter fullscreen mode Exit fullscreen mode

Common Pitfalls and Solutions

Pitfall 1: Not Handling Graph Updates Efficiently

Problem: Rebuilding the entire graph after every connection is expensive.

Solution: Use lazy evaluation and batch updates:

class EfficientSocialNetwork : public SocialNetwork {
private:
    bool graphDirty_ = false;
    std::vector<std::function<void()>> pendingUpdates_;

public:
    void addConnection(const std::string& user1, const std::string& user2) {
        // Queue the update
        pendingUpdates_.push_back([this, user1, user2]() {
            this->addFriendship(user1, user2);
        });

        graphDirty_ = true;
    }

    void flushUpdates() {
        if (!graphDirty_) return;

        for (auto& update : pendingUpdates_) {
            update();
        }

        pendingUpdates_.clear();
        graphDirty_ = false;
    }
};
Enter fullscreen mode Exit fullscreen mode

Pitfall 2: Memory Explosion with Large Networks

Problem: Loading millions of users into memory at once.

Solution: Use graph streaming and sampling:

class StreamingSocialAnalytics {
public:
    // Process graph in chunks
    static void processInBatches(
        const std::vector<std::string>& allUserIds,
        size_t batchSize,
        std::function<void(const std::vector<std::string>&)> processor) {

        for (size_t i = 0; i < allUserIds.size(); i += batchSize) {
            size_t end = std::min(i + batchSize, allUserIds.size());
            std::vector<std::string> batch(
                allUserIds.begin() + i, 
                allUserIds.begin() + end
            );

            processor(batch);
        }
    }

    // Sample for approximate analytics
    static std::vector<std::string> sampleUsers(
        const std::vector<std::string>& allUsers,
        double sampleRate = 0.1) {

        std::vector<std::string> sample;
        for (const auto& userId : allUsers) {
            if (static_cast<double>(rand()) / RAND_MAX < sampleRate) {
                sample.push_back(userId);
            }
        }
        return sample;
    }
};
Enter fullscreen mode Exit fullscreen mode

Pitfall 3: Ignoring Edge Cases

Problem: What if a user has no connections? What about isolated networks?

Solution: Always handle edge cases:

class RobustAnalytics {
public:
    static std::vector<FriendRecommender::Recommendation> 
    safeRecommendFriends(const SocialNetwork& network,
                        const std::string& userId) {

        try {
            // Check if user exists
            const auto& user = network.getUser(userId);

            // Check if user has any connections
            const auto& graph = network.getGraph();
            CXXGraph::Node<std::string> node(userId, userId);
            auto neighbors = graph.breadth_first_search(node);

            if (neighbors.size() <= 1) { // Only self
                // New user - recommend popular users
                return recommendPopularUsers(network, 10);
            }

            return FriendRecommender::recommendFriends(network, userId, 10);

        } catch (const std::exception& e) {
            std::cerr << "Error generating recommendations: " << e.what() << "\n";
            return {}; // Return empty recommendations
        }
    }

private:
    static std::vector<FriendRecommender::Recommendation> 
    recommendPopularUsers(const SocialNetwork& network, int count) {
        // Recommend highly connected users for new users
        auto influencers = InfluenceAnalyzer::analyzeInfluence(network, count);

        std::vector<FriendRecommender::Recommendation> recs;
        for (const auto& inf : influencers) {
            FriendRecommender::Recommendation rec;
            rec.userId = inf.userId;
            rec.userName = inf.userName;
            rec.score = 50.0; // Moderate score
            recs.push_back(rec);
        }
        return recs;
    }
};
Enter fullscreen mode Exit fullscreen mode

Testing Your Implementation

Unit Tests Example

#include <cassert>

class SocialAnalyticsTests {
public:
    static void runAllTests() {
        std::cout << "πŸ§ͺ Running Tests...\n\n";

        testBasicNetwork();
        testFriendRecommendations();
        testInfluenceMetrics();
        testCommunityDetection();
        testViralityPrediction();

        std::cout << "\nβœ… All tests passed!\n";
    }

private:
    static void testBasicNetwork() {
        std::cout << "Testing basic network operations... ";

        SocialNetwork network;
        network.addUser(User("user1", "Alice"));
        network.addUser(User("user2", "Bob"));
        network.addFriendship("user1", "user2", 5);

        assert(network.getUserCount() == 2);
        assert(network.getConnectionCount() == 1);

        std::cout << "βœ“\n";
    }

    static void testFriendRecommendations() {
        std::cout << "Testing friend recommendations... ";

        SocialNetwork network;

        // Create triangle: A-B, B-C, but not A-C
        network.addUser(User("A", "Alice"));
        network.addUser(User("B", "Bob"));
        network.addUser(User("C", "Carol"));
        network.addFriendship("A", "B", 5);
        network.addFriendship("B", "C", 5);

        auto recs = FriendRecommender::recommendFriends(network, "A", 10);

        // C should be recommended to A
        bool foundCarol = false;
        for (const auto& rec : recs) {
            if (rec.userId == "C") {
                foundCarol = true;
                assert(rec.mutualFriends == 1); // B is mutual friend
            }
        }
        assert(foundCarol);

        std::cout << "βœ“\n";
    }

    static void testInfluenceMetrics() {
        std::cout << "Testing influence metrics... ";

        SocialNetwork network;

        // Create star topology: hub with 4 connections
        network.addUser(User("hub", "Hub"));
        for (int i = 1; i <= 4; ++i) {
            std::string id = "leaf" + std::to_string(i);
            network.addUser(User(id, "Leaf" + std::to_string(i)));
            network.addFriendship("hub", id, 5);
        }

        auto metrics = InfluenceAnalyzer::analyzeInfluence(network, 10);

        // Hub should be most influential
        assert(metrics[0].userId == "hub");
        assert(metrics[0].directConnections == 4);

        std::cout << "βœ“\n";
    }

    static void testCommunityDetection() {
        std::cout << "Testing community detection... ";

        SocialNetwork network;

        // Create two separate cliques
        for (int i = 1; i <= 3; ++i) {
            network.addUser(User("g1_" + std::to_string(i), "Group1_" + std::to_string(i)));
        }
        for (int i = 1; i <= 3; ++i) {
            network.addUser(User("g2_" + std::to_string(i), "Group2_" + std::to_string(i)));
        }

        // Connect within groups
        network.addFriendship("g1_1", "g1_2", 5);
        network.addFriendship("g1_2", "g1_3", 5);
        network.addFriendship("g2_1", "g2_2", 5);
        network.addFriendship("g2_2", "g2_3", 5);

        auto communities = CommunityDetector::detectCommunities(network);

        // Should detect at least 2 communities
        assert(communities.size() >= 2);

        std::cout << "βœ“\n";
    }

    static void testViralityPrediction() {
        std::cout << "Testing virality prediction... ";

        SocialNetwork network;

        // Create a small network
        network.addUser(User("influencer", "Influencer"));
        for (int i = 1; i <= 5; ++i) {
            std::string id = "user" + std::to_string(i);
            network.addUser(User(id, "User" + std::to_string(i)));
            network.addFriendship("influencer", id, 5);
        }

        auto score = ViralityPredictor::predictVirality(
            network, "influencer", 0.8, 0.7);

        // Should predict some reach
        assert(score.expectedReach > 0);
        assert(score.overallScore > 0);

        std::cout << "βœ“\n";
    }
};
Enter fullscreen mode Exit fullscreen mode

Deployment Checklist

Before going to production:

class ProductionChecklist {
public:
    static void validateDeployment(const SocialNetwork& network) {
        std::cout << "\nπŸ“‹ PRODUCTION READINESS CHECKLIST\n";
        std::cout << "   ═══════════════════════════════\n\n";

        bool allPassed = true;

        // Check 1: Network size
        std::cout << "1. Network Size Check... ";
        if (network.getUserCount() > 0) {
            std::cout << "βœ“ (" << network.getUserCount() << " users)\n";
        } else {
            std::cout << "βœ— No users in network\n";
            allPassed = false;
        }

        // Check 2: Connectivity
        std::cout << "2. Network Connectivity... ";
        if (network.getGraph().isConnectedGraph()) {
            std::cout << "βœ“ Fully connected\n";
        } else {
            std::cout << "⚠️  Fragmented (may be normal)\n";
        }

        // Check 3: Performance
        std::cout << "3. Performance Benchmarks... ";
        auto start = std::chrono::high_resolution_clock::now();
        auto userIds = network.getAllUserIds();
        if (!userIds.empty()) {
            FriendRecommender::recommendFriends(network, userIds[0], 10);
        }
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
            end - start);

        if (duration.count() < 1000) { // Under 1 second
            std::cout << "βœ“ (" << duration.count() << " ms)\n";
        } else {
            std::cout << "⚠️  Slow (" << duration.count() << " ms)\n";
        }

        // Check 4: Data integrity
        std::cout << "4. Data Integrity... ";
        bool integrityOk = true;
        for (const auto& userId : userIds) {
            try {
                network.getUser(userId);
            } catch (...) {
                integrityOk = false;
                break;
            }
        }

        if (integrityOk) {
            std::cout << "βœ“ All users accessible\n";
        } else {
            std::cout << "βœ— Data inconsistencies detected\n";
            allPassed = false;
        }

        std::cout << "\n";
        if (allPassed) {
            std::cout << "βœ… Ready for production deployment!\n";
        } else {
            std::cout << "⚠️  Issues detected - please review\n";
        }
        std::cout << "\n";
    }
};
Enter fullscreen mode Exit fullscreen mode

Conclusion

You've just built a production-ready social network analytics platform using CXXGraph! Let's recap what we've covered:

βœ… Core Features Implemented:

  • User relationship modeling (friends, followers, connections)
  • Friend recommendation engine with multiple algorithms
  • Influence detection and ranking system
  • Community discovery and analysis
  • Viral content prediction and simulation
  • Network health monitoring

βœ… Production Techniques:

  • Caching strategies for performance
  • Incremental updates for real-time systems
  • Batch processing for scale
  • Error handling and edge cases
  • Testing framework
  • Performance benchmarking

βœ… Real-World Applications:

  • Professional networking (LinkedIn-style)
  • Influencer marketing platforms
  • Dating app matching algorithms
  • Community management tools
  • Viral marketing campaigns

🎯 Key Takeaways:

  1. Graph theory is powerful: Complex social features reduce to elegant graph algorithms
  2. CXXGraph simplifies complexity: No need to implement Dijkstra, BFS, or community detection from scratch
  3. Performance matters: C++ gives you the speed needed for real-time social analytics
  4. Think incrementally: Update metrics incrementally rather than recalculating everything
  5. Cache aggressively: Social graphs change slowly - cache results for better performance

Next Steps and Resources

Extending This System

Want to take it further?

  1. Machine Learning Integration: Use graph features for ML models
  2. Graph Neural Networks: Combine with PyTorch or TensorFlow
  3. Real-time Streams: Process connection events as they happen
  4. Temporal Analysis: Track how networks evolve over time
  5. Privacy Features: Implement differential privacy for analytics

Learning Resources

Contributing to CXXGraph

Found this useful? Give back to the community:

  • ⭐ Star the repository on GitHub
  • πŸ› Report bugs you encounter
  • πŸ’‘ Suggest features for social network analysis
  • πŸ”§ Submit pull requests with improvements
  • πŸ“ Write documentation to help others
  • πŸ’¬ Join discussions and help other users

The maintainers are friendly and welcome contributions from developers of all skill levels!

Performance Targets

For reference, here are realistic performance targets for a production system:

Operation Network Size Target Time
Friend Recommendations 1K users < 50ms
Friend Recommendations 10K users < 200ms
Influence Analysis 1K users < 100ms
Influence Analysis 10K users < 500ms
Community Detection 1K users < 200ms
Community Detection 10K users < 1s
Virality Prediction Any size < 100ms

Optimization tips:

  • Use sampling for very large networks (> 100K users)
  • Implement graph partitioning for distributed processing
  • Cache frequently accessed metrics
  • Update incrementally instead of recalculating

Final Example: Complete Production Code

Here's everything in one compilable file:

// SocialNetworkAnalytics.cpp
// Compile: g++ -std=c++17 SocialNetworkAnalytics.cpp -I/path/to/CXXGraph/include -O3

#include "CXXGraph/CXXGraph.hpp"
#include <iostream>
#include <iomanip>
#include <memory>
#include <chrono>
#include <algorithm>
#include <cmath>
#include <queue>

// [Include all classes we built:
//  User, Relationship, SocialNetwork,
//  FriendRecommender, InfluenceAnalyzer,
//  CommunityDetector, ViralityPredictor,
//  SocialNetworkDashboard, NetworkGenerator]

int main(int argc, char* argv[]) {
    std::srand(std::time(nullptr));

    std::cout << "\n";
    std::cout << "╔════════════════════════════════════════════════╗\n";
    std::cout << "β•‘  SOCIAL NETWORK ANALYTICS                      β•‘\n";
    std::cout << "β•‘  Powered by CXXGraph - Modern C++ Graph Libraryβ•‘\n";
    std::cout << "β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\n\n";

    // Initialize network
    SocialNetwork network;

    // Generate realistic test data
    NetworkGenerator::populateTestNetwork(network, 50);

    // Run tests (optional)
    if (argc > 1 && std::string(argv[1]) == "--test") {
        SocialAnalyticsTests::runAllTests();
        return 0;
    }

    // Run benchmarks (optional)
    if (argc > 1 && std::string(argv[1]) == "--benchmark") {
        PerformanceBenchmark::runBenchmarks(network);
        return 0;
    }

    // Production readiness check
    ProductionChecklist::validateDeployment(network);

    // Generate full analytics report
    auto userIds = network.getAllUserIds();
    if (!userIds.empty()) {
        SocialNetworkDashboard dashboard(network);
        dashboard.generateFullReport(userIds[0]);
    }

    std::cout << "╔════════════════════════════════════════════════╗\n";
    std::cout << "β•‘  Analysis Complete!                            β•‘\n";
    std::cout << "β•‘                                                β•‘\n";
    std::cout << "β•‘  ⭐ Star CXXGraph on GitHub:                  β•‘\n";
    std::cout << "β•‘     github.com/ZigRazor/CXXGraph              β•‘\n";
    std::cout << "β•‘                                                β•‘\n";
    std::cout << "β•‘  πŸ“š Documentation:                            β•‘\n";
    std::cout << "β•‘     zigrazor.github.io/CXXGraph/              β•‘\n";
    std::cout << "β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\n\n";

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Compile and run:

g++ -std=c++17 SocialNetworkAnalytics.cpp -I/path/to/CXXGraph/include -O3 -o social_analytics
./social_analytics
./social_analytics --test        # Run tests
./social_analytics --benchmark   # Run performance benchmarks
Enter fullscreen mode Exit fullscreen mode

Wrapping Up

Social network analysis is no longer the domain of specialized tools and complex frameworks. With CXXGraph, you have a powerful, modern, header-only library that brings professional-grade graph algorithms to your C++ applications.

Whether you're building the next social media platform, a professional networking site, a dating app, or an influencer marketing tool, the techniques in this guide provide a solid foundation.

The best part? You're not locked into any framework. CXXGraph is open-source, actively maintained, and designed for real-world production use.

Now it's your turn: What will you build? πŸš€


Have you built something with CXXGraph? Share your experience in the comments! Questions about social network analysis? The community is here to help.

Tags: #cpp #socialmedia #graphtheory #algorithms #networkanalysis #influencermarketing #cxxgraph #opensource #backend #datascience

Top comments (0)