Skip to main content

Custom Weight Calculations ย 

Helixโ€™s shortest path algorithms support sophisticated weight calculations that can reference properties from edges, source nodes, and destination nodes. This enables real-world routing scenarios where path costs depend on multiple factors and contexts.
Custom weights are available in both ShortestPathDijkstras and ShortestPathAStar.

Property Contexts

Property contexts allow you to reference different parts of the graph structure in your weight expressions:
Context SyntaxDescriptionExample Use Case
_::{property}Edge propertyRoad distance, bandwidth, cost
_::FromN::{property}Source node propertyOrigin traffic, elevation, population
_::ToN::{property}Destination node propertyTarget popularity, capacity, demand
_::FromV::{property}Source node vector propertyEmbedding similarity
_::ToV::{property}Destination node vector propertyFeature matching
All weight expressions must evaluate to non-negative values. Negative weights can cause incorrect results or infinite loops.

Context Reference Table

Edge Context: _::{property}

Access properties directly on the edge being evaluated:
// Use edge distance property
::ShortestPathDijkstras<Road>(_::{distance})

// Use edge bandwidth property
::ShortestPathDijkstras<Connection>(_::{bandwidth})

// Use edge reliability property
::ShortestPathDijkstras<Route>(_::{reliability})
Common use cases:
  • Distance-based routing
  • Bandwidth optimization
  • Cost minimization
  • Time-based routing

Source Node Context: _::FromN::{property}

Access properties from the node where the edge originates:
// Weight based on source traffic
::ShortestPathDijkstras<Road>(MUL(_::{distance}, _::FromN::{traffic_factor}))

// Avoid high-elevation starting points
::ShortestPathDijkstras<Trail>(ADD(_::{length}, _::FromN::{elevation}))

// Consider source congestion
::ShortestPathDijkstras<Connection>(DIV(_::{bandwidth}, _::FromN::{load}))
Common use cases:
  • Traffic-aware routing (avoid congested sources)
  • Elevation-based path planning
  • Load balancing (distribute from busy sources)
  • Source capacity constraints

Destination Node Context: _::ToN::{property}

Access properties from the node where the edge terminates:
// Prefer popular destinations
::ShortestPathDijkstras<Road>(DIV(_::{distance}, _::ToN::{popularity}))

// Avoid high-cost destinations
::ShortestPathDijkstras<Route>(MUL(_::{distance}, _::ToN::{cost_multiplier}))

// Consider destination capacity
::ShortestPathDijkstras<Connection>(DIV(_::{bandwidth}, _::ToN::{available_capacity}))
Common use cases:
  • Popularity-weighted routing
  • Destination capacity management
  • Cost-aware pathfinding
  • Attraction-based navigation

Example 1: Time-decay routing with source context

QUERY FindFreshRoute(start_id: ID, end_id: ID) =>
    result <- N<Warehouse>(start_id)
        ::ShortestPathDijkstras<ShippingRoute>(
            MUL(_::{distance}, POW(1.1, _::FromN::{days_since_update}))
        )
        ::To(end_id)
    RETURN result

QUERY CreateWarehouse(name: String, days_old: I64) =>
    warehouse <- CREATE V<Warehouse> {
        name: name,
        days_since_update: days_old
    }
    RETURN warehouse

QUERY CreateShippingRoute(from_id: ID, to_id: ID, distance: F64) =>
    route <- CREATE E<ShippingRoute>(from_id, to_id) { distance: distance }
    RETURN route
Hereโ€™s how to run the query using the SDKs or curl
from helix.client import Client

client = Client(local=True, port=6969)

# Create warehouses with freshness info
# Weight = distance * 1.1^(days_since_update)
# Penalizes routes from warehouses with stale data
warehouses = {}
warehouse_data = [
    ("Main Hub", 0),      # Fresh data
    ("North Branch", 5),  # 5 days old
    ("South Branch", 2),  # 2 days old
    ("East Branch", 10),  # Very stale
    ("Destination", 0),
]

for name, days_old in warehouse_data:
    result = client.query("CreateWarehouse", {
        "name": name,
        "days_old": days_old
    })
    warehouses[name] = result["warehouse"]["id"]

# Create shipping routes
routes = [
    ("Main Hub", "North Branch", 100.0),
    ("Main Hub", "South Branch", 120.0),
    ("North Branch", "Destination", 150.0),
    ("South Branch", "Destination", 140.0),
    ("Main Hub", "East Branch", 80.0),
    ("East Branch", "Destination", 130.0),
]

for from_wh, to_wh, distance in routes:
    client.query("CreateShippingRoute", {
        "from_id": warehouses[from_wh],
        "to_id": warehouses[to_wh],
        "distance": distance
    })

# Find route preferring fresh data sources
result = client.query("FindFreshRoute", {
    "start_id": warehouses["Main Hub"],
    "end_id": warehouses["Destination"]
})

print(f"Route preferring fresh data:")
print(f"Path: {' -> '.join([node['name'] for node in result['result']['path']])}")
print(f"Adjusted weight: {result['result']['total_weight']:.2f}")

Example 2: Destination-aware routing with popularity weighting

QUERY FindPopularRoute(start_id: ID, end_id: ID) =>
    result <- N<Station>(start_id)
        ::ShortestPathDijkstras<Connection>(
            DIV(_::{distance}, _::ToN::{popularity})
        )
        ::To(end_id)
    RETURN result

QUERY CreateStation(name: String, popularity: F64) =>
    station <- CREATE V<Station> {
        name: name,
        popularity: popularity
    }
    RETURN station

QUERY CreateConnection(from_id: ID, to_id: ID, distance: F64) =>
    connection <- CREATE E<Connection>(from_id, to_id) { distance: distance }
    RETURN connection
Hereโ€™s how to run the query using the SDKs or curl
from helix.client import Client

client = Client(local=True, port=6969)

# Create stations with popularity scores
# Weight = distance / destination_popularity
# Prefers routes through popular stations
stations = {}
station_data = [
    ("Entry Point", 5.0),
    ("Scenic Overlook", 8.5),    # Very popular
    ("Hidden Trail", 2.0),        # Less popular
    ("Summit View", 9.0),         # Most popular
    ("Back Route", 3.0),
]

for name, popularity in station_data:
    result = client.query("CreateStation", {
        "name": name,
        "popularity": popularity
    })
    stations[name] = result["station"]["id"]

# Create connections
connections = [
    ("Entry Point", "Scenic Overlook", 100.0),
    ("Entry Point", "Hidden Trail", 80.0),
    ("Scenic Overlook", "Summit View", 120.0),
    ("Hidden Trail", "Back Route", 90.0),
    ("Back Route", "Summit View", 110.0),
]

for from_st, to_st, distance in connections:
    client.query("CreateConnection", {
        "from_id": stations[from_st],
        "to_id": stations[to_st],
        "distance": distance
    })

# Find route preferring popular destinations
result = client.query("FindPopularRoute", {
    "start_id": stations["Entry Point"],
    "end_id": stations["Summit View"]
})

print(f"Route through popular stations:")
print(f"Path: {' -> '.join([node['name'] for node in result['result']['path']])}")
print(f"Popularity-adjusted weight: {result['result']['total_weight']:.2f}")

Example 3: Combining source and destination contexts

QUERY FindBalancedRoute(start_id: ID, end_id: ID) =>
    result <- N<Node>(start_id)
        ::ShortestPathDijkstras<Link>(
            MUL(
                MUL(_::{cost}, _::FromN::{load_factor}),
                DIV(1, _::ToN::{capacity})
            )
        )
        ::To(end_id)
    RETURN result

QUERY CreateNode(name: String, load_factor: F64, capacity: F64) =>
    node <- CREATE V<Node> {
        name: name,
        load_factor: load_factor,
        capacity: capacity
    }
    RETURN node

QUERY CreateLink(from_id: ID, to_id: ID, cost: F64) =>
    link <- CREATE E<Link>(from_id, to_id) { cost: cost }
    RETURN link
Hereโ€™s how to run the query using the SDKs or curl
from helix.client import Client

client = Client(local=True, port=6969)

# Create nodes with load and capacity
# Weight = cost * source_load / dest_capacity
# Avoids heavy sources and low-capacity destinations
nodes = {}
node_data = [
    ("Source", 1.0, 100.0),
    ("Router A", 2.5, 80.0),   # Heavy load
    ("Router B", 1.2, 120.0),  # Light load, high capacity
    ("Router C", 1.5, 60.0),
    ("Destination", 1.0, 200.0),
]

for name, load, capacity in node_data:
    result = client.query("CreateNode", {
        "name": name,
        "load_factor": load,
        "capacity": capacity
    })
    nodes[name] = result["node"]["id"]

# Create links
links = [
    ("Source", "Router A", 10.0),
    ("Source", "Router B", 15.0),
    ("Router A", "Destination", 20.0),
    ("Router B", "Router C", 12.0),
    ("Router C", "Destination", 18.0),
]

for from_node, to_node, cost in links:
    client.query("CreateLink", {
        "from_id": nodes[from_node],
        "to_id": nodes[to_node],
        "cost": cost
    })

# Find balanced route
result = client.query("FindBalancedRoute", {
    "start_id": nodes["Source"],
    "end_id": nodes["Destination"]
})

print(f"Balanced route considering load and capacity:")
print(f"Path: {' -> '.join([node['name'] for node in result['result']['path']])}")
print(f"Composite weight: {result['result']['total_weight']:.2f}")

Real-World Use Cases

Traffic-Aware Navigation

// Penalize routes starting from congested areas
::ShortestPathDijkstras<Road>(MUL(_::{distance}, _::FromN::{congestion}))

Cost Optimization

// Minimize cost considering both base rate and destination fees
::ShortestPathDijkstras<Route>(ADD(_::{base_cost}, _::ToN::{destination_fee}))

Load Balancing

// Distribute traffic away from heavily loaded servers
::ShortestPathDijkstras<Connection>(DIV(_::{latency}, SUB(1, _::ToN::{load_percent})))

Capacity Planning

// Prefer high-capacity destinations
::ShortestPathDijkstras<Link>(DIV(_::{distance}, _::ToN::{available_capacity}))

Best Practices

1. Property Normalization

Ensure properties are on similar scales:
// Good: Both factors are normalized 0-1
MUL(_::{distance}, ADD(_::FromN::{traffic}, _::ToN::{congestion}))

// Careful: Distance in miles, traffic as percentage
MUL(_::{distance}, _::FromN::{traffic_percent})  // May need scaling

2. Avoid Division by Zero

Protect against zero denominators:
// Add small epsilon or use MAX
DIV(_::{distance}, ADD(_::ToN::{popularity}, 0.01))

3. Index Key Properties

For best performance, index properties used in weight calculations:
// Index frequently-accessed properties
V::City {
    @index traffic_factor: F64,
    @index popularity: F64
}

4. Test Weight Distributions

Verify weights produce expected behavior:
  • Log sample weights during development
  • Ensure non-negative values
  • Check for reasonable ranges