Source code for qbiocode.apps.quvine.embedding.word2vec
# Copyright 2026, IBM Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import numpy as np
import hashlib
import logging
from qbiocode.apps.quvine._deps import require_module
# gensim is provided by the [quvine] extra and is resolved at the point of use,
# so importing this module (and therefore qbiocode.apps.quvine) never requires it.
#
# The previous version of this guard advised "pip install gensim==4.3.0 or
# downgrade scipy" on failure. That advice is wrong for this package: gensim<4.4
# needs scipy.triu, removed in scipy 1.13, and pinning scipy back would force
# numpy<2.0, which conflicts with qiskit-machine-learning==0.9.0. The extra pins
# gensim>=4.4 precisely so that no scipy downgrade is needed.
[docs]
def corpus_to_embedding(
corpus,
nodes,
vector_size=64,
window=5,
sg=1,
negative=10,
min_count=0,
workers=8,
epochs=100,
):
"""
Train Word2Vec embeddings from a compiled corpus.
corpus: List[List[str]] or List[List[int]]
nodes: List[str] or List[int]
Raises:
QuvineDependencyError: If gensim is not installed. The message names the
[quvine] extra and the command that installs it.
"""
Word2Vec = require_module(
"gensim.models", feature="SGNS embedding learning (word2vec)"
).Word2Vec
assert all(isinstance(w[0], str) for w in corpus)
# ensure all nodes appear at least once
sentences = [list(w) for w in corpus]
seen = set(x for w in sentences for x in w)
sentences += [[v] for v in nodes if v not in seen]
#print("deep hash:", hash(tuple(tuple(w) for w in sentences[:50])))
assert all(isinstance(w, list) and all(isinstance(t, str) for t in w) for w in corpus)
model = Word2Vec(
sentences=sentences,
vector_size=vector_size,
window=window,
sg=sg,
negative=negative,
min_count=min_count,
workers=workers,
epochs=epochs,
)
#print("model id:", id(model))
assert set(nodes) <= set(model.wv.key_to_index), \
"Node list and Word2Vec vocabulary are inconsistent"
assert all(v in model.wv for v in nodes)
Z = np.zeros((len(nodes), vector_size))
for i, v in enumerate(nodes):
Z[i] = model.wv[v]
W = model.wv.vectors
h = hashlib.md5(W[:10,:10].tobytes()).hexdigest()
# print("weights md5:", h)
# print("vocab size:", len(model.wv))
# print("first 3 vocab:", list(model.wv.key_to_index.keys())[:3])
# print("vector[0] head:", model.wv[nodes[0]][:5])
# print(
# "sanity",
# np.std(Z),
# np.mean(Z),
# np.sum(Z[:5, :5])
# )
return Z