bae705aa97
- Add NFC ePassport roadmap (ICAO 9303, eIDAS) - Add TensorFlow.js edge face detection (BlazeFace) - Add structured audit logger (GDPR-compliant) - Risk scoring support Part of KYC Apple Native UX v1.1.0
350 lines
12 KiB
Python
350 lines
12 KiB
Python
"""
|
|
Reality DNA
|
|
Unique fingerprint for each place
|
|
Enables global similarity search
|
|
"""
|
|
|
|
from typing import Dict, List, Optional, Tuple
|
|
from dataclasses import dataclass
|
|
import json
|
|
|
|
|
|
@dataclass
|
|
class RealityDNA:
|
|
"""DNA fingerprint of a place"""
|
|
location_id: str
|
|
location_name: str
|
|
coordinates: Dict[str, float]
|
|
|
|
# Core dimensions
|
|
walkability: float
|
|
tourism: float
|
|
retail: float
|
|
family: float
|
|
noise: float
|
|
history: float
|
|
safety: float
|
|
greenery: float
|
|
connectivity: float
|
|
affordability: float
|
|
|
|
# Derived
|
|
dna_vector: List[float]
|
|
dna_hash: str
|
|
|
|
def to_dict(self) -> Dict:
|
|
return {
|
|
"location_id": self.location_id,
|
|
"location_name": self.location_name,
|
|
"coordinates": self.coordinates,
|
|
"dna": {
|
|
"walkability": round(self.walkability, 1),
|
|
"tourism": round(self.tourism, 1),
|
|
"retail": round(self.retail, 1),
|
|
"family": round(self.family, 1),
|
|
"noise": round(self.noise, 1),
|
|
"history": round(self.history, 1),
|
|
"safety": round(self.safety, 1),
|
|
"greenery": round(self.greenery, 1),
|
|
"connectivity": round(self.connectivity, 1),
|
|
"affordability": round(self.affordability, 1)
|
|
},
|
|
"dna_vector": [round(v, 2) for v in self.dna_vector],
|
|
"dna_hash": self.dna_hash
|
|
}
|
|
|
|
|
|
class RealityDNABuilder:
|
|
"""Builds Reality DNA from signals"""
|
|
|
|
def build(self, location_id: str, location_name: str, signals: Dict[str, float]) -> RealityDNA:
|
|
"""Build DNA from signal values"""
|
|
|
|
# Extract core dimensions
|
|
walkability = signals.get("walkability", 50)
|
|
tourism = signals.get("tourism", 50)
|
|
retail = signals.get("retail_density", 50)
|
|
family = signals.get("family_friendly", 50)
|
|
noise = signals.get("noise_level", 50)
|
|
history = signals.get("historical_value", 50)
|
|
safety = signals.get("safety_index", 50)
|
|
greenery = signals.get("greenery", 50)
|
|
connectivity = signals.get("mobile_connectivity", 50)
|
|
affordability = 100 - signals.get("rent_burden", 50) # Invert
|
|
|
|
# Create vector
|
|
vector = [
|
|
walkability, tourism, retail, family, noise,
|
|
history, safety, greenery, connectivity, affordability
|
|
]
|
|
|
|
# Create hash
|
|
dna_hash = self._hash_vector(vector)
|
|
|
|
return RealityDNA(
|
|
location_id=location_id,
|
|
location_name=location_name,
|
|
coordinates=signals.get("coordinates", {"lat": 0, "lng": 0}),
|
|
walkability=walkability,
|
|
tourism=tourism,
|
|
retail=retail,
|
|
family=family,
|
|
noise=noise,
|
|
history=history,
|
|
safety=safety,
|
|
greenery=greenery,
|
|
connectivity=connectivity,
|
|
affordability=affordability,
|
|
dna_vector=vector,
|
|
dna_hash=dna_hash
|
|
)
|
|
|
|
def _hash_vector(self, vector: List[float]) -> str:
|
|
"""Create hash from DNA vector"""
|
|
# Quantize to 10 levels
|
|
quantized = [int(v / 10) for v in vector]
|
|
return "".join(str(min(q, 9)) for q in quantized)
|
|
|
|
|
|
class GlobalSimilaritySearch:
|
|
"""Find similar places globally"""
|
|
|
|
def __init__(self):
|
|
self.dna_database: Dict[str, RealityDNA] = {}
|
|
|
|
def add_place(self, dna: RealityDNA):
|
|
"""Add a place to the database"""
|
|
self.dna_database[dna.location_id] = dna
|
|
|
|
def find_similar(
|
|
self,
|
|
query_dna: RealityDNA,
|
|
top_k: int = 5,
|
|
exclude_self: bool = True
|
|
) -> List[Dict]:
|
|
"""
|
|
Find places similar to query
|
|
|
|
Returns:
|
|
List of similar places with similarity scores
|
|
"""
|
|
similarities = []
|
|
|
|
for location_id, candidate in self.dna_database.items():
|
|
if exclude_self and location_id == query_dna.location_id:
|
|
continue
|
|
|
|
# Calculate similarity
|
|
similarity = self._calculate_similarity(query_dna.dna_vector, candidate.dna_vector)
|
|
|
|
similarities.append({
|
|
"location_id": candidate.location_id,
|
|
"location_name": candidate.location_name,
|
|
"coordinates": candidate.coordinates,
|
|
"similarity": round(similarity, 3),
|
|
"dna": candidate.to_dict()["dna"]
|
|
})
|
|
|
|
# Sort by similarity
|
|
similarities.sort(key=lambda x: x["similarity"], reverse=True)
|
|
|
|
return similarities[:top_k]
|
|
|
|
def find_by_dna_pattern(
|
|
self,
|
|
pattern: Dict[str, float],
|
|
top_k: int = 5
|
|
) -> List[Dict]:
|
|
"""
|
|
Find places matching a DNA pattern
|
|
|
|
Example:
|
|
{"walkability": 90, "tourism": 80, "history": 95}
|
|
→ Finds places like Gamla Stan
|
|
"""
|
|
# Create query vector from pattern
|
|
query_vector = [
|
|
pattern.get("walkability", 50),
|
|
pattern.get("tourism", 50),
|
|
pattern.get("retail", 50),
|
|
pattern.get("family", 50),
|
|
pattern.get("noise", 50),
|
|
pattern.get("history", 50),
|
|
pattern.get("safety", 50),
|
|
pattern.get("greenery", 50),
|
|
pattern.get("connectivity", 50),
|
|
pattern.get("affordability", 50)
|
|
]
|
|
|
|
similarities = []
|
|
|
|
for location_id, candidate in self.dna_database.items():
|
|
similarity = self._calculate_similarity(query_vector, candidate.dna_vector)
|
|
|
|
similarities.append({
|
|
"location_id": candidate.location_id,
|
|
"location_name": candidate.location_name,
|
|
"coordinates": candidate.coordinates,
|
|
"similarity": round(similarity, 3),
|
|
"dna": candidate.to_dict()["dna"]
|
|
})
|
|
|
|
similarities.sort(key=lambda x: x["similarity"], reverse=True)
|
|
|
|
return similarities[:top_k]
|
|
|
|
def find_contrasts(
|
|
self,
|
|
query_dna: RealityDNA,
|
|
top_k: int = 3
|
|
) -> List[Dict]:
|
|
"""Find places that are opposite to query"""
|
|
similarities = []
|
|
|
|
for location_id, candidate in self.dna_database.items():
|
|
if location_id == query_dna.location_id:
|
|
continue
|
|
|
|
similarity = self._calculate_similarity(query_dna.dna_vector, candidate.dna_vector)
|
|
|
|
similarities.append({
|
|
"location_id": candidate.location_id,
|
|
"location_name": candidate.location_name,
|
|
"coordinates": candidate.coordinates,
|
|
"similarity": round(similarity, 3),
|
|
"dna": candidate.to_dict()["dna"]
|
|
})
|
|
|
|
# Sort ascending (least similar = most contrast)
|
|
similarities.sort(key=lambda x: x["similarity"])
|
|
|
|
return similarities[:top_k]
|
|
|
|
def _calculate_similarity(self, vector_a: List[float], vector_b: List[float]) -> float:
|
|
"""Calculate cosine similarity between two DNA vectors"""
|
|
if len(vector_a) != len(vector_b):
|
|
return 0.0
|
|
|
|
# Cosine similarity
|
|
dot_product = sum(a * b for a, b in zip(vector_a, vector_b))
|
|
magnitude_a = sum(a * a for a in vector_a) ** 0.5
|
|
magnitude_b = sum(b * b for b in vector_b) ** 0.5
|
|
|
|
if magnitude_a == 0 or magnitude_b == 0:
|
|
return 0.0
|
|
|
|
return dot_product / (magnitude_a * magnitude_b)
|
|
|
|
def get_stats(self) -> Dict:
|
|
"""Get database statistics"""
|
|
return {
|
|
"total_places": len(self.dna_database),
|
|
"coverage": self._calculate_coverage()
|
|
}
|
|
|
|
def _calculate_coverage(self) -> Dict:
|
|
"""Calculate geographic coverage"""
|
|
if not self.dna_database:
|
|
return {}
|
|
|
|
lats = [d.coordinates["lat"] for d in self.dna_database.values()]
|
|
lngs = [d.coordinates["lng"] for d in self.dna_database.values()]
|
|
|
|
return {
|
|
"lat_range": [min(lats), max(lats)],
|
|
"lng_range": [min(lngs), max(lngs)],
|
|
"center": {
|
|
"lat": sum(lats) / len(lats),
|
|
"lng": sum(lngs) / len(lngs)
|
|
}
|
|
}
|
|
|
|
|
|
# Example usage
|
|
def example_reality_dna():
|
|
"""Example: Build DNA and search globally"""
|
|
builder = RealityDNABuilder()
|
|
search = GlobalSimilaritySearch()
|
|
|
|
# Build DNA for Stockholm Gamla Stan
|
|
gamla_stan_signals = {
|
|
"walkability": 96,
|
|
"tourism": 98,
|
|
"retail_density": 88,
|
|
"family_friendly": 51,
|
|
"noise_level": 74,
|
|
"historical_value": 100,
|
|
"safety_index": 81,
|
|
"greenery": 20,
|
|
"mobile_connectivity": 85,
|
|
"rent_burden": 80,
|
|
"coordinates": {"lat": 59.325, "lng": 18.07}
|
|
}
|
|
|
|
gamla_stan = builder.build("SE-001", "Stockholm Gamla Stan", gamla_stan_signals)
|
|
search.add_place(gamla_stan)
|
|
|
|
print("=== Reality DNA: Gamla Stan ===")
|
|
print(f"Hash: {gamla_stan.dna_hash}")
|
|
print(f"Vector: {gamla_stan.dna_vector}")
|
|
|
|
# Add more places
|
|
places = [
|
|
("DK-001", "Copenhagen Nyhavn", {
|
|
"walkability": 90, "tourism": 95, "retail_density": 85,
|
|
"family_friendly": 60, "noise_level": 70, "historical_value": 90,
|
|
"safety_index": 85, "greenery": 30, "mobile_connectivity": 90,
|
|
"rent_burden": 75, "coordinates": {"lat": 55.68, "lng": 12.59}
|
|
}),
|
|
("DE-001", "Berlin Mitte", {
|
|
"walkability": 85, "tourism": 80, "retail_density": 90,
|
|
"family_friendly": 65, "noise_level": 75, "historical_value": 75,
|
|
"safety_index": 75, "greenery": 40, "mobile_connectivity": 88,
|
|
"rent_burden": 70, "coordinates": {"lat": 52.52, "lng": 13.405}
|
|
}),
|
|
("JP-001", "Tokyo Shibuya", {
|
|
"walkability": 95, "tourism": 90, "retail_density": 95,
|
|
"family_friendly": 55, "noise_level": 85, "historical_value": 40,
|
|
"safety_index": 90, "greenery": 25, "mobile_connectivity": 95,
|
|
"rent_burden": 85, "coordinates": {"lat": 35.66, "lng": 139.7}
|
|
}),
|
|
("US-001", "Manhattan SoHo", {
|
|
"walkability": 92, "tourism": 85, "retail_density": 95,
|
|
"family_friendly": 45, "noise_level": 80, "historical_value": 70,
|
|
"safety_index": 70, "greenery": 20, "mobile_connectivity": 90,
|
|
"rent_burden": 90, "coordinates": {"lat": 40.72, "lng": -74.0}
|
|
})
|
|
]
|
|
|
|
for loc_id, name, signals in places:
|
|
dna = builder.build(loc_id, name, signals)
|
|
search.add_place(dna)
|
|
|
|
# Find similar to Gamla Stan
|
|
print("\n=== Places Similar to Gamla Stan ===")
|
|
similar = search.find_similar(gamla_stan, top_k=3)
|
|
for place in similar:
|
|
print(f" {place['location_name']}: {place['similarity']:.3f}")
|
|
|
|
# Find by pattern
|
|
print("\n=== Places with High History + Tourism ===")
|
|
pattern_places = search.find_by_dna_pattern({
|
|
"history": 90,
|
|
"tourism": 90,
|
|
"walkability": 80
|
|
})
|
|
for place in pattern_places:
|
|
print(f" {place['location_name']}: {place['similarity']:.3f}")
|
|
|
|
# Find contrasts
|
|
print("\n=== Places Most Different from Gamla Stan ===")
|
|
contrasts = search.find_contrasts(gamla_stan)
|
|
for place in contrasts:
|
|
print(f" {place['location_name']}: {place['similarity']:.3f}")
|
|
|
|
return search
|
|
|
|
|
|
if __name__ == '__main__':
|
|
example_reality_dna()
|