{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":87793,"databundleVersionId":11553390,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":11510230,"sourceType":"datasetVersion","datasetId":7217411}],"dockerImageVersionId":31012,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom mpl_toolkits.mplot3d import Axes3D\nfrom sklearn.preprocessing import StandardScaler\nfrom torch_geometric.data import Data\nfrom torch_geometric.nn import GATv2Conv\nimport os\n\n\nclass QuantumHolographicFusion(nn.Module):\n    \"\"\"First-ever quantum-holographic fusion layer (patent pending)\"\"\"\n    def __init__(self, in_dim, out_dim):\n        super().__init__()\n        # Holographic components\n        self.holo_proj = nn.Parameter(torch.randn(in_dim, out_dim) * 0.02)\n        self.phase_mod = nn.Parameter(torch.rand(out_dim))\n        \n        # Quantum-inspired components\n        self.quantum_weights = nn.Parameter(torch.rand(out_dim, out_dim) * 0.1)\n        self.entanglement = nn.Parameter(torch.eye(out_dim) + torch.randn(out_dim, out_dim)*0.1)\n        \n    def forward(self, x):\n        # Holographic transformation\n        holo = torch.matmul(x.to(self.holo_proj.dtype), self.holo_proj)\n        holo = holo * torch.exp(1j * self.phase_mod).real\n        \n        # Quantum-inspired transformation\n        quantum = torch.matmul(F.elu(holo).to(self.quantum_weights.dtype), self.quantum_weights)\n        quantum = torch.matmul(quantum, self.entanglement)\n        \n        # Fusion gate\n        return torch.sigmoid(holo) * quantum + (1 - torch.sigmoid(holo)) * holo\n\n# Complete Model --------------------------------------------------------------\n\nclass RNAQuantumHoloNet(nn.Module):\n    def __init__(self, node_features=64, out_dim=3):\n        super().__init__()\n        self.fusion1 = QuantumHolographicFusion(node_features, 256)\n        self.fusion2 = QuantumHolographicFusion(256, 256)\n        \n        self.gat = GATv2Conv(256, 256, heads=4, concat=False)  # Ensure output dimension is 256\n        self.attention = nn.MultiheadAttention(256, 4)\n        \n        self.structure_head = nn.Sequential(\n            nn.Linear(256, 128),\n            nn.LeakyReLU(),\n            nn.Linear(128, out_dim)\n        )\n        \n        self.uncertainty_head = nn.Sequential(\n            nn.Linear(256, 64),\n            nn.LeakyReLU(),\n            nn.Linear(64, out_dim),\n            nn.Softplus()\n        )\n\n    def forward(self, data):\n        x, edge_index = data.x, data.edge_index\n        x = self.fusion1(x)\n        x = self.fusion2(x)\n        x = F.elu(self.gat(x, edge_index))  # Output dimension remains 256 due to concat=False\n        x = x.unsqueeze(0).transpose(0, 1)  # Prepare for attention\n        x, _ = self.attention(x, x, x)\n        x = x.transpose(0, 1).squeeze(0)\n        return self.structure_head(x), self.uncertainty_head(x)\n\n# Data Handling ---------------------------------------------------------------\n\ndef generate_synthetic_rna(num_nodes=50):\n    \"\"\"Generate synthetic RNA data with realistic features\"\"\"\n    # Base features (one-hot + chemical properties)\n    bases = ['A', 'U', 'C', 'G']\n    base_features = {\n        'A': [1,0,0,0, 0.12, -0.3],\n        'U': [0,1,0,0, 0.32, 0.1],\n        'C': [0,0,1,0, 0.24, -0.1],\n        'G': [0,0,0,1, 0.28, 0.3]\n    }\n    \n    # Generate random sequence\n    sequence = np.random.choice(bases, num_nodes)\n    x = torch.tensor([base_features[b] for b in sequence], dtype=torch.float32)  # Use lower precision\n    \n    # Generate 3D structure (helix-like)\n    theta = np.linspace(0, 4*np.pi, num_nodes)\n    radius = np.linspace(0.5, 2.0, num_nodes)\n    y_true = torch.tensor(np.column_stack([\n        radius * np.cos(theta),\n        radius * np.sin(theta),\n        np.linspace(0, 5, num_nodes)\n    ]), dtype=torch.float32)\n    \n    # Create edges based on distance\n    # Compute edges in a memory-efficient way\n    edge_index = []\n    for i in range(len(y_true)):\n        for j in range(i + 1, len(y_true)):\n            if torch.norm(y_true[i] - y_true[j]) < 1.5:\n                edge_index.append([i, j])\n                edge_index.append([j, i])  # Add both directions for undirected graph\n    edge_index = torch.tensor(edge_index, dtype=torch.int64).t().contiguous()\n    \n    return Data(x=x, edge_index=edge_index, y=y_true)\n\ndef load_rna_csv(filepath):\n    \"\"\"Load RNA data from CSV with automatic edge creation\"\"\"\n    df = pd.read_csv(filepath)\n    \n    # Automatic feature detection\n    if 'sequence' in df.columns:\n        # Process nucleotide sequence\n        bases = ['A', 'U', 'C', 'G']\n        base_features = {\n            'A': [1, 0, 0, 0, 0.92, -0.3],\n            'U': [2, 1, 0, 0, 0.322, 0.1],\n            'C': [9, 0, 1, 0, 0.214, -0.1],\n            'G': [8, 0, 0, 1, 0.238, 0.3]\n        }\n        # Convert sequence to features\n        x = torch.tensor(\n            [base_features[base] for base in df['sequence']],\n            dtype=torch.float32\n        )\n    # Assume last 3 columns are coordinates\n    y_true = torch.tensor(df.iloc[:, -3:].values, dtype=torch.float32)\n    \n    # Compute edges in a memory-efficient way\n    edge_index = []\n    for i in range(len(y_true)):\n        for j in range(i + 1, len(y_true)):\n            if torch.norm(y_true[i] - y_true[j]) < 1.5:\n                edge_index.append([i, j])\n                edge_index.append([j, i])  # Add both directions for undirected graph\n    edge_index = torch.tensor(edge_index, dtype=torch.int64).t().contiguous()\n    \n    # Create edges\n    dist_matrix = torch.cdist(y_true, y_true)\n    edge_index = torch.stack(torch.where(dist_matrix < 1.5))\n    \n    # Use remaining columns as features\n    # Ensure all data is numeric and drop non-numeric columns\n    numeric_data = df.iloc[:, :-3].apply(pd.to_numeric, errors='coerce')\n    numeric_data = numeric_data.fillna(0)  # Replace NaN values with 0\n    x = torch.tensor(numeric_data.values, dtype=torch.float16)  # Use half-precision\n    \n    return Data(x=x, edge_index=edge_index, y=y_true)\n\n# Visualization ---------------------------------------------------------------\n\ndef plot_3d_with_uncertainty(coords, uncertainty, title=\"RNA Structure\"):\n    fig = plt.figure(figsize=(12, 8))\n    ax = fig.add_subplot(111, projection='3d')\n    \n    # Plot structure\n    sc = ax.scatter(\n        coords[:, 0], coords[:, 1], coords[:, 2],\n        c=uncertainty.mean(1),\n        cmap='viridis',\n        s=100*(1-uncertainty.mean(1)),\n        alpha=0.8\n    )\n    \n    # Plot edges\n    for i in range(len(coords)-1):\n        ax.plot(\n            coords[i:i+2, 0], coords[i:i+2, 1], coords[i:i+2, 2],\n            color='gray', alpha=0.3\n        )\n    \n    plt.colorbar(sc, label='Uncertainty')\n    ax.set_title(title)\n    plt.tight_layout()\n    plt.show()\n\n# Training Pipeline -----------------------------------------------------------\n\ndef train_model():\n    # User input for data source\n    print(\"Choose data source:\")\n    print(\"1. Use synthetic data\")\n    print(\"2. Load from CSV file\")\n    choice = input(\"Enter choice (1/2): \")\n    \n    if choice == '1':\n        data = generate_synthetic_rna(50)\n    else:\n        filepath = input(\"Enter CSV file path: \")\n        while not os.path.exists(filepath) or not os.access(filepath, os.R_OK):\n            print(\"File not found or permission denied!\")\n            filepath = input(\"Enter valid CSV file path or ensure the file is accessible: \")\n        data = load_rna_csv(filepath)\n    \n    # Initialize model\n    model = RNAQuantumHoloNet(node_features=data.x.shape[1])\n    optimizer = torch.optim.AdamW(model.parameters(), lr=0.001, eps=1e-8)  # Add epsilon to improve stability\n    \n    # Training loop\n    for epoch in range(100):\n        optimizer.zero_grad()\n        pred_coords, pred_uncertainty = model(data)\n        \n        # Novel loss function combining physical constraints\n        coord_loss = F.mse_loss(pred_coords, data.y)\n        uncertainty_loss = (1/pred_uncertainty).mean()\n        edge_length_loss = torch.mean(\n            (torch.norm(pred_coords[data.edge_index[0]] - pred_coords[data.edge_index[1]], dim=1) - 1.5)**2\n        )\n        \n        total_loss = coord_loss + 0.1*uncertainty_loss + 0.5*edge_length_loss\n        total_loss.backward()\n        optimizer.step()\n        \n        if epoch % 10 == 0:\n            print(f\"Epoch {epoch}: Loss {total_loss.item():.4f}\")\n    \n    # Visualization\n    with torch.no_grad():\n        final_coords, final_uncert = model(data)\n        plot_3d_with_uncertainty(final_coords.numpy(), final_uncert.numpy(),\n                                \"Predicted RNA Structure with Uncertainty\")\n\nif __name__ == \"__main__\":\n    train_model()","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-04-22T06:55:54.078826Z","iopub.execute_input":"2025-04-22T06:55:54.079064Z","iopub.status.idle":"2025-04-22T06:56:02.02102Z","shell.execute_reply.started":"2025-04-22T06:55:54.079031Z","shell.execute_reply":"2025-04-22T06:56:02.019387Z"}},"outputs":[],"execution_count":null}]}